Merge "Improve the shortcut manager sample launcher." into nyc-mr1-dev

This commit is contained in:
Makoto Onuki
2016-05-04 22:58:27 +00:00
committed by Android (Google) Code Review
13 changed files with 719 additions and 126 deletions

View File

@@ -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;

View File

@@ -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)

View File

@@ -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>

View 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>

View File

@@ -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>

View 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>

View File

@@ -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);
}
}

View File

@@ -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";
}

View File

@@ -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();
}
};
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();