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