diff --git a/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/AppListFragment.java b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/AppListFragment.java index 819066a1c..4d728b7c0 100644 --- a/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/AppListFragment.java +++ b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/AppListFragment.java @@ -15,201 +15,54 @@ */ package com.example.android.pm.shortcutlauncherdemo; -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.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 java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; -public class AppListFragment extends MyBaseListFragment { - private AppAdapter mAdapter; +public class AppListFragment extends BaseActivityListFragment { @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mAdapter = new AppAdapter(getActivity()); - setListAdapter(mAdapter); + protected List getActivities(UserHandle user) { + return mLauncherApps.getActivityList(null, user); } @Override - protected void refreshList() { - Log.d(Global.TAG, "Loading apps and shortcuts..."); + protected void onBindAction2(Button v, LauncherActivityInfo ai, OnClickListener listener) { + try { + if (mUserManager.isUserUnlocked(ai.getUser()) + && mLauncherApps.hasShortcutHostPermission()) { + mQuery.setPackage(ai.getComponentName().getPackageName()); + mQuery.setQueryFlags(ShortcutQuery.FLAG_MATCH_DYNAMIC + | ShortcutQuery.FLAG_MATCH_PINNED + | ShortcutQuery.FLAG_MATCH_MANIFEST + | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY); + mQuery.setActivity(ai.getComponentName()); - final List apps = new ArrayList<>(); - - for (UserHandle user : mLauncherApps.getProfiles()) { - 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 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 final UserManager mUserManager; - private final LauncherApps mLauncherApps; - private List mList; - - public AppAdapter(Context context) { - mContext = context; - mInflater = mContext.getSystemService(LayoutInflater.class); - mUserManager = mContext.getSystemService(UserManager.class); - mLauncherApps = mContext.getSystemService(LauncherApps.class); - } - - public void setList(List 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); - try { - if (mUserManager.isUserUnlocked(ai.getUser()) - && mLauncherApps.hasShortcutHostPermission()) { - mQuery.setPackage(ai.getComponentName().getPackageName()); - mQuery.setQueryFlags(ShortcutQuery.FLAG_MATCH_DYNAMIC - | ShortcutQuery.FLAG_MATCH_PINNED - | ShortcutQuery.FLAG_MATCH_MANIFEST - | 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"); - } - } - } catch (Exception e) { - Log.w(Global.TAG, "Caught exception", e); + if (mLauncherApps.getShortcuts(mQuery, ai.getUser()).size() > 0) { + v.setOnClickListener(listener); + 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: - try { - mLauncherApps.startMainActivity(ai.getComponentName(), ai.getUser(), - null, null); - } catch (Exception e) { - Global.showToast(getContext(), e.getMessage()); - } - return; - case R.id.action2: - showShortcutsForPackage(ai); - return; - } + } catch (Exception e) { + Log.w(Global.TAG, "Caught exception", e); } } - private void showShortcutsForPackage(LauncherActivityInfo ai) { + @Override + protected void onLaunch(LauncherActivityInfo ai) { + mLauncherApps.startMainActivity(ai.getComponentName(), ai.getUser(), null, null); + } + + @Override + protected void onAction2(LauncherActivityInfo ai) { final Intent i = PackageShortcutActivity.getLaunchIntent( getActivity(), ai.getComponentName().getPackageName(), @@ -217,5 +70,4 @@ public class AppListFragment extends MyBaseListFragment { ai.getUser(), ai.getLabel()); getActivity().startActivity(i); - } -} \ No newline at end of file + }} \ No newline at end of file diff --git a/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/BaseActivityListFragment.java b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/BaseActivityListFragment.java new file mode 100644 index 000000000..01c6bb5c0 --- /dev/null +++ b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/BaseActivityListFragment.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2017 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.content.Context; +import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps; +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 java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public abstract class BaseActivityListFragment 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 apps = new ArrayList<>(); + + try { + for (UserHandle user : mLauncherApps.getProfiles()) { + if (mUserManager.isUserUnlocked(user)) { + apps.addAll(getActivities(user)); + } + } + Collections.sort(apps, sLauncherIconComparator); + } catch (Exception e) { + Global.showToast(getContext(), e.getMessage()); + } + + Log.d(Global.TAG, "Apps and shortcuts loaded. (count=" + apps.size() + ")"); + + mAdapter.setList(apps); + } + + protected abstract List getActivities(UserHandle user); + + private static final Comparator 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; + }; + + private class AppAdapter extends BaseAdapter implements OnClickListener { + private final Context mContext; + private final LayoutInflater mInflater; + private List mList; + + public AppAdapter(Context context) { + mContext = context; + mInflater = mContext.getSystemService(LayoutInflater.class); + mUserManager = mContext.getSystemService(UserManager.class); + mLauncherApps = mContext.getSystemService(LauncherApps.class); + } + + public void setList(List 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); + + try { + onBindAction2(v, ai, this); + } catch (Exception e) { + Log.w(Global.TAG, "Caught exception", e); + } + } + + 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: + try { + onLaunch(ai); + } catch (Exception e) { + Global.showToast(getContext(), e.getMessage()); + } + return; + case R.id.action2: + try { + onAction2(ai); + } catch (Exception e) { + Global.showToast(getContext(), e.getMessage()); + } + return; + } + } + } + + protected void onBindAction2(Button v, LauncherActivityInfo ai, + OnClickListener listener) { + } + + protected abstract void onLaunch(LauncherActivityInfo ai); + + protected void onAction2(LauncherActivityInfo ai) { + } +} \ No newline at end of file diff --git a/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/ShortcutLauncherMain.java b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/ShortcutLauncherMain.java index cc6349408..d2ec91f01 100644 --- a/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/ShortcutLauncherMain.java +++ b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/ShortcutLauncherMain.java @@ -47,6 +47,7 @@ public class ShortcutLauncherMain extends Activity { ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); ab.addTab(ab.newTab().setText("App list").setTabListener(mTabListener)); ab.addTab(ab.newTab().setText("Pinned shortcuts").setTabListener(mTabListener)); + ab.addTab(ab.newTab().setText("Create shortcuts").setTabListener(mTabListener)); } @Override @@ -91,13 +92,15 @@ public class ShortcutLauncherMain extends Activity { null /* means "all profiles" of this user*/, /* showDetails =*/ true ); + case 2: + return new ShortcutTemplateListFragment(); } return null; } @Override public int getCount() { - return 2; + return 3; } @Override diff --git a/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/ShortcutTemplateListFragment.java b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/ShortcutTemplateListFragment.java new file mode 100644 index 000000000..13a6f3bfd --- /dev/null +++ b/samples/ShortcutDemo/launcher/src/com/example/android/pm/shortcutlauncherdemo/ShortcutTemplateListFragment.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 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.content.Intent; +import android.content.IntentSender; +import android.content.IntentSender.SendIntentException; +import android.content.pm.LauncherActivityInfo; +import android.content.pm.LauncherApps.PinItemRequest; +import android.os.UserHandle; +import android.util.Log; + +import java.util.List; + +public class ShortcutTemplateListFragment extends BaseActivityListFragment { + private static final String TAG = "ShortcutTemplateListFragment"; + private static final int REQUEST_SHORTCUT = 1; + + @Override + protected List getActivities(UserHandle user) { + return mLauncherApps.getShortcutConfigActivityList(null, user); + } + + @Override + protected void onLaunch(LauncherActivityInfo ai) { + final IntentSender is = mLauncherApps.getShortcutConfigActivityIntent(ai); + try { + startIntentSenderForResult(is, REQUEST_SHORTCUT, null, 0,0, 0, null); + } catch (SendIntentException e) { + Log.e(TAG, "Couldn't start activity", e); + Global.showToast(getActivity(), "Couldn't start activity: " + e.getMessage()); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode != Activity.RESULT_OK || data == null) { + return; + } + switch (requestCode) { + case REQUEST_SHORTCUT: + final PinItemRequest req = mLauncherApps.getPinItemRequest(data); + if (req == null) { + Global.showToast(getActivity(), + "App doesn't support app shortcut (only supports \"legacy\" ones)"); + } else { + req.accept(); + } + break; + } + } +} diff --git a/samples/ShortcutSample/AndroidManifest.xml b/samples/ShortcutSample/AndroidManifest.xml index b4c65d171..b19992b4b 100644 --- a/samples/ShortcutSample/AndroidManifest.xml +++ b/samples/ShortcutSample/AndroidManifest.xml @@ -32,6 +32,9 @@ + + + { final String url = editUri.getText().toString().trim(); if (url.length() > 0) { - addUriAsync(url, forPin); + if (forResult) { + addUriAsync(url, forPin, forResult); + } + } + }) + .setOnCancelListener((dialog) -> { + if (forResult) { + setResult(Activity.RESULT_CANCELED); + finish(); } }) .show(); } - private void addUriAsync(String uri, boolean forPin) { - new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - mHelper.addWebSiteShortcut(uri, forPin); - return null; - } + private void addUriAsync(String uri, boolean forPin, boolean forResult) { + if (forResult) { + new AsyncTask() { + @Override + protected ShortcutInfo doInBackground(Void... params) { + return mHelper.createShortcutForUrl(uri); + } - @Override - protected void onPostExecute(Void aVoid) { - refreshList(); - } - }.execute(); + @Override + protected void onPostExecute(ShortcutInfo shortcut) { + setResult(Activity.RESULT_OK, + mShortcutManager.createShortcutResultIntent(shortcut)); + finish(); + } + }.execute(); + } else { + new AsyncTask() { + @Override + protected Void doInBackground(Void... params) { + mHelper.addWebSiteShortcut(uri, forPin); + return null; + } + + @Override + protected void onPostExecute(Void aVoid) { + refreshList(); + } + }.execute(); + } } private void refreshList() { diff --git a/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java b/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java index 9f3494ead..bd049b357 100644 --- a/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java +++ b/samples/ShortcutSample/src/com/example/android/shortcutsample/ShortcutHelper.java @@ -156,8 +156,9 @@ public class ShortcutHelper { }.execute(); } - private ShortcutInfo createShortcutForUrl(String urlAsString) { + public ShortcutInfo createShortcutForUrl(String urlAsString) { Log.i(TAG, "createShortcutForUrl: " + urlAsString); + urlAsString = normalizeUrl(urlAsString); final ShortcutInfo.Builder b = new ShortcutInfo.Builder(mContext, urlAsString); @@ -202,8 +203,7 @@ public class ShortcutHelper { } public void addWebSiteShortcut(String urlAsString, boolean forPin) { - final String uriFinal = urlAsString; - final ShortcutInfo shortcut = createShortcutForUrl(normalizeUrl(uriFinal)); + final ShortcutInfo shortcut = createShortcutForUrl(urlAsString); if (forPin) { callShortcutManager(() -> mShortcutManager.requestPinShortcut(