Merge "Improve the shortcut manager sample launcher." into nyc-mr1-dev
This commit is contained in:
@@ -17,13 +17,15 @@ package com.example.android.pm.shortcutdemo;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -60,6 +62,10 @@ public abstract class ShortcutAdapter extends BaseAdapter implements OnClickList
|
||||
protected abstract int getLaunchId();
|
||||
protected abstract int getAction2Id();
|
||||
|
||||
protected boolean showLine2() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean showLaunch(ShortcutInfo si) {
|
||||
return false;
|
||||
}
|
||||
@@ -156,10 +162,15 @@ public abstract class ShortcutAdapter extends BaseAdapter implements OnClickList
|
||||
view.setTag(si);
|
||||
|
||||
line1.setText(si.getTitle());
|
||||
line2.setText(
|
||||
si.getId() + (si.isDynamic() ? " [dynamic]" : "")
|
||||
+ (si.isPinned() ? " [pinned]" : "") + "\n"
|
||||
+ mAppLabelCache.getAppLabel(si.getPackageName()));
|
||||
if (showLine2()) {
|
||||
line2.setText(
|
||||
si.getId() + (si.isDynamic() ? " [dynamic]" : "")
|
||||
+ (si.isPinned() ? " [pinned]" : "") + "\n"
|
||||
+ mAppLabelCache.getAppLabel(si.getPackageName()));
|
||||
line2.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
line2.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// view.setBackgroundColor(si.isPinned() ? Color.rgb(255, 255, 192) : Color.WHITE);
|
||||
|
||||
@@ -169,22 +180,34 @@ public abstract class ShortcutAdapter extends BaseAdapter implements OnClickList
|
||||
image.setVisibility(View.GONE);
|
||||
} else {
|
||||
image.setVisibility(View.VISIBLE);
|
||||
Bitmap icon = null;
|
||||
if (si.hasIconResource()) {
|
||||
try {
|
||||
final Resources res = mContext.getPackageManager().getResourcesForApplication(
|
||||
si.getPackageName());
|
||||
icon = BitmapFactory.decodeResource(res, si.getIconResourceId());
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(TAG, "Unable to load icon from " + si.getPackageName(), e);
|
||||
}
|
||||
} else if (si.hasIconFile()) {
|
||||
icon = pfdToBitmap(mLauncherApps.getShortcutIconFd(si));
|
||||
}
|
||||
image.setImageBitmap(icon);
|
||||
image.setImageDrawable(getShortcutIcon(si));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon of a shortcut, with the profile badge if necessary.
|
||||
*/
|
||||
private Drawable getShortcutIcon(ShortcutInfo si) {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final Bitmap bitmap;
|
||||
if (si.hasIconResource()) {
|
||||
try {
|
||||
final Resources res = pm.getResourcesForApplication(
|
||||
si.getPackageName());
|
||||
bitmap = BitmapFactory.decodeResource(res, si.getIconResourceId());
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(TAG, "Unable to load icon from " + si.getPackageName(), e);
|
||||
return null;
|
||||
}
|
||||
} else if (si.hasIconFile()) {
|
||||
bitmap = pfdToBitmap(mLauncherApps.getShortcutIconFd(si));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return pm.getUserBadgedIcon(new BitmapDrawable(mContext.getResources(), bitmap),
|
||||
si.getUserHandle());
|
||||
}
|
||||
|
||||
private Bitmap pfdToBitmap(ParcelFileDescriptor pfd) {
|
||||
if (pfd == null) {
|
||||
return null;
|
||||
|
||||
@@ -34,6 +34,8 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/../common/res
|
||||
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res1
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 android-support-v13
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
@@ -54,6 +56,8 @@ LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/../common/res
|
||||
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res2
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 android-support-v13
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
<application android:label="@string/app_title"
|
||||
android:resizeableActivity="true">
|
||||
<activity android:name="ShortcutLauncher">
|
||||
<activity android:name="ShortcutLauncherMain">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
@@ -29,5 +29,8 @@
|
||||
<category android:name="android.intent.category.HOME" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="PackageShortcutActivity"
|
||||
android:theme="@android:style/Theme.Holo.Light.Dialog">
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
21
samples/ShortcutDemo/launcher/res/layout/framelayout.xml
Normal file
21
samples/ShortcutDemo/launcher/res/layout/framelayout.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2016 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/main"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
</FrameLayout>
|
||||
@@ -14,16 +14,12 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:enabled="true"
|
||||
/>
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
27
samples/ShortcutDemo/launcher/res/layout/my_list.xml
Normal file
27
samples/ShortcutDemo/launcher/res/layout/my_list.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2016 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1"
|
||||
android:enabled="true"
|
||||
/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.android.pm.shortcutlauncherdemo;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.LauncherApps.ShortcutQuery;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class AppListFragment extends MyBaseListFragment {
|
||||
private AppAdapter mAdapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mAdapter = new AppAdapter(getActivity());
|
||||
setListAdapter(mAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshList() {
|
||||
Log.d(Global.TAG, "Loading apps and shortcuts...");
|
||||
|
||||
final List<LauncherActivityInfo> apps = new ArrayList<>();
|
||||
|
||||
for (UserHandle user : mUserManager.getUserProfiles()) {
|
||||
apps.addAll(mLauncherApps.getActivityList(null, user));
|
||||
}
|
||||
Collections.sort(apps, sLauncherIconComparator);
|
||||
|
||||
Log.d(Global.TAG, "Apps and shortcuts loaded.");
|
||||
|
||||
mAdapter.setList(apps);
|
||||
}
|
||||
|
||||
private static final Comparator<LauncherActivityInfo> sLauncherIconComparator =
|
||||
(LauncherActivityInfo l1, LauncherActivityInfo l2) -> {
|
||||
int ret = 0;
|
||||
ret = l1.getLabel().toString().compareTo(l2.getLabel().toString());
|
||||
if (ret != 0) return ret;
|
||||
|
||||
// TODO Don't rely on hashCode being the user-id.
|
||||
ret = l1.getUser().hashCode() - l2.getUser().hashCode();
|
||||
if (ret != 0) return ret;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
public class AppAdapter extends BaseAdapter implements OnClickListener {
|
||||
private final Context mContext;
|
||||
private final LayoutInflater mInflater;
|
||||
private LauncherApps mLauncherApps;
|
||||
private List<LauncherActivityInfo> mList;
|
||||
|
||||
public AppAdapter(Context context) {
|
||||
mContext = context;
|
||||
mInflater = mContext.getSystemService(LayoutInflater.class);
|
||||
mLauncherApps = mContext.getSystemService(LauncherApps.class);
|
||||
}
|
||||
|
||||
public void setList(List<LauncherActivityInfo> list) {
|
||||
mList = list;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mList == null ? 0 : mList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LauncherActivityInfo getItem(int position) {
|
||||
return mList == null ? null : mList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areAllItemsEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final View view;
|
||||
if (convertView != null) {
|
||||
view = convertView;
|
||||
} else {
|
||||
view = mInflater.inflate(R.layout.list_item, null);
|
||||
}
|
||||
|
||||
bindView(view, getItem(position));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
public void bindView(View view, LauncherActivityInfo ai) {
|
||||
{
|
||||
final View v = view.findViewById(R.id.launch);
|
||||
|
||||
v.setTag(ai);
|
||||
|
||||
v.setOnClickListener(this);
|
||||
v.setVisibility(View.VISIBLE);
|
||||
}
|
||||
{
|
||||
final Button v = (Button) view.findViewById(R.id.action2);
|
||||
|
||||
v.setTag(ai);
|
||||
|
||||
v.setVisibility(View.INVISIBLE);
|
||||
if (mLauncherApps.hasShortcutHostPermission()) {
|
||||
mQuery.setPackage(ai.getComponentName().getPackageName());
|
||||
mQuery.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC
|
||||
| ShortcutQuery.FLAG_GET_PINNED
|
||||
| ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY);
|
||||
mQuery.setActivity(ai.getComponentName());
|
||||
|
||||
if (mLauncherApps.getShortcuts(mQuery, ai.getUser()).size() > 0) {
|
||||
v.setOnClickListener(this);
|
||||
v.setVisibility(View.VISIBLE);
|
||||
v.setText("Shortcuts");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final TextView line1 = (TextView) view.findViewById(R.id.line1);
|
||||
final TextView line2 = (TextView) view.findViewById(R.id.line2);
|
||||
|
||||
line1.setText(ai.getLabel());
|
||||
|
||||
// TODO Do it on worker thread
|
||||
final Drawable icon = ai.getBadgedIcon(DisplayMetrics.DENSITY_DEFAULT);
|
||||
final ImageView image = (ImageView) view.findViewById(R.id.image);
|
||||
image.setImageDrawable(icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick (View v){
|
||||
final LauncherActivityInfo ai = (LauncherActivityInfo) v.getTag();
|
||||
switch (v.getId()) {
|
||||
case R.id.launch:
|
||||
mLauncherApps.startMainActivity(ai.getComponentName(), ai.getUser(),
|
||||
null, null);
|
||||
return;
|
||||
case R.id.action2:
|
||||
showShortcutsForPackage(ai);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showShortcutsForPackage(LauncherActivityInfo ai) {
|
||||
final Intent i = PackageShortcutActivity.getLaunchIntent(
|
||||
getActivity(),
|
||||
ai.getComponentName().getPackageName(),
|
||||
ai.getComponentName(),
|
||||
ai.getUser(),
|
||||
ai.getLabel());
|
||||
getActivity().startActivity(i);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.android.pm.shortcutlauncherdemo;
|
||||
|
||||
public class Global {
|
||||
public static final String TAG = "ShortcutLauncherDemo";
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.android.pm.shortcutlauncherdemo;
|
||||
|
||||
import android.app.ListFragment;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.LauncherApps.ShortcutQuery;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MyBaseListFragment extends ListFragment {
|
||||
protected UserManager mUserManager;
|
||||
protected LauncherApps mLauncherApps;
|
||||
|
||||
private ArrayMap<String, String> mAppNames = new ArrayMap<>();
|
||||
|
||||
protected final ShortcutQuery mQuery = new ShortcutQuery();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mUserManager = getActivity().getSystemService(UserManager.class);
|
||||
mLauncherApps = getActivity().getSystemService(LauncherApps.class);
|
||||
mLauncherApps.registerCallback(mLauncherCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
Log.d(Global.TAG, "Started");
|
||||
|
||||
refreshList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
showPermissionWarningToastWhenNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mLauncherApps.unregisterCallback(mLauncherCallback);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
protected void showPermissionWarningToastWhenNeeded() {
|
||||
if (!mLauncherApps.hasShortcutHostPermission()) {
|
||||
Toast.makeText(getActivity(), "App doesn't have the shortcut permissions",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
protected final String getAppLabel(String packageName) {
|
||||
String name = mAppNames.get(packageName);
|
||||
if (name != null) {
|
||||
return name;
|
||||
}
|
||||
PackageManager pm = getActivity().getPackageManager();
|
||||
try {
|
||||
final ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
|
||||
return pm.getApplicationLabel(ai).toString();
|
||||
} catch (NameNotFoundException e) {
|
||||
return packageName;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void refreshList();
|
||||
|
||||
private final LauncherApps.Callback mLauncherCallback = new LauncherApps.Callback() {
|
||||
@Override
|
||||
public void onPackageRemoved(String packageName, UserHandle user) {
|
||||
refreshList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageAdded(String packageName, UserHandle user) {
|
||||
refreshList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageChanged(String packageName, UserHandle user) {
|
||||
refreshList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
|
||||
refreshList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackagesUnavailable(String[] packageNames, UserHandle user,
|
||||
boolean replacing) {
|
||||
refreshList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShortcutsChanged(String packageName,
|
||||
List<ShortcutInfo> shortcuts, UserHandle user) {
|
||||
refreshList();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.android.pm.shortcutlauncherdemo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
|
||||
public class PackageShortcutActivity extends Activity {
|
||||
private static final String KEY_TARGET_PACKAGE = "PackageShortcutActivity.target_package";
|
||||
private static final String KEY_TARGET_ACTIVITY = "PackageShortcutActivity.target_activity";
|
||||
private static final String KEY_TARGET_USER = "PackageShortcutActivity.user";
|
||||
private static final String KEY_TITLE = "PackageShortcutActivity.title";
|
||||
|
||||
public static Intent getLaunchIntent(Context context, String targetPackage,
|
||||
ComponentName targetActivity, UserHandle user, CharSequence title) {
|
||||
final Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setComponent(new ComponentName(context, PackageShortcutActivity.class));
|
||||
|
||||
i.putExtra(KEY_TARGET_PACKAGE, targetPackage);
|
||||
i.putExtra(KEY_TARGET_ACTIVITY, targetActivity);
|
||||
i.putExtra(KEY_TARGET_USER, user);
|
||||
i.putExtra(KEY_TITLE, title);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.framelayout);
|
||||
|
||||
final Intent i = getIntent();
|
||||
|
||||
final Fragment f = new ShortcutListFragment().setArguments(
|
||||
i.getStringExtra(KEY_TARGET_PACKAGE),
|
||||
/* targetActivity=*/ i.getParcelableExtra(KEY_TARGET_ACTIVITY),
|
||||
/*includeDynamic=*/ true,
|
||||
/*includePinned=*/ true,
|
||||
i.getParcelableExtra(KEY_TARGET_USER),
|
||||
/* showDetails =*/ false
|
||||
);
|
||||
|
||||
setTitle(i.getStringExtra(KEY_TITLE));
|
||||
|
||||
getFragmentManager().beginTransaction().replace(R.id.main, f).commit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.example.android.pm.shortcutlauncherdemo;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.ActionBar.Tab;
|
||||
import android.app.ActionBar.TabListener;
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.support.v13.app.FragmentStatePagerAdapter;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
|
||||
public class ShortcutLauncherMain extends Activity {
|
||||
private LauncherApps mLauncherApps;
|
||||
private ViewPager mPager;
|
||||
private PagerAdapter mPagerAdapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.main);
|
||||
|
||||
mLauncherApps = getSystemService(LauncherApps.class);
|
||||
|
||||
mPager = (ViewPager) findViewById(R.id.pager);
|
||||
mPager.setOffscreenPageLimit(2);
|
||||
mPagerAdapter = new MyPagerAdapter(getFragmentManager());
|
||||
mPager.setAdapter(mPagerAdapter);
|
||||
|
||||
final ActionBar ab = getActionBar();
|
||||
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
|
||||
ab.addTab(ab.newTab().setText("App list").setTabListener(mTabListener));
|
||||
ab.addTab(ab.newTab().setText("Pinned shortcuts").setTabListener(mTabListener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Ignore.
|
||||
}
|
||||
|
||||
private TabListener mTabListener = new TabListener() {
|
||||
@Override
|
||||
public void onTabSelected(Tab tab, FragmentTransaction ft) {
|
||||
mPager.setCurrentItem(tab.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(Tab tab, FragmentTransaction ft) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
private class MyPagerAdapter extends FragmentStatePagerAdapter {
|
||||
public MyPagerAdapter(FragmentManager fm) {
|
||||
super(fm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return new AppListFragment();
|
||||
case 1:
|
||||
return new ShortcutListFragment().setArguments(
|
||||
/* targetPackage =*/ null,
|
||||
/* targetActivity =*/ null,
|
||||
/* includeDynamic = */ false,
|
||||
/* includePinned =*/ true,
|
||||
null /* means "all profiles" of this user*/,
|
||||
/* showDetails =*/ true
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,15 @@
|
||||
*/
|
||||
package com.example.android.pm.shortcutlauncherdemo;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.LauncherApps.ShortcutQuery;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.os.UserManager;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.example.android.pm.shortcutdemo.ShortcutAdapter;
|
||||
@@ -37,50 +33,59 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class ShortcutLauncher extends ListActivity {
|
||||
public static final String TAG = "ShortcutLauncherDemo";
|
||||
public class ShortcutListFragment extends MyBaseListFragment {
|
||||
private static final String TAG = "ShortcutListFragment";
|
||||
|
||||
private LauncherApps mLauncherApps;
|
||||
private static final String ARG_TARGET_PACKAGE = "target_package";
|
||||
private static final String ARG_TARGET_ACTIVITY = "target_activity";
|
||||
private static final String ARG_INCLUDE_DYNAMIC = "include_dynamic";
|
||||
private static final String ARG_INCLUDE_PINNED = "include_pinned";
|
||||
private static final String ARG_USER = "user";
|
||||
private static final String ARG_SHOW_DETAILS = "show_details";
|
||||
|
||||
private MyAdapter mAdapter;
|
||||
|
||||
private ArrayMap<String, String> mAppNames = new ArrayMap<>();
|
||||
public ShortcutListFragment setArguments(String targetPackage, ComponentName targetActivity,
|
||||
boolean includeDynamic,
|
||||
boolean includePinned, UserHandle user, boolean showDetails) {
|
||||
final Bundle b = new Bundle();
|
||||
b.putString(ARG_TARGET_PACKAGE, targetPackage);
|
||||
b.putParcelable(ARG_TARGET_ACTIVITY, targetActivity);
|
||||
b.putBoolean(ARG_INCLUDE_DYNAMIC, includeDynamic);
|
||||
b.putBoolean(ARG_INCLUDE_PINNED, includePinned);
|
||||
b.putParcelable(ARG_USER, user);
|
||||
b.putBoolean(ARG_SHOW_DETAILS, showDetails);
|
||||
|
||||
setArguments(b);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.main);
|
||||
|
||||
mLauncherApps = getSystemService(LauncherApps.class);
|
||||
mLauncherApps.registerCallback(mLauncherCallback);
|
||||
|
||||
if (mLauncherApps.hasShortcutHostPermission()) {
|
||||
mAdapter = new MyAdapter(this);
|
||||
mUserManager = getActivity().getSystemService(UserManager.class);
|
||||
mLauncherApps = getActivity().getSystemService(LauncherApps.class);
|
||||
if (!mLauncherApps.hasShortcutHostPermission()) {
|
||||
Toast.makeText(getActivity(), "App doesn't have the shortcut permissions",
|
||||
Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
mAdapter = new MyAdapter(getActivity(), getArguments().getBoolean(ARG_SHOW_DETAILS));
|
||||
|
||||
setListAdapter(mAdapter);
|
||||
} else {
|
||||
showToast("Please make this app as the default launcher.");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
private void showToast(String message) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
refreshList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
mLauncherApps.unregisterCallback(mLauncherCallback);
|
||||
|
||||
super.onDestroy();
|
||||
private List<UserHandle> getTargetUsers() {
|
||||
final UserHandle arg = getArguments().getParcelable(ARG_USER);
|
||||
if (arg == null) {
|
||||
return mUserManager.getUserProfiles();
|
||||
} else {
|
||||
final List<UserHandle> ret = new ArrayList<>();
|
||||
ret.add(arg);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
private void togglePin(ShortcutInfo selected) {
|
||||
@@ -88,7 +93,9 @@ public class ShortcutLauncher extends ListActivity {
|
||||
|
||||
final List<String> pinned = new ArrayList<>();
|
||||
for (ShortcutInfo si : mAdapter.getShortcuts()) {
|
||||
if (si.isPinned() && si.getPackageName().equals(packageName)) {
|
||||
if (si.isPinned()
|
||||
&& si.getPackageName().equals(packageName)
|
||||
&& si.getUserHandle().equals(selected.getUserHandle())) {
|
||||
pinned.add(si.getId());
|
||||
}
|
||||
}
|
||||
@@ -97,38 +104,33 @@ public class ShortcutLauncher extends ListActivity {
|
||||
} else {
|
||||
pinned.add(selected.getId());
|
||||
}
|
||||
mLauncherApps.pinShortcuts(packageName, pinned, Process.myUserHandle());
|
||||
mLauncherApps.pinShortcuts(packageName, pinned, selected.getUserHandle());
|
||||
}
|
||||
|
||||
private void launch(ShortcutInfo si) {
|
||||
mLauncherApps.startShortcut(si.getPackageName(), si.getId(), null, null,
|
||||
Process.myUserHandle());
|
||||
si.getUserHandle());
|
||||
}
|
||||
|
||||
private String getAppLabel(String packageName) {
|
||||
String name = mAppNames.get(packageName);
|
||||
if (name != null) {
|
||||
return name;
|
||||
@Override
|
||||
protected void refreshList() {
|
||||
if (!mLauncherApps.hasShortcutHostPermission()) {
|
||||
return;
|
||||
}
|
||||
PackageManager pm = getPackageManager();
|
||||
try {
|
||||
final ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
|
||||
return pm.getApplicationLabel(ai).toString();
|
||||
} catch (NameNotFoundException e) {
|
||||
return packageName;
|
||||
|
||||
final List<ShortcutInfo> list = new ArrayList<>();
|
||||
|
||||
for (UserHandle user : getTargetUsers()) {
|
||||
final Bundle b = getArguments();
|
||||
mQuery.setQueryFlags(
|
||||
(b.getBoolean(ARG_INCLUDE_DYNAMIC) ? ShortcutQuery.FLAG_GET_DYNAMIC : 0) |
|
||||
(b.getBoolean(ARG_INCLUDE_PINNED) ? ShortcutQuery.FLAG_GET_PINNED : 0));
|
||||
mQuery.setPackage(b.getString(ARG_TARGET_PACKAGE));
|
||||
mQuery.setActivity(b.getParcelable(ARG_TARGET_ACTIVITY));
|
||||
|
||||
list.addAll(mLauncherApps.getShortcuts(mQuery, user));
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshList() {
|
||||
final ShortcutQuery q = new ShortcutQuery();
|
||||
q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
|
||||
|
||||
final List<ShortcutInfo> list = mLauncherApps.getShortcuts(q, Process.myUserHandle());
|
||||
Collections.sort(list, mShortcutComparator);
|
||||
Log.i(TAG, "All shortcuts:");
|
||||
for (ShortcutInfo si : list) {
|
||||
Log.i(TAG, si.toString());
|
||||
}
|
||||
|
||||
mAdapter.setShortcuts(list);
|
||||
}
|
||||
@@ -139,48 +141,21 @@ public class ShortcutLauncher extends ListActivity {
|
||||
ret = getAppLabel(s1.getPackageName()).compareTo(getAppLabel(s2.getPackageName()));
|
||||
if (ret != 0) return ret;
|
||||
|
||||
ret = s1.getUserHandle().hashCode() - s2.getUserHandle().hashCode();
|
||||
if (ret != 0) return ret;
|
||||
|
||||
ret = s1.getId().compareTo(s2.getId());
|
||||
if (ret != 0) return ret;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
private final LauncherApps.Callback mLauncherCallback = new LauncherApps.Callback() {
|
||||
@Override
|
||||
public void onPackageRemoved(String packageName, UserHandle user) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageAdded(String packageName, UserHandle user) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageChanged(String packageName, UserHandle user) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackagesUnavailable(String[] packageNames, UserHandle user,
|
||||
boolean replacing) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShortcutsChanged(String packageName,
|
||||
List<ShortcutInfo> shortcuts, UserHandle user) {
|
||||
Log.w(TAG, "onShortcutsChanged: user=" + user + " package=" + packageName);
|
||||
for (ShortcutInfo si : shortcuts) {
|
||||
Log.i(TAG, si.toString());
|
||||
}
|
||||
refreshList();
|
||||
}
|
||||
};
|
||||
|
||||
class MyAdapter extends ShortcutAdapter {
|
||||
public MyAdapter(Context context) {
|
||||
private final boolean mShowLine2;
|
||||
|
||||
public MyAdapter(Context context, boolean showLine2) {
|
||||
super(context);
|
||||
mShowLine2 = showLine2;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -237,5 +212,10 @@ public class ShortcutLauncher extends ListActivity {
|
||||
protected void onAction2Clicked(ShortcutInfo si) {
|
||||
togglePin(si);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean showLine2() {
|
||||
return mShowLine2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
public class ShortcutPublisher extends Activity {
|
||||
@@ -53,6 +54,8 @@ public class ShortcutPublisher extends Activity {
|
||||
|
||||
private static final Random sRandom = new Random();
|
||||
|
||||
private static final AtomicInteger sSequenceNumber = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -217,7 +220,8 @@ public class ShortcutPublisher extends Activity {
|
||||
|
||||
public void onAddPressed(View view) {
|
||||
final ShortcutInfo si = addRandomIntents(this, new ShortcutInfo.Builder(this)
|
||||
.setId("shortcut-" + formatTime(System.currentTimeMillis()))
|
||||
.setId("shortcut-" + formatTime(System.currentTimeMillis()) + "-"
|
||||
+ sSequenceNumber.getAndIncrement())
|
||||
.setWeight(10)).build();
|
||||
callApi(this, () -> mShortcutManager.addDynamicShortcuts(Arrays.asList(si)));
|
||||
refreshList();
|
||||
|
||||
Reference in New Issue
Block a user