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.shortcutsample; 17 18 import android.app.Activity; 19 import android.app.AlertDialog; 20 import android.app.ListActivity; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.ShortcutInfo; 24 import android.content.pm.ShortcutManager; 25 import android.os.AsyncTask; 26 import android.os.Bundle; 27 import androidx.core.content.pm.ShortcutManagerCompat; 28 import android.util.ArraySet; 29 import android.util.Log; 30 import android.view.LayoutInflater; 31 import android.view.View; 32 import android.view.View.OnClickListener; 33 import android.view.ViewGroup; 34 import android.view.inputmethod.EditorInfo; 35 import android.widget.BaseAdapter; 36 import android.widget.Button; 37 import android.widget.EditText; 38 import android.widget.TextView; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.Set; 43 44 public class Main extends ListActivity implements OnClickListener { 45 static final String TAG = "ShortcutSample"; 46 47 private static final String ID_ADD_WEBSITE = "add_website"; 48 49 private static final String ACTION_ADD_WEBSITE = 50 "com.example.android.shortcutsample.ADD_WEBSITE"; 51 52 private MyAdapter mAdapter; 53 54 private ShortcutHelper mHelper; 55 private ShortcutManager mShortcutManager; 56 57 // @GuardedBy("sVisibleInstances") 58 private static final Set<Main> sVisibleInstances = new ArraySet<>(); 59 60 @Override onCreate(Bundle savedInstanceState)61 protected void onCreate(Bundle savedInstanceState) { 62 super.onCreate(savedInstanceState); 63 64 setContentView(R.layout.main); 65 66 mHelper = new ShortcutHelper(this); 67 mShortcutManager = getSystemService(ShortcutManager.class); 68 69 mHelper.maybeRestoreAllDynamicShortcuts(); 70 71 mHelper.refreshShortcuts(/*force=*/ false); 72 73 if (ACTION_ADD_WEBSITE.equals(getIntent().getAction())) { 74 // Invoked via the manifest shortcut. 75 addWebSite(/* forPin=*/ false, /* forResult= */ false); 76 } else if (Intent.ACTION_CREATE_SHORTCUT.equals(getIntent().getAction())) { 77 addWebSite(/* forPin=*/ true, /* forResult= */ true); 78 } 79 80 mAdapter = new MyAdapter(this.getApplicationContext()); 81 setListAdapter(mAdapter); 82 } 83 84 @Override onStart()85 protected void onStart() { 86 super.onStart(); 87 refreshList(); 88 synchronized (sVisibleInstances) { 89 sVisibleInstances.add(this); 90 } 91 findViewById(R.id.request_new_pin_shortcut).setVisibility( 92 ShortcutManagerCompat.isRequestPinShortcutSupported(this) 93 ? View.VISIBLE : View.GONE); 94 } 95 96 @Override onStop()97 protected void onStop() { 98 synchronized (sVisibleInstances) { 99 sVisibleInstances.remove(this); 100 } 101 super.onStop(); 102 } 103 104 /** 105 * Handle the add button. 106 */ onAddPressed(View v)107 public void onAddPressed(View v) { 108 addWebSite(/* forPin=*/ false, /* forResult= */ false); 109 } 110 111 /** 112 * Handle the add button. 113 */ onRequestNewPinPressed(View v)114 public void onRequestNewPinPressed(View v) { 115 addWebSite(/* forPin=*/ true, /* forResult= */ false); 116 } 117 addWebSite(boolean forPin, boolean forResult)118 private void addWebSite(boolean forPin, boolean forResult) { 119 Log.i(TAG, "addWebSite forPin=" + forPin); 120 121 // This is important. This allows the launcher to build a prediction model. 122 mHelper.reportShortcutUsed(ID_ADD_WEBSITE); 123 124 final EditText editUri = new EditText(this); 125 126 editUri.setHint("http://www.android.com/"); 127 editUri.setInputType(EditorInfo.TYPE_TEXT_VARIATION_URI); 128 129 new AlertDialog.Builder(this) 130 .setTitle(forPin ? "Create pin shortcut for website" : "Add new website") 131 .setMessage("Type URL of a website") 132 .setView(editUri) 133 .setPositiveButton("Add", (dialog, whichButton) -> { 134 final String url = editUri.getText().toString().trim(); 135 if (url.length() > 0) { 136 addUriAsync(url, forPin, forResult); 137 } 138 }) 139 .setOnCancelListener((dialog) -> { 140 if (forResult) { 141 setResult(Activity.RESULT_CANCELED); 142 finish(); 143 } 144 }) 145 .show(); 146 } 147 addUriAsync(String uri, boolean forPin, boolean forResult)148 private void addUriAsync(String uri, boolean forPin, boolean forResult) { 149 if (forResult) { 150 new AsyncTask<Void, Void, ShortcutInfo>() { 151 @Override 152 protected ShortcutInfo doInBackground(Void... params) { 153 return mHelper.createShortcutForUrl(uri); 154 } 155 156 @Override 157 protected void onPostExecute(ShortcutInfo shortcut) { 158 setResult(Activity.RESULT_OK, 159 mShortcutManager.createShortcutResultIntent(shortcut)); 160 finish(); 161 } 162 }.execute(); 163 } else { 164 new AsyncTask<Void, Void, Void>() { 165 @Override 166 protected Void doInBackground(Void... params) { 167 mHelper.addWebSiteShortcut(uri, forPin); 168 return null; 169 } 170 171 @Override 172 protected void onPostExecute(Void aVoid) { 173 refreshList(); 174 } 175 }.execute(); 176 } 177 } 178 refreshList()179 private void refreshList() { 180 mAdapter.setShortcuts(mHelper.getShortcuts()); 181 } 182 183 @Override onClick(View v)184 public void onClick(View v) { 185 final ShortcutInfo shortcut = (ShortcutInfo) ((View) v.getParent()).getTag(); 186 187 switch (v.getId()) { 188 case R.id.disable: 189 if (shortcut.isEnabled()) { 190 mHelper.disableShortcut(shortcut); 191 } else { 192 mHelper.enableShortcut(shortcut); 193 } 194 refreshList(); 195 break; 196 case R.id.remove: 197 mHelper.removeShortcut(shortcut); 198 refreshList(); 199 break; 200 case R.id.request_pin: 201 // This is an update case, so just pass the ID. 202 mHelper.requestPinShortcut(shortcut.getId()); 203 refreshList(); 204 break; 205 } 206 } 207 208 private static final List<ShortcutInfo> EMPTY_LIST = new ArrayList<>(); 209 getType(ShortcutInfo shortcut)210 private String getType(ShortcutInfo shortcut) { 211 final StringBuilder sb = new StringBuilder(); 212 String sep = ""; 213 if (shortcut.isDeclaredInManifest()) { 214 sb.append(sep); 215 sb.append("Manifest"); 216 sep = ", "; 217 } 218 if (shortcut.isDynamic()) { 219 sb.append(sep); 220 sb.append("Dynamic"); 221 sep = ", "; 222 } 223 if (shortcut.isPinned()) { 224 sb.append(sep); 225 sb.append("Pinned"); 226 sep = ", "; 227 } 228 if (!shortcut.isEnabled()) { 229 sb.append(sep); 230 sb.append("Disabled"); 231 sep = ", "; 232 } 233 return sb.toString(); 234 } 235 236 private class MyAdapter extends BaseAdapter { 237 private final Context mContext; 238 private final LayoutInflater mInflater; 239 private List<ShortcutInfo> mList = EMPTY_LIST; 240 MyAdapter(Context context)241 public MyAdapter(Context context) { 242 mContext = context; 243 mInflater = mContext.getSystemService(LayoutInflater.class); 244 } 245 246 @Override getCount()247 public int getCount() { 248 return mList.size(); 249 } 250 251 @Override getItem(int position)252 public Object getItem(int position) { 253 return mList.get(position); 254 } 255 256 @Override getItemId(int position)257 public long getItemId(int position) { 258 return position; 259 } 260 261 @Override hasStableIds()262 public boolean hasStableIds() { 263 return false; 264 } 265 266 @Override areAllItemsEnabled()267 public boolean areAllItemsEnabled() { 268 return true; 269 } 270 271 @Override isEnabled(int position)272 public boolean isEnabled(int position) { 273 return true; 274 } 275 setShortcuts(List<ShortcutInfo> list)276 public void setShortcuts(List<ShortcutInfo> list) { 277 mList = list; 278 notifyDataSetChanged(); 279 } 280 281 @Override getView(int position, View convertView, ViewGroup parent)282 public View getView(int position, View convertView, ViewGroup parent) { 283 final View view; 284 if (convertView != null) { 285 view = convertView; 286 } else { 287 view = mInflater.inflate(R.layout.list_item, null); 288 } 289 290 bindView(view, position, mList.get(position)); 291 292 return view; 293 } 294 bindView(View view, int position, ShortcutInfo shortcut)295 public void bindView(View view, int position, ShortcutInfo shortcut) { 296 view.setTag(shortcut); 297 298 final TextView line1 = (TextView) view.findViewById(R.id.line1); 299 final TextView line2 = (TextView) view.findViewById(R.id.line2); 300 301 line1.setText(shortcut.getLongLabel()); 302 line2.setText(getType(shortcut)); 303 304 final Button remove = (Button) view.findViewById(R.id.remove); 305 final Button disable = (Button) view.findViewById(R.id.disable); 306 final Button requestPin = (Button) view.findViewById(R.id.request_pin); 307 308 disable.setText( 309 shortcut.isEnabled() ? R.string.disable_shortcut : R.string.enable_shortcut); 310 311 remove.setVisibility(shortcut.isImmutable() ? View.GONE : View.VISIBLE); 312 disable.setVisibility(shortcut.isImmutable() ? View.GONE : View.VISIBLE); 313 requestPin.setVisibility( 314 ShortcutManagerCompat.isRequestPinShortcutSupported(mContext) 315 ? View.VISIBLE : View.GONE); 316 317 remove.setOnClickListener(Main.this); 318 disable.setOnClickListener(Main.this); 319 requestPin.setOnClickListener(Main.this); 320 } 321 } 322 refreshAllInstances()323 public static void refreshAllInstances() { 324 synchronized (sVisibleInstances) { 325 for (Main instance : sVisibleInstances) { 326 instance.refreshList(); 327 } 328 } 329 } 330 } 331