• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 
17 package com.android.systemui.usb;
18 
19 import android.annotation.NonNull;
20 import android.app.Notification;
21 import android.app.Notification.Action;
22 import android.app.NotificationManager;
23 import android.app.PendingIntent;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.pm.PackageManager;
29 import android.content.pm.PackageManager.MoveCallback;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.os.UserHandle;
33 import android.os.storage.DiskInfo;
34 import android.os.storage.StorageEventListener;
35 import android.os.storage.StorageManager;
36 import android.os.storage.VolumeInfo;
37 import android.os.storage.VolumeRecord;
38 import android.text.TextUtils;
39 import android.text.format.DateUtils;
40 import android.util.Log;
41 import android.util.SparseArray;
42 
43 import com.android.internal.R;
44 import com.android.systemui.SystemUI;
45 
46 import java.util.List;
47 
48 public class StorageNotification extends SystemUI {
49     private static final String TAG = "StorageNotification";
50 
51     private static final int PUBLIC_ID = 0x53505542; // SPUB
52     private static final int PRIVATE_ID = 0x53505256; // SPRV
53     private static final int DISK_ID = 0x5344534b; // SDSK
54     private static final int MOVE_ID = 0x534d4f56; // SMOV
55 
56     private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
57     private static final String ACTION_FINISH_WIZARD = "com.android.systemui.action.FINISH_WIZARD";
58 
59     // TODO: delay some notifications to avoid bumpy fast operations
60 
61     private NotificationManager mNotificationManager;
62     private StorageManager mStorageManager;
63 
64     private static class MoveInfo {
65         public int moveId;
66         public Bundle extras;
67         public String packageName;
68         public String label;
69         public String volumeUuid;
70     }
71 
72     private final SparseArray<MoveInfo> mMoves = new SparseArray<>();
73 
74     private final StorageEventListener mListener = new StorageEventListener() {
75         @Override
76         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
77             onVolumeStateChangedInternal(vol);
78         }
79 
80         @Override
81         public void onVolumeRecordChanged(VolumeRecord rec) {
82             // Avoid kicking notifications when getting early metadata before
83             // mounted. If already mounted, we're being kicked because of a
84             // nickname or init'ed change.
85             final VolumeInfo vol = mStorageManager.findVolumeByUuid(rec.getFsUuid());
86             if (vol != null && vol.isMountedReadable()) {
87                 onVolumeStateChangedInternal(vol);
88             }
89         }
90 
91         @Override
92         public void onVolumeForgotten(String fsUuid) {
93             // Stop annoying the user
94             mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
95         }
96 
97         @Override
98         public void onDiskScanned(DiskInfo disk, int volumeCount) {
99             onDiskScannedInternal(disk, volumeCount);
100         }
101 
102         @Override
103         public void onDiskDestroyed(DiskInfo disk) {
104             onDiskDestroyedInternal(disk);
105         }
106     };
107 
108     private final BroadcastReceiver mSnoozeReceiver = new BroadcastReceiver() {
109         @Override
110         public void onReceive(Context context, Intent intent) {
111             // TODO: kick this onto background thread
112             final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID);
113             mStorageManager.setVolumeSnoozed(fsUuid, true);
114         }
115     };
116 
117     private final BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
118         @Override
119         public void onReceive(Context context, Intent intent) {
120             // When finishing the adoption wizard, clean up any notifications
121             // for moving primary storage
122             mNotificationManager.cancelAsUser(null, MOVE_ID, UserHandle.ALL);
123         }
124     };
125 
126     private final MoveCallback mMoveCallback = new MoveCallback() {
127         @Override
128         public void onCreated(int moveId, Bundle extras) {
129             final MoveInfo move = new MoveInfo();
130             move.moveId = moveId;
131             move.extras = extras;
132             if (extras != null) {
133                 move.packageName = extras.getString(Intent.EXTRA_PACKAGE_NAME);
134                 move.label = extras.getString(Intent.EXTRA_TITLE);
135                 move.volumeUuid = extras.getString(VolumeRecord.EXTRA_FS_UUID);
136             }
137             mMoves.put(moveId, move);
138         }
139 
140         @Override
141         public void onStatusChanged(int moveId, int status, long estMillis) {
142             final MoveInfo move = mMoves.get(moveId);
143             if (move == null) {
144                 Log.w(TAG, "Ignoring unknown move " + moveId);
145                 return;
146             }
147 
148             if (PackageManager.isMoveStatusFinished(status)) {
149                 onMoveFinished(move, status);
150             } else {
151                 onMoveProgress(move, status, estMillis);
152             }
153         }
154     };
155 
156     @Override
start()157     public void start() {
158         mNotificationManager = mContext.getSystemService(NotificationManager.class);
159 
160         mStorageManager = mContext.getSystemService(StorageManager.class);
161         mStorageManager.registerListener(mListener);
162 
163         mContext.registerReceiver(mSnoozeReceiver, new IntentFilter(ACTION_SNOOZE_VOLUME),
164                 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
165         mContext.registerReceiver(mFinishReceiver, new IntentFilter(ACTION_FINISH_WIZARD),
166                 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
167 
168         // Kick current state into place
169         final List<DiskInfo> disks = mStorageManager.getDisks();
170         for (DiskInfo disk : disks) {
171             onDiskScannedInternal(disk, disk.volumeCount);
172         }
173 
174         final List<VolumeInfo> vols = mStorageManager.getVolumes();
175         for (VolumeInfo vol : vols) {
176             onVolumeStateChangedInternal(vol);
177         }
178 
179         mContext.getPackageManager().registerMoveCallback(mMoveCallback, new Handler());
180 
181         updateMissingPrivateVolumes();
182     }
183 
updateMissingPrivateVolumes()184     private void updateMissingPrivateVolumes() {
185         final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
186         for (VolumeRecord rec : recs) {
187             if (rec.getType() != VolumeInfo.TYPE_PRIVATE) continue;
188 
189             final String fsUuid = rec.getFsUuid();
190             final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
191             if ((info != null && info.isMountedWritable()) || rec.isSnoozed()) {
192                 // Yay, private volume is here, or user snoozed
193                 mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
194 
195             } else {
196                 // Boo, annoy the user to reinsert the private volume
197                 final CharSequence title = mContext.getString(R.string.ext_media_missing_title,
198                         rec.getNickname());
199                 final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
200 
201                 Notification.Builder builder = new Notification.Builder(mContext)
202                         .setSmallIcon(R.drawable.ic_sd_card_48dp)
203                         .setColor(mContext.getColor(R.color.system_notification_accent_color))
204                         .setContentTitle(title)
205                         .setContentText(text)
206                         .setContentIntent(buildForgetPendingIntent(rec))
207                         .setStyle(new Notification.BigTextStyle().bigText(text))
208                         .setVisibility(Notification.VISIBILITY_PUBLIC)
209                         .setLocalOnly(true)
210                         .setCategory(Notification.CATEGORY_SYSTEM)
211                         .setDeleteIntent(buildSnoozeIntent(fsUuid));
212                 SystemUI.overrideNotificationAppName(mContext, builder);
213 
214                 mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, builder
215                         .build(), UserHandle.ALL);
216             }
217         }
218     }
219 
onDiskScannedInternal(DiskInfo disk, int volumeCount)220     private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
221         if (volumeCount == 0 && disk.size > 0) {
222             // No supported volumes found, give user option to format
223             final CharSequence title = mContext.getString(
224                     R.string.ext_media_unsupported_notification_title, disk.getDescription());
225             final CharSequence text = mContext.getString(
226                     R.string.ext_media_unsupported_notification_message, disk.getDescription());
227 
228             Notification.Builder builder = new Notification.Builder(mContext)
229                     .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
230                     .setColor(mContext.getColor(R.color.system_notification_accent_color))
231                     .setContentTitle(title)
232                     .setContentText(text)
233                     .setContentIntent(buildInitPendingIntent(disk))
234                     .setStyle(new Notification.BigTextStyle().bigText(text))
235                     .setVisibility(Notification.VISIBILITY_PUBLIC)
236                     .setLocalOnly(true)
237                     .setCategory(Notification.CATEGORY_ERROR);
238             SystemUI.overrideNotificationAppName(mContext, builder);
239 
240             mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, builder.build(),
241                     UserHandle.ALL);
242 
243         } else {
244             // Yay, we have volumes!
245             mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
246         }
247     }
248 
249     /**
250      * Remove all notifications for a disk when it goes away.
251      *
252      * @param disk The disk that went away.
253      */
onDiskDestroyedInternal(@onNull DiskInfo disk)254     private void onDiskDestroyedInternal(@NonNull DiskInfo disk) {
255         mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
256     }
257 
onVolumeStateChangedInternal(VolumeInfo vol)258     private void onVolumeStateChangedInternal(VolumeInfo vol) {
259         switch (vol.getType()) {
260             case VolumeInfo.TYPE_PRIVATE:
261                 onPrivateVolumeStateChangedInternal(vol);
262                 break;
263             case VolumeInfo.TYPE_PUBLIC:
264                 onPublicVolumeStateChangedInternal(vol);
265                 break;
266         }
267     }
268 
onPrivateVolumeStateChangedInternal(VolumeInfo vol)269     private void onPrivateVolumeStateChangedInternal(VolumeInfo vol) {
270         Log.d(TAG, "Notifying about private volume: " + vol.toString());
271 
272         updateMissingPrivateVolumes();
273     }
274 
onPublicVolumeStateChangedInternal(VolumeInfo vol)275     private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
276         Log.d(TAG, "Notifying about public volume: " + vol.toString());
277 
278         final Notification notif;
279         switch (vol.getState()) {
280             case VolumeInfo.STATE_UNMOUNTED:
281                 notif = onVolumeUnmounted(vol);
282                 break;
283             case VolumeInfo.STATE_CHECKING:
284                 notif = onVolumeChecking(vol);
285                 break;
286             case VolumeInfo.STATE_MOUNTED:
287             case VolumeInfo.STATE_MOUNTED_READ_ONLY:
288                 notif = onVolumeMounted(vol);
289                 break;
290             case VolumeInfo.STATE_FORMATTING:
291                 notif = onVolumeFormatting(vol);
292                 break;
293             case VolumeInfo.STATE_EJECTING:
294                 notif = onVolumeEjecting(vol);
295                 break;
296             case VolumeInfo.STATE_UNMOUNTABLE:
297                 notif = onVolumeUnmountable(vol);
298                 break;
299             case VolumeInfo.STATE_REMOVED:
300                 notif = onVolumeRemoved(vol);
301                 break;
302             case VolumeInfo.STATE_BAD_REMOVAL:
303                 notif = onVolumeBadRemoval(vol);
304                 break;
305             default:
306                 notif = null;
307                 break;
308         }
309 
310         if (notif != null) {
311             mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
312         } else {
313             mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
314         }
315     }
316 
onVolumeUnmounted(VolumeInfo vol)317     private Notification onVolumeUnmounted(VolumeInfo vol) {
318         // Ignored
319         return null;
320     }
321 
onVolumeChecking(VolumeInfo vol)322     private Notification onVolumeChecking(VolumeInfo vol) {
323         final DiskInfo disk = vol.getDisk();
324         final CharSequence title = mContext.getString(
325                 R.string.ext_media_checking_notification_title, disk.getDescription());
326         final CharSequence text = mContext.getString(
327                 R.string.ext_media_checking_notification_message, disk.getDescription());
328 
329         return buildNotificationBuilder(vol, title, text)
330                 .setCategory(Notification.CATEGORY_PROGRESS)
331                 .setPriority(Notification.PRIORITY_LOW)
332                 .setOngoing(true)
333                 .build();
334     }
335 
onVolumeMounted(VolumeInfo vol)336     private Notification onVolumeMounted(VolumeInfo vol) {
337         final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid());
338         final DiskInfo disk = vol.getDisk();
339 
340         // Don't annoy when user dismissed in past.  (But make sure the disk is adoptable; we
341         // used to allow snoozing non-adoptable disks too.)
342         if (rec.isSnoozed() && disk.isAdoptable()) {
343             return null;
344         }
345 
346         if (disk.isAdoptable() && !rec.isInited()) {
347             final CharSequence title = disk.getDescription();
348             final CharSequence text = mContext.getString(
349                     R.string.ext_media_new_notification_message, disk.getDescription());
350 
351             final PendingIntent initIntent = buildInitPendingIntent(vol);
352             return buildNotificationBuilder(vol, title, text)
353                     .addAction(new Action(R.drawable.ic_settings_24dp,
354                             mContext.getString(R.string.ext_media_init_action), initIntent))
355                     .addAction(new Action(R.drawable.ic_eject_24dp,
356                             mContext.getString(R.string.ext_media_unmount_action),
357                             buildUnmountPendingIntent(vol)))
358                     .setContentIntent(initIntent)
359                     .setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()))
360                     .setCategory(Notification.CATEGORY_SYSTEM)
361                     .build();
362 
363         } else {
364             final CharSequence title = disk.getDescription();
365             final CharSequence text = mContext.getString(
366                     R.string.ext_media_ready_notification_message, disk.getDescription());
367 
368             final PendingIntent browseIntent = buildBrowsePendingIntent(vol);
369             final Notification.Builder builder = buildNotificationBuilder(vol, title, text)
370                     .addAction(new Action(R.drawable.ic_folder_24dp,
371                             mContext.getString(R.string.ext_media_browse_action),
372                             browseIntent))
373                     .addAction(new Action(R.drawable.ic_eject_24dp,
374                             mContext.getString(R.string.ext_media_unmount_action),
375                             buildUnmountPendingIntent(vol)))
376                     .setContentIntent(browseIntent)
377                     .setCategory(Notification.CATEGORY_SYSTEM)
378                     .setPriority(Notification.PRIORITY_LOW);
379             // Non-adoptable disks can't be snoozed.
380             if (disk.isAdoptable()) {
381                 builder.setDeleteIntent(buildSnoozeIntent(vol.getFsUuid()));
382             }
383 
384             return builder.build();
385         }
386     }
387 
onVolumeFormatting(VolumeInfo vol)388     private Notification onVolumeFormatting(VolumeInfo vol) {
389         // Ignored
390         return null;
391     }
392 
onVolumeEjecting(VolumeInfo vol)393     private Notification onVolumeEjecting(VolumeInfo vol) {
394         final DiskInfo disk = vol.getDisk();
395         final CharSequence title = mContext.getString(
396                 R.string.ext_media_unmounting_notification_title, disk.getDescription());
397         final CharSequence text = mContext.getString(
398                 R.string.ext_media_unmounting_notification_message, disk.getDescription());
399 
400         return buildNotificationBuilder(vol, title, text)
401                 .setCategory(Notification.CATEGORY_PROGRESS)
402                 .setPriority(Notification.PRIORITY_LOW)
403                 .setOngoing(true)
404                 .build();
405     }
406 
onVolumeUnmountable(VolumeInfo vol)407     private Notification onVolumeUnmountable(VolumeInfo vol) {
408         final DiskInfo disk = vol.getDisk();
409         final CharSequence title = mContext.getString(
410                 R.string.ext_media_unmountable_notification_title, disk.getDescription());
411         final CharSequence text = mContext.getString(
412                 R.string.ext_media_unmountable_notification_message, disk.getDescription());
413 
414         return buildNotificationBuilder(vol, title, text)
415                 .setContentIntent(buildInitPendingIntent(vol))
416                 .setCategory(Notification.CATEGORY_ERROR)
417                 .build();
418     }
419 
onVolumeRemoved(VolumeInfo vol)420     private Notification onVolumeRemoved(VolumeInfo vol) {
421         if (!vol.isPrimary()) {
422             // Ignore non-primary media
423             return null;
424         }
425 
426         final DiskInfo disk = vol.getDisk();
427         final CharSequence title = mContext.getString(
428                 R.string.ext_media_nomedia_notification_title, disk.getDescription());
429         final CharSequence text = mContext.getString(
430                 R.string.ext_media_nomedia_notification_message, disk.getDescription());
431 
432         return buildNotificationBuilder(vol, title, text)
433                 .setCategory(Notification.CATEGORY_ERROR)
434                 .build();
435     }
436 
onVolumeBadRemoval(VolumeInfo vol)437     private Notification onVolumeBadRemoval(VolumeInfo vol) {
438         if (!vol.isPrimary()) {
439             // Ignore non-primary media
440             return null;
441         }
442 
443         final DiskInfo disk = vol.getDisk();
444         final CharSequence title = mContext.getString(
445                 R.string.ext_media_badremoval_notification_title, disk.getDescription());
446         final CharSequence text = mContext.getString(
447                 R.string.ext_media_badremoval_notification_message, disk.getDescription());
448 
449         return buildNotificationBuilder(vol, title, text)
450                 .setCategory(Notification.CATEGORY_ERROR)
451                 .build();
452     }
453 
onMoveProgress(MoveInfo move, int status, long estMillis)454     private void onMoveProgress(MoveInfo move, int status, long estMillis) {
455         final CharSequence title;
456         if (!TextUtils.isEmpty(move.label)) {
457             title = mContext.getString(R.string.ext_media_move_specific_title, move.label);
458         } else {
459             title = mContext.getString(R.string.ext_media_move_title);
460         }
461 
462         final CharSequence text;
463         if (estMillis < 0) {
464             text = null;
465         } else {
466             text = DateUtils.formatDuration(estMillis);
467         }
468 
469         final PendingIntent intent;
470         if (move.packageName != null) {
471             intent = buildWizardMovePendingIntent(move);
472         } else {
473             intent = buildWizardMigratePendingIntent(move);
474         }
475 
476         Notification.Builder builder = new Notification.Builder(mContext)
477                 .setSmallIcon(R.drawable.ic_sd_card_48dp)
478                 .setColor(mContext.getColor(R.color.system_notification_accent_color))
479                 .setContentTitle(title)
480                 .setContentText(text)
481                 .setContentIntent(intent)
482                 .setStyle(new Notification.BigTextStyle().bigText(text))
483                 .setVisibility(Notification.VISIBILITY_PUBLIC)
484                 .setLocalOnly(true)
485                 .setCategory(Notification.CATEGORY_PROGRESS)
486                 .setPriority(Notification.PRIORITY_LOW)
487                 .setProgress(100, status, false)
488                 .setOngoing(true);
489         SystemUI.overrideNotificationAppName(mContext, builder);
490 
491         mNotificationManager.notifyAsUser(move.packageName, MOVE_ID,
492                 builder.build(), UserHandle.ALL);
493     }
494 
onMoveFinished(MoveInfo move, int status)495     private void onMoveFinished(MoveInfo move, int status) {
496         if (move.packageName != null) {
497             // We currently ignore finished app moves; just clear the last
498             // published progress
499             mNotificationManager.cancelAsUser(move.packageName, MOVE_ID, UserHandle.ALL);
500             return;
501         }
502 
503         final VolumeInfo privateVol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
504         final String descrip = mStorageManager.getBestVolumeDescription(privateVol);
505 
506         final CharSequence title;
507         final CharSequence text;
508         if (status == PackageManager.MOVE_SUCCEEDED) {
509             title = mContext.getString(R.string.ext_media_move_success_title);
510             text = mContext.getString(R.string.ext_media_move_success_message, descrip);
511         } else {
512             title = mContext.getString(R.string.ext_media_move_failure_title);
513             text = mContext.getString(R.string.ext_media_move_failure_message);
514         }
515 
516         // Jump back into the wizard flow if we moved to a real disk
517         final PendingIntent intent;
518         if (privateVol != null && privateVol.getDisk() != null) {
519             intent = buildWizardReadyPendingIntent(privateVol.getDisk());
520         } else if (privateVol != null) {
521             intent = buildVolumeSettingsPendingIntent(privateVol);
522         } else {
523             intent = null;
524         }
525 
526         Notification.Builder builder = new Notification.Builder(mContext)
527                 .setSmallIcon(R.drawable.ic_sd_card_48dp)
528                 .setColor(mContext.getColor(R.color.system_notification_accent_color))
529                 .setContentTitle(title)
530                 .setContentText(text)
531                 .setContentIntent(intent)
532                 .setStyle(new Notification.BigTextStyle().bigText(text))
533                 .setVisibility(Notification.VISIBILITY_PUBLIC)
534                 .setLocalOnly(true)
535                 .setCategory(Notification.CATEGORY_SYSTEM)
536                 .setPriority(Notification.PRIORITY_LOW)
537                 .setAutoCancel(true);
538         SystemUI.overrideNotificationAppName(mContext, builder);
539 
540         mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, builder.build(),
541                 UserHandle.ALL);
542     }
543 
getSmallIcon(DiskInfo disk, int state)544     private int getSmallIcon(DiskInfo disk, int state) {
545         if (disk.isSd()) {
546             switch (state) {
547                 case VolumeInfo.STATE_CHECKING:
548                 case VolumeInfo.STATE_EJECTING:
549                     return R.drawable.ic_sd_card_48dp;
550                 default:
551                     return R.drawable.ic_sd_card_48dp;
552             }
553         } else if (disk.isUsb()) {
554             return R.drawable.ic_usb_48dp;
555         } else {
556             return R.drawable.ic_sd_card_48dp;
557         }
558     }
559 
buildNotificationBuilder(VolumeInfo vol, CharSequence title, CharSequence text)560     private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
561             CharSequence text) {
562         Notification.Builder builder = new Notification.Builder(mContext)
563                 .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
564                 .setColor(mContext.getColor(R.color.system_notification_accent_color))
565                 .setContentTitle(title)
566                 .setContentText(text)
567                 .setStyle(new Notification.BigTextStyle().bigText(text))
568                 .setVisibility(Notification.VISIBILITY_PUBLIC)
569                 .setLocalOnly(true);
570         overrideNotificationAppName(mContext, builder);
571         return builder;
572     }
573 
buildInitPendingIntent(DiskInfo disk)574     private PendingIntent buildInitPendingIntent(DiskInfo disk) {
575         final Intent intent = new Intent();
576         intent.setClassName("com.android.settings",
577                 "com.android.settings.deviceinfo.StorageWizardInit");
578         intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
579 
580         final int requestKey = disk.getId().hashCode();
581         return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
582                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
583     }
584 
buildInitPendingIntent(VolumeInfo vol)585     private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
586         final Intent intent = new Intent();
587         intent.setClassName("com.android.settings",
588                 "com.android.settings.deviceinfo.StorageWizardInit");
589         intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
590 
591         final int requestKey = vol.getId().hashCode();
592         return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
593                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
594     }
595 
buildUnmountPendingIntent(VolumeInfo vol)596     private PendingIntent buildUnmountPendingIntent(VolumeInfo vol) {
597         final Intent intent = new Intent();
598         intent.setClassName("com.android.settings",
599                 "com.android.settings.deviceinfo.StorageUnmountReceiver");
600         intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
601 
602         final int requestKey = vol.getId().hashCode();
603         return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
604                 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
605     }
606 
buildBrowsePendingIntent(VolumeInfo vol)607     private PendingIntent buildBrowsePendingIntent(VolumeInfo vol) {
608         final Intent intent = vol.buildBrowseIntent();
609 
610         final int requestKey = vol.getId().hashCode();
611         return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
612                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
613     }
614 
buildVolumeSettingsPendingIntent(VolumeInfo vol)615     private PendingIntent buildVolumeSettingsPendingIntent(VolumeInfo vol) {
616         final Intent intent = new Intent();
617         switch (vol.getType()) {
618             case VolumeInfo.TYPE_PRIVATE:
619                 intent.setClassName("com.android.settings",
620                         "com.android.settings.Settings$PrivateVolumeSettingsActivity");
621                 break;
622             case VolumeInfo.TYPE_PUBLIC:
623                 intent.setClassName("com.android.settings",
624                         "com.android.settings.Settings$PublicVolumeSettingsActivity");
625                 break;
626             default:
627                 return null;
628         }
629         intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
630 
631         final int requestKey = vol.getId().hashCode();
632         return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
633                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
634     }
635 
buildSnoozeIntent(String fsUuid)636     private PendingIntent buildSnoozeIntent(String fsUuid) {
637         final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
638         intent.putExtra(VolumeRecord.EXTRA_FS_UUID, fsUuid);
639 
640         final int requestKey = fsUuid.hashCode();
641         return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
642                 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
643     }
644 
buildForgetPendingIntent(VolumeRecord rec)645     private PendingIntent buildForgetPendingIntent(VolumeRecord rec) {
646         final Intent intent = new Intent();
647         intent.setClassName("com.android.settings",
648                 "com.android.settings.Settings$PrivateVolumeForgetActivity");
649         intent.putExtra(VolumeRecord.EXTRA_FS_UUID, rec.getFsUuid());
650 
651         final int requestKey = rec.getFsUuid().hashCode();
652         return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
653                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
654     }
655 
buildWizardMigratePendingIntent(MoveInfo move)656     private PendingIntent buildWizardMigratePendingIntent(MoveInfo move) {
657         final Intent intent = new Intent();
658         intent.setClassName("com.android.settings",
659                 "com.android.settings.deviceinfo.StorageWizardMigrateProgress");
660         intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId);
661 
662         final VolumeInfo vol = mStorageManager.findVolumeByQualifiedUuid(move.volumeUuid);
663         if (vol != null) {
664             intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
665         }
666         return PendingIntent.getActivityAsUser(mContext, move.moveId, intent,
667                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
668     }
669 
buildWizardMovePendingIntent(MoveInfo move)670     private PendingIntent buildWizardMovePendingIntent(MoveInfo move) {
671         final Intent intent = new Intent();
672         intent.setClassName("com.android.settings",
673                 "com.android.settings.deviceinfo.StorageWizardMoveProgress");
674         intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId);
675 
676         return PendingIntent.getActivityAsUser(mContext, move.moveId, intent,
677                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
678     }
679 
buildWizardReadyPendingIntent(DiskInfo disk)680     private PendingIntent buildWizardReadyPendingIntent(DiskInfo disk) {
681         final Intent intent = new Intent();
682         intent.setClassName("com.android.settings",
683                 "com.android.settings.deviceinfo.StorageWizardReady");
684         intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
685 
686         final int requestKey = disk.getId().hashCode();
687         return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
688                 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
689     }
690 }
691