1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.example.android.pm.shortcutlauncherdemo; 17 18 import android.content.ComponentName; 19 import android.content.Context; 20 import android.content.pm.LauncherApps; 21 import android.content.pm.LauncherApps.ShortcutQuery; 22 import android.content.pm.ShortcutInfo; 23 import android.os.Bundle; 24 import android.os.UserHandle; 25 import android.os.UserManager; 26 import android.util.Log; 27 import android.widget.Toast; 28 29 import com.example.android.pm.shortcutdemo.ShortcutAdapter; 30 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.Comparator; 34 import java.util.List; 35 36 public class ShortcutListFragment extends MyBaseListFragment { 37 private static final String TAG = "ShortcutListFragment"; 38 39 private static final String ARG_TARGET_PACKAGE = "target_package"; 40 private static final String ARG_TARGET_ACTIVITY = "target_activity"; 41 private static final String ARG_INCLUDE_DYNAMIC = "include_dynamic"; 42 private static final String ARG_INCLUDE_MANIFEST = "include_manifest"; 43 private static final String ARG_INCLUDE_PINNED = "include_pinned"; 44 private static final String ARG_USER = "user"; 45 private static final String ARG_SHOW_DETAILS = "show_details"; 46 47 private MyAdapter mAdapter; 48 49 public ShortcutListFragment setArguments(String targetPackage, ComponentName targetActivity, 50 boolean includeDynamic, boolean includeManifest, 51 boolean includePinned, UserHandle user, boolean showDetails) { 52 final Bundle b = new Bundle(); 53 b.putString(ARG_TARGET_PACKAGE, targetPackage); 54 b.putParcelable(ARG_TARGET_ACTIVITY, targetActivity); 55 b.putBoolean(ARG_INCLUDE_DYNAMIC, includeDynamic); 56 b.putBoolean(ARG_INCLUDE_MANIFEST, includeManifest); 57 b.putBoolean(ARG_INCLUDE_PINNED, includePinned); 58 b.putParcelable(ARG_USER, user); 59 b.putBoolean(ARG_SHOW_DETAILS, showDetails); 60 61 setArguments(b); 62 63 return this; 64 } 65 66 @Override 67 public void onCreate(Bundle savedInstanceState) { 68 super.onCreate(savedInstanceState); 69 70 mUserManager = getActivity().getSystemService(UserManager.class); 71 mLauncherApps = getActivity().getSystemService(LauncherApps.class); 72 73 mAdapter = new MyAdapter(getActivity(), getArguments().getBoolean(ARG_SHOW_DETAILS)); 74 setListAdapter(mAdapter); 75 76 if (!mLauncherApps.hasShortcutHostPermission()) { 77 Toast.makeText(getActivity(), "App doesn't have the shortcut permissions", 78 Toast.LENGTH_LONG).show(); 79 } 80 } 81 82 private List<UserHandle> getTargetUsers() { 83 final UserHandle arg = getArguments().getParcelable(ARG_USER); 84 if (arg == null) { 85 return Compat.getProfiles(getActivity()); 86 } else { 87 final List<UserHandle> ret = new ArrayList<>(); 88 ret.add(arg); 89 return ret; 90 } 91 } 92 93 private void togglePin(ShortcutInfo selected) { 94 final String packageName = selected.getPackage(); 95 final UserHandle user = selected.getUserHandle(); 96 97 try { 98 final ShortcutQuery q = new ShortcutQuery() 99 .setPackage(packageName) 100 .setQueryFlags(ShortcutQuery.FLAG_MATCH_PINNED) 101 ; 102 103 final List<String> pinned = new ArrayList<>(); 104 for (ShortcutInfo si : mLauncherApps.getShortcuts(q, user)) { 105 pinned.add(si.getId()); 106 } 107 if (selected.isPinned()) { 108 pinned.remove(selected.getId()); 109 } else { 110 pinned.add(selected.getId()); 111 } 112 mLauncherApps.pinShortcuts(packageName, pinned, selected.getUserHandle()); 113 } catch (Exception e) { 114 Global.showToast(getContext(), e.getMessage()); 115 } 116 } 117 118 private void launch(ShortcutInfo si) { 119 try { 120 mLauncherApps.startShortcut(si.getPackage(), si.getId(), null, null, 121 si.getUserHandle()); 122 } catch (Exception e) { 123 Global.showToast(getContext(), e.getMessage()); 124 } 125 } 126 127 @Override 128 protected void refreshList() { 129 Log.i(TAG, "Refreshing shortcuts"); 130 try { 131 if (!mLauncherApps.hasShortcutHostPermission()) { 132 return; 133 } 134 135 final List<ShortcutInfo> list = new ArrayList<>(); 136 137 for (UserHandle user : getTargetUsers()) { 138 if (!mUserManager.isUserUnlocked(user)) { 139 continue; 140 } 141 142 // To detect a race condition, first fetch all shortcuts and report if none found. 143 mQuery.setQueryFlags( 144 ShortcutQuery.FLAG_MATCH_PINNED | ShortcutQuery.FLAG_MATCH_DYNAMIC 145 | ShortcutQuery.FLAG_MATCH_MANIFEST 146 | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY); 147 mQuery.setPackage(null); 148 mQuery.setActivity(null); 149 mQuery.setChangedSince(0); 150 final int numShortcuts = mLauncherApps.getShortcuts(mQuery, user).size(); 151 if (numShortcuts == 0) { 152 final String message = "No shortcut found for " + user; 153 Log.e(TAG, message); 154 Global.showToast(getContext(), message); 155 } 156 157 final Bundle b = getArguments(); 158 mQuery.setQueryFlags( 159 (b.getBoolean(ARG_INCLUDE_DYNAMIC) ? ShortcutQuery.FLAG_MATCH_DYNAMIC : 0) | 160 (b.getBoolean(ARG_INCLUDE_MANIFEST) ? ShortcutQuery.FLAG_MATCH_MANIFEST : 0) | 161 (b.getBoolean(ARG_INCLUDE_PINNED) ? ShortcutQuery.FLAG_MATCH_PINNED : 0)); 162 mQuery.setPackage(b.getString(ARG_TARGET_PACKAGE)); 163 mQuery.setActivity(b.getParcelable(ARG_TARGET_ACTIVITY)); 164 165 list.addAll(mLauncherApps.getShortcuts(mQuery, user)); 166 } 167 Collections.sort(list, mShortcutComparator); 168 169 mAdapter.setShortcuts(list); 170 } catch (Exception e) { 171 Log.w(Global.TAG, "Caught exception", e); 172 } 173 } 174 175 private final Comparator<ShortcutInfo> mShortcutComparator = 176 (ShortcutInfo s1, ShortcutInfo s2) -> { 177 int ret = 0; 178 ret = getAppLabel(s1.getPackage()).compareTo(getAppLabel(s2.getPackage())); 179 if (ret != 0) return ret; 180 181 ret = s1.getUserHandle().hashCode() - s2.getUserHandle().hashCode(); 182 if (ret != 0) return ret; 183 184 ret = s1.getId().compareTo(s2.getId()); 185 if (ret != 0) return ret; 186 187 return 0; 188 }; 189 190 class MyAdapter extends ShortcutAdapter { 191 private final boolean mShowLine2; 192 193 public MyAdapter(Context context, boolean showLine2) { 194 super(context); 195 mShowLine2 = showLine2; 196 } 197 198 @Override 199 protected int getLayoutId() { 200 return R.layout.list_item; 201 } 202 203 @Override 204 protected int getText1Id() { 205 return R.id.line1; 206 } 207 208 @Override 209 protected int getText2Id() { 210 return R.id.line2; 211 } 212 213 @Override 214 protected int getImageId() { 215 return R.id.image; 216 } 217 218 @Override 219 protected int getLaunchId() { 220 return R.id.launch; 221 } 222 223 @Override 224 protected int getAction2Id() { 225 return R.id.action2; 226 } 227 228 @Override 229 protected boolean showLaunch(ShortcutInfo si) { 230 return true; 231 } 232 233 @Override 234 protected boolean showAction2(ShortcutInfo si) { 235 return true; 236 } 237 238 @Override 239 protected String getAction2Text(ShortcutInfo si) { 240 return si.isPinned() ? "Unpin" : "Pin"; 241 } 242 243 @Override 244 protected void onLaunchClicked(ShortcutInfo si) { 245 launch(si); 246 } 247 248 @Override 249 protected void onAction2Clicked(ShortcutInfo si) { 250 togglePin(si); 251 } 252 253 @Override 254 protected boolean showLine2() { 255 return mShowLine2; 256 } 257 } 258 } 259