Home | History | Annotate | Download | only in shortcutdemo
      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.shortcutdemo;
     17 
     18 import android.app.Activity;
     19 import android.app.Notification;
     20 import android.app.Notification.Action;
     21 import android.app.Notification.Builder;
     22 import android.app.NotificationManager;
     23 import android.app.PendingIntent;
     24 import android.app.RemoteInput;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.pm.ShortcutInfo;
     29 import android.content.pm.ShortcutManager;
     30 import android.graphics.BitmapFactory;
     31 import android.graphics.drawable.Icon;
     32 import android.net.Uri;
     33 import android.os.Bundle;
     34 import android.text.format.Time;
     35 import android.util.ArrayMap;
     36 import android.util.Log;
     37 import android.util.Pair;
     38 import android.view.View;
     39 import android.widget.ListView;
     40 import android.widget.Toast;
     41 
     42 import java.util.ArrayList;
     43 import java.util.Arrays;
     44 import java.util.Collections;
     45 import java.util.Comparator;
     46 import java.util.List;
     47 import java.util.Map;
     48 import java.util.Random;
     49 import java.util.concurrent.atomic.AtomicInteger;
     50 import java.util.function.BooleanSupplier;
     51 
     52 public class ShortcutPublisher extends Activity {
     53     public static final String TAG = "ShortcutDemo";
     54 
     55     private static final String SETUP_SHORTCUT_ID = "setup";
     56 
     57     private ShortcutManager mShortcutManager;
     58 
     59     private ListView mList;
     60     private MyAdapter mAdapter;
     61 
     62     private static final Random sRandom = new Random();
     63 
     64     private static final AtomicInteger sSequenceNumber = new AtomicInteger();
     65 
     66     private ComponentName mMyActivity;
     67 
     68     @Override
     69     public void onCreate(Bundle savedInstanceState) {
     70         super.onCreate(savedInstanceState);
     71 
     72         setContentView(R.layout.main);
     73 
     74         mShortcutManager = getSystemService(ShortcutManager.class);
     75 
     76         mMyActivity = getIntent().getComponent();
     77         if (mMyActivity == null) {
     78             mMyActivity = new ComponentName(this, ShortcutPublisher.class);
     79         }
     80 
     81         mList = (ListView) findViewById(android.R.id.list);
     82         mAdapter = new MyAdapter(this);
     83         mList.setAdapter(mAdapter);
     84 
     85         Log.d(TAG, "intent=" + getIntent());
     86         Log.d(TAG, "extras=" + getIntent().getExtras());
     87     }
     88 
     89     @Override
     90     protected void onResume() {
     91         super.onResume();
     92 
     93         refreshList();
     94     }
     95 
     96     @Override
     97     protected void onDestroy() {
     98         super.onDestroy();
     99     }
    100 
    101     private List<ShortcutInfo> getAllShortcuts() {
    102         final Map<String, ShortcutInfo> map = new ArrayMap<>();
    103         for (ShortcutInfo si : mShortcutManager.getManifestShortcuts()) {
    104             if (!si.getActivity().equals(mMyActivity)) continue;
    105             if (!map.containsKey(si.getId())) {
    106                 map.put(si.getId(), si);
    107             }
    108         }
    109         for (ShortcutInfo si : mShortcutManager.getDynamicShortcuts()) {
    110             if (!si.getActivity().equals(mMyActivity)) continue;
    111             if (!map.containsKey(si.getId())) {
    112                 map.put(si.getId(), si);
    113             }
    114         }
    115         for (ShortcutInfo si : mShortcutManager.getPinnedShortcuts()) {
    116             if (!si.getActivity().equals(mMyActivity)) continue;
    117             if (!map.containsKey(si.getId())) {
    118                 map.put(si.getId(), si);
    119             }
    120         }
    121         return new ArrayList<>(map.values());
    122     }
    123 
    124     private void refreshList() {
    125         final List<ShortcutInfo> list = getAllShortcuts();
    126         Collections.sort(list, mShortcutComparator);
    127         mAdapter.setShortcuts(list);
    128     }
    129 
    130     private final Comparator<ShortcutInfo> mShortcutComparator =
    131             (ShortcutInfo s1, ShortcutInfo s2) -> {
    132                 int ret = 0;
    133                 ret = (s1.isDeclaredInManifest() ? 0 : 1) - (s2.isDeclaredInManifest() ? 0 : 1);
    134                 if (ret != 0) return ret;
    135 
    136                 ret = (s1.isDynamic() ? 0 : 1) - (s2.isDynamic() ? 0 : 1);
    137                 if (ret != 0) return ret;
    138 
    139                 ret = s1.getId().compareTo(s2.getId());
    140                 if (ret != 0) return ret;
    141 
    142                 return 0;
    143             };
    144 
    145     private void dumpCurrentShortcuts() {
    146         Log.d(TAG, "Dynamic shortcuts:");
    147         for (ShortcutInfo si : mShortcutManager.getDynamicShortcuts()) {
    148             Log.d(TAG, "  " + si.toString());
    149         }
    150         Log.d(TAG, "Pinned shortcuts:");
    151         for (ShortcutInfo si : mShortcutManager.getPinnedShortcuts()) {
    152             Log.d(TAG, "  " + si.toString());
    153         }
    154     }
    155 
    156     private static void showToast(Context context, String message) {
    157         Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    158     }
    159 
    160     private static void showThrottledToast(Context context) {
    161         showToast(context,
    162                 "Throttled, use \"adb shell cmd shortcut reset-throttling\" to reset counters");
    163     }
    164 
    165     public static void callApi(Context context, BooleanSupplier call) {
    166         try {
    167             if (!call.getAsBoolean()) {
    168                 showThrottledToast(context);
    169             }
    170         } catch (RuntimeException r) {
    171             Log.w(TAG, r.getMessage(), r);
    172             showToast(context, r.getMessage());
    173         }
    174     }
    175 
    176     private static List<Pair<String, String>> sIntentList = Arrays.asList(
    177             Pair.create("Google Search", "http://www.google.com"),
    178             Pair.create("Google Mail", "http://mail.google.com"),
    179             Pair.create("Google Maps", "http://maps.google.com"),
    180             Pair.create("Google Drive", "http://drive.google.com"),
    181             Pair.create("Google Photos", "http://photos.google.com"),
    182             Pair.create("Google Hangouts", "http://hangouts.google.com"),
    183             Pair.create("Google+", "http://plus.google.com")
    184     );
    185 
    186     public static ShortcutInfo.Builder addRandomIntents(Context context, ShortcutInfo.Builder b) {
    187         final int i = sRandom.nextInt(sIntentList.size());
    188         b.setShortLabel(sIntentList.get(i).first);
    189         b.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(sIntentList.get(i).second)));
    190         b.setIcon(Icon.createWithResource(context, R.drawable.icon2));
    191         return b;
    192     }
    193 
    194     public void onPublishPressed(View view) {
    195         dumpCurrentShortcuts();
    196         final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(getResources(),
    197                 R.drawable.icon_large_2));
    198         final Icon icon3 = Icon.createWithResource(this, R.drawable.icon_large_3);
    199 
    200         final Intent intent2 = new Intent(Intent.ACTION_VIEW);
    201         intent2.setClass(this, ShortcutPublisher.class);
    202 
    203         final Intent intent3 = new Intent(Intent.ACTION_VIEW);
    204         intent3.setClass(this, ShortcutPublisher.class);
    205         intent3.putExtra("str", "str-value");
    206         intent3.putExtra("nest", new Bundle());
    207         intent3.getBundleExtra("nest").putInt("int", 123);
    208 
    209         final ShortcutInfo si1 = addRandomIntents(this, new ShortcutInfo.Builder(this, "shortcut1"))
    210                 .setActivity(mMyActivity)
    211                 .build();
    212 
    213         final ShortcutInfo si2 = new ShortcutInfo.Builder(this, SETUP_SHORTCUT_ID)
    214                 .setActivity(mMyActivity)
    215                 .setShortLabel("Shortcut Demo Main")
    216                 .setIcon(icon2)
    217                 .setIntent(intent2)
    218                 .build();
    219 
    220         final ShortcutInfo si3 = new ShortcutInfo.Builder(this, "shortcut3")
    221                 .setActivity(mMyActivity)
    222                 .setShortLabel("Shortcut Demo Main with extras")
    223                 .setIcon(icon3)
    224                 .setIntent(intent3)
    225                 .build();
    226 
    227         callApi(this, () -> mShortcutManager.setDynamicShortcuts(Arrays.asList(si1, si2, si3)));
    228         refreshList();
    229     }
    230 
    231     public void onDeleteAllPressed(View view) {
    232         callApi(this, () -> {
    233             mShortcutManager.removeAllDynamicShortcuts();
    234             return true;
    235         });
    236         refreshList();
    237     }
    238 
    239     static String formatTime(long time) {
    240         Time tobj = new Time();
    241         tobj.set(time);
    242         return tobj.format("%Y-%m-%d %H:%M:%S");
    243     }
    244 
    245     public void onAddPressed(View view) {
    246         final ShortcutInfo si = addRandomIntents(this, new ShortcutInfo.Builder(this,
    247                     "shortcut-" + formatTime(System.currentTimeMillis()) + "-"
    248                         + sSequenceNumber.getAndIncrement()))
    249                 .setActivity(mMyActivity)
    250                 .build();
    251         callApi(this, () -> mShortcutManager.addDynamicShortcuts(Arrays.asList(si)));
    252         refreshList();
    253     }
    254 
    255     public void onUpdatePressed(View view) {
    256         final List updateList = new ArrayList<>();
    257 
    258         for (ShortcutInfo si : getAllShortcuts()) {
    259             if (SETUP_SHORTCUT_ID.equals(si.getId())) continue;
    260             if (si.isImmutable()) continue;
    261             if (!si.getActivity().equals(mMyActivity)) continue;
    262             updateList.add(addRandomIntents(this, new ShortcutInfo.Builder(this, si.getId()))
    263                     .build());
    264         }
    265         callApi(this, () -> mShortcutManager.updateShortcuts(updateList));
    266         refreshList();
    267     }
    268 
    269     void launch(ShortcutInfo si) {
    270         startActivity(si.getIntent());
    271     }
    272 
    273     void deleteDynamic(ShortcutInfo si) {
    274         mShortcutManager.removeDynamicShortcuts(Arrays.asList(si.getId()));
    275         refreshList();
    276     }
    277 
    278     public void onShowNotificationPressed(View v) {
    279         final PendingIntent receiverIntent =
    280                 PendingIntent.getBroadcast(this, 0,
    281                         new Intent().setComponent(new ComponentName(this, ShortcutReceiver.class)),
    282                         PendingIntent.FLAG_UPDATE_CURRENT);
    283         final RemoteInput ri = new RemoteInput.Builder("result").setLabel("Remote input").build();
    284 
    285         final Notification.Builder nb = new Builder(this)
    286                 .setContentText("Test")
    287                 .setContentTitle(getPackageName())
    288                 .setSmallIcon(R.drawable.icon_large_2)
    289                 .addAction(new Action.Builder(0, "Remote input", receiverIntent)
    290                         .addRemoteInput(ri)
    291                         .build());
    292         getSystemService(NotificationManager.class).notify(0, nb.build());
    293     }
    294 
    295     class MyAdapter extends ShortcutAdapter {
    296         public MyAdapter(Context context) {
    297             super(context);
    298         }
    299 
    300         @Override
    301         protected int getLayoutId() {
    302             return R.layout.list_item;
    303         }
    304 
    305         @Override
    306         protected int getText1Id() {
    307             return R.id.line1;
    308         }
    309 
    310         @Override
    311         protected int getText2Id() {
    312             return R.id.line2;
    313         }
    314 
    315         @Override
    316         protected int getImageId() {
    317             return R.id.image;
    318         }
    319 
    320         @Override
    321         protected int getLaunchId() {
    322             return R.id.launch;
    323         }
    324 
    325         @Override
    326         protected int getAction2Id() {
    327             return R.id.action2;
    328         }
    329 
    330         @Override
    331         protected boolean showLaunch(ShortcutInfo si) {
    332             return true;
    333         }
    334 
    335         @Override
    336         protected boolean showAction2(ShortcutInfo si) {
    337             return si.isDynamic(); // TODO Need disable too.
    338         }
    339 
    340         @Override
    341         protected String getAction2Text(ShortcutInfo si) {
    342             return "Delete";
    343         }
    344 
    345         @Override
    346         protected void onLaunchClicked(ShortcutInfo si) {
    347             launch(si);
    348         }
    349 
    350         @Override
    351         protected void onAction2Clicked(ShortcutInfo si) {
    352             deleteDynamic(si);
    353         }
    354     }
    355 }
    356