blob: ad215551a90f08d12148d97426a31edbf45e193d [file] [log] [blame]
San Mehat64e6a452010-02-04 20:53:48 -08001/*
Jeff Sharkey56bd3122015-04-14 10:30:34 -07002 * Copyright (C) 2015 The Android Open Source Project
San Mehat64e6a452010-02-04 20:53:48 -08003 *
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
Joe Onoratofe4f3ae2010-06-04 11:25:26 -070017package com.android.systemui.usb;
San Mehat64e6a452010-02-04 20:53:48 -080018
San Mehat64e6a452010-02-04 20:53:48 -080019import android.app.Notification;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070020import android.app.Notification.Action;
San Mehat64e6a452010-02-04 20:53:48 -080021import android.app.NotificationManager;
22import android.app.PendingIntent;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070023import android.content.BroadcastReceiver;
24import android.content.Context;
San Mehat64e6a452010-02-04 20:53:48 -080025import android.content.Intent;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070026import android.content.IntentFilter;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070027import android.content.pm.PackageManager;
28import android.content.pm.PackageManager.MoveCallback;
Jeff Sharkey50a05452015-04-29 11:24:52 -070029import android.os.Bundle;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070030import android.os.Handler;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070031import android.os.UserHandle;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070032import android.os.storage.DiskInfo;
San Mehatb1043402010-02-05 08:26:50 -080033import android.os.storage.StorageEventListener;
34import android.os.storage.StorageManager;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070035import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070036import android.os.storage.VolumeRecord;
37import android.text.TextUtils;
38import android.text.format.DateUtils;
John Spurlockcd686b52013-06-05 10:13:46 -040039import android.util.Log;
Jeff Sharkey50a05452015-04-29 11:24:52 -070040import android.util.SparseArray;
San Mehat64e6a452010-02-04 20:53:48 -080041
Jeff Sharkey56bd3122015-04-14 10:30:34 -070042import com.android.internal.R;
John Spurlock3e309b22013-06-25 11:01:29 -040043import com.android.systemui.SystemUI;
44
Jeff Sharkey56bd3122015-04-14 10:30:34 -070045import java.util.List;
46
John Spurlock3e309b22013-06-25 11:01:29 -040047public class StorageNotification extends SystemUI {
San Mehat64e6a452010-02-04 20:53:48 -080048 private static final String TAG = "StorageNotification";
49
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070050 private static final int PUBLIC_ID = 0x53505542; // SPUB
51 private static final int PRIVATE_ID = 0x53505256; // SPRV
52 private static final int DISK_ID = 0x5344534b; // SDSK
53 private static final int MOVE_ID = 0x534d4f56; // SMOV
Daniel Sandlerc07907e2010-02-22 15:08:41 -050054
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070055 private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
56
Jeff Sharkey56bd3122015-04-14 10:30:34 -070057 // TODO: delay some notifications to avoid bumpy fast operations
San Mehat64e6a452010-02-04 20:53:48 -080058
Jeff Sharkey56bd3122015-04-14 10:30:34 -070059 private NotificationManager mNotificationManager;
San Mehatb1043402010-02-05 08:26:50 -080060 private StorageManager mStorageManager;
San Mehat64e6a452010-02-04 20:53:48 -080061
Jeff Sharkey50a05452015-04-29 11:24:52 -070062 private static class MoveInfo {
63 public int moveId;
64 public Bundle extras;
65 public String packageName;
66 public String label;
67 public String volumeUuid;
68 }
69
70 private final SparseArray<MoveInfo> mMoves = new SparseArray<>();
71
Jeff Sharkey56bd3122015-04-14 10:30:34 -070072 private final StorageEventListener mListener = new StorageEventListener() {
73 @Override
74 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070075 onVolumeStateChangedInternal(vol);
John Spurlock3e309b22013-06-25 11:01:29 -040076 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070077
78 @Override
Jeff Sharkey50a05452015-04-29 11:24:52 -070079 public void onVolumeRecordChanged(VolumeRecord rec) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070080 // Avoid kicking notifications when getting early metadata before
81 // mounted. If already mounted, we're being kicked because of a
82 // nickname or init'ed change.
Jeff Sharkey50a05452015-04-29 11:24:52 -070083 final VolumeInfo vol = mStorageManager.findVolumeByUuid(rec.getFsUuid());
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070084 if (vol != null && vol.isMountedReadable()) {
85 onVolumeStateChangedInternal(vol);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070086 }
Jeff Sharkey50a05452015-04-29 11:24:52 -070087 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070088
Jeff Sharkey50a05452015-04-29 11:24:52 -070089 @Override
90 public void onVolumeForgotten(String fsUuid) {
91 // Stop annoying the user
92 mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070093 }
94
95 @Override
96 public void onDiskScanned(DiskInfo disk, int volumeCount) {
97 onDiskScannedInternal(disk, volumeCount);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070098 }
99 };
100
101 private final BroadcastReceiver mSnoozeReceiver = new BroadcastReceiver() {
102 @Override
103 public void onReceive(Context context, Intent intent) {
104 // TODO: kick this onto background thread
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700105 final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID);
106 mStorageManager.setVolumeSnoozed(fsUuid, true);
107 }
108 };
109
110 private final MoveCallback mMoveCallback = new MoveCallback() {
111 @Override
Jeff Sharkey50a05452015-04-29 11:24:52 -0700112 public void onCreated(int moveId, Bundle extras) {
113 final MoveInfo move = new MoveInfo();
114 move.moveId = moveId;
115 move.extras = extras;
116 if (extras != null) {
117 move.packageName = extras.getString(Intent.EXTRA_PACKAGE_NAME);
118 move.label = extras.getString(Intent.EXTRA_TITLE);
119 move.volumeUuid = extras.getString(VolumeRecord.EXTRA_FS_UUID);
120 }
121 mMoves.put(moveId, move);
122 }
123
124 @Override
125 public void onStatusChanged(int moveId, int status, long estMillis) {
126 final MoveInfo move = mMoves.get(moveId);
127 if (move == null) {
128 Log.w(TAG, "Ignoring unknown move " + moveId);
129 return;
130 }
131
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700132 if (PackageManager.isMoveStatusFinished(status)) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700133 onMoveFinished(move, status);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700134 } else {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700135 onMoveProgress(move, status, estMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700136 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700137 }
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700138 };
San Mehat64e6a452010-02-04 20:53:48 -0800139
John Spurlock3e309b22013-06-25 11:01:29 -0400140 @Override
141 public void start() {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700142 mNotificationManager = mContext.getSystemService(NotificationManager.class);
John Spurlock3e309b22013-06-25 11:01:29 -0400143
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700144 mStorageManager = mContext.getSystemService(StorageManager.class);
145 mStorageManager.registerListener(mListener);
Daniel Sandler5b8743f2010-11-03 09:43:46 -0400146
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700147 mContext.registerReceiver(mSnoozeReceiver, new IntentFilter(ACTION_SNOOZE_VOLUME),
148 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
149
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700150 // Kick current state into place
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -0700151 final List<DiskInfo> disks = mStorageManager.getDisks();
152 for (DiskInfo disk : disks) {
153 onDiskScannedInternal(disk, disk.volumeCount);
154 }
155
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700156 final List<VolumeInfo> vols = mStorageManager.getVolumes();
157 for (VolumeInfo vol : vols) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700158 onVolumeStateChangedInternal(vol);
159 }
160
161 mContext.getPackageManager().registerMoveCallback(mMoveCallback, new Handler());
162
163 updateMissingPrivateVolumes();
164 }
165
166 private void updateMissingPrivateVolumes() {
167 final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
168 for (VolumeRecord rec : recs) {
169 if (rec.getType() != VolumeInfo.TYPE_PRIVATE) continue;
170
171 final String fsUuid = rec.getFsUuid();
172 final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
173 if (info != null && info.isMountedWritable()) {
174 // Yay, private volume is here!
175 mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
176
177 } else {
178 // Boo, annoy the user to reinsert the private volume
179 final CharSequence title = mContext.getString(R.string.ext_media_missing_title,
180 rec.getNickname());
181 final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
182
183 final Notification notif = new Notification.Builder(mContext)
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700184 .setSmallIcon(R.drawable.ic_sd_card_48dp)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700185 .setColor(mContext.getColor(R.color.system_notification_accent_color))
186 .setContentTitle(title)
187 .setContentText(text)
Jeff Sharkey50a05452015-04-29 11:24:52 -0700188 .setContentIntent(buildForgetPendingIntent(rec))
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700189 .setStyle(new Notification.BigTextStyle().bigText(text))
190 .setVisibility(Notification.VISIBILITY_PUBLIC)
191 .setLocalOnly(true)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700192 .setCategory(Notification.CATEGORY_SYSTEM)
193 .setOngoing(true)
194 .build();
195
196 mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, notif, UserHandle.ALL);
197 }
San Mehat64e6a452010-02-04 20:53:48 -0800198 }
199 }
200
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700201 private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -0700202 if (volumeCount == 0 && disk.size > 0) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700203 // No supported volumes found, give user option to format
204 final CharSequence title = mContext.getString(
205 R.string.ext_media_unmountable_notification_title, disk.getDescription());
206 final CharSequence text = mContext.getString(
207 R.string.ext_media_unmountable_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800208
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700209 final Notification notif = new Notification.Builder(mContext)
210 .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
211 .setColor(mContext.getColor(R.color.system_notification_accent_color))
212 .setContentTitle(title)
213 .setContentText(text)
Jeff Sharkey50a05452015-04-29 11:24:52 -0700214 .setContentIntent(buildInitPendingIntent(disk))
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700215 .setStyle(new Notification.BigTextStyle().bigText(text))
216 .setVisibility(Notification.VISIBILITY_PUBLIC)
217 .setLocalOnly(true)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700218 .setCategory(Notification.CATEGORY_ERROR)
219 .build();
220
221 mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, notif, UserHandle.ALL);
222
223 } else {
224 // Yay, we have volumes!
225 mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
226 }
227 }
228
229 private void onVolumeStateChangedInternal(VolumeInfo vol) {
230 switch (vol.getType()) {
231 case VolumeInfo.TYPE_PRIVATE:
232 onPrivateVolumeStateChangedInternal(vol);
233 break;
234 case VolumeInfo.TYPE_PUBLIC:
235 onPublicVolumeStateChangedInternal(vol);
236 break;
237 }
238 }
239
240 private void onPrivateVolumeStateChangedInternal(VolumeInfo vol) {
241 Log.d(TAG, "Notifying about private volume: " + vol.toString());
242
243 updateMissingPrivateVolumes();
244 }
245
246 private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
247 Log.d(TAG, "Notifying about public volume: " + vol.toString());
San Mehat64e6a452010-02-04 20:53:48 -0800248
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700249 final Notification notif;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700250 switch (vol.getState()) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700251 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700252 notif = onVolumeUnmounted(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700253 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700254 case VolumeInfo.STATE_CHECKING:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700255 notif = onVolumeChecking(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700256 break;
257 case VolumeInfo.STATE_MOUNTED:
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700258 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700259 notif = onVolumeMounted(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700260 break;
261 case VolumeInfo.STATE_FORMATTING:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700262 notif = onVolumeFormatting(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700263 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700264 case VolumeInfo.STATE_EJECTING:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700265 notif = onVolumeEjecting(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700266 break;
267 case VolumeInfo.STATE_UNMOUNTABLE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700268 notif = onVolumeUnmountable(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700269 break;
270 case VolumeInfo.STATE_REMOVED:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700271 notif = onVolumeRemoved(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700272 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700273 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700274 notif = onVolumeBadRemoval(vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700275 break;
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700276 default:
277 notif = null;
278 break;
279 }
280
281 if (notif != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700282 mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700283 } else {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700284 mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
San Mehat64e6a452010-02-04 20:53:48 -0800285 }
286 }
287
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700288 private Notification onVolumeUnmounted(VolumeInfo vol) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700289 // Ignored
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700290 return null;
San Mehat64e6a452010-02-04 20:53:48 -0800291 }
292
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700293 private Notification onVolumeChecking(VolumeInfo vol) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700294 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700295 final CharSequence title = mContext.getString(
296 R.string.ext_media_checking_notification_title, disk.getDescription());
297 final CharSequence text = mContext.getString(
298 R.string.ext_media_checking_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800299
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700300 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700301 .setCategory(Notification.CATEGORY_PROGRESS)
302 .setPriority(Notification.PRIORITY_LOW)
303 .setOngoing(true)
304 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700305 }
San Mehat64e6a452010-02-04 20:53:48 -0800306
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700307 private Notification onVolumeMounted(VolumeInfo vol) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700308 final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid());
309
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700310 // Don't annoy when user dismissed in past
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700311 if (rec.isSnoozed()) return null;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700312
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700313 final DiskInfo disk = vol.getDisk();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700314 if (disk.isAdoptable() && !rec.isInited()) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700315 final CharSequence title = disk.getDescription();
316 final CharSequence text = mContext.getString(
317 R.string.ext_media_new_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800318
Jeff Sharkey50a05452015-04-29 11:24:52 -0700319 final PendingIntent initIntent = buildInitPendingIntent(vol);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700320 return buildNotificationBuilder(vol, title, text)
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700321 .addAction(new Action(R.drawable.ic_settings_24dp,
322 mContext.getString(R.string.ext_media_init_action), initIntent))
323 .addAction(new Action(R.drawable.ic_eject_24dp,
324 mContext.getString(R.string.ext_media_unmount_action),
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700325 buildUnmountPendingIntent(vol)))
Jeff Sharkey50a05452015-04-29 11:24:52 -0700326 .setContentIntent(initIntent)
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700327 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700328 .setCategory(Notification.CATEGORY_SYSTEM)
329 .build();
John Spurlock209bede2013-07-17 12:23:27 -0400330
San Mehat64e6a452010-02-04 20:53:48 -0800331 } else {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700332 final CharSequence title = disk.getDescription();
333 final CharSequence text = mContext.getString(
334 R.string.ext_media_ready_notification_message, disk.getDescription());
335
Jeff Sharkey50a05452015-04-29 11:24:52 -0700336 final PendingIntent browseIntent = buildBrowsePendingIntent(vol);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700337 return buildNotificationBuilder(vol, title, text)
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700338 .addAction(new Action(R.drawable.ic_folder_24dp,
339 mContext.getString(R.string.ext_media_browse_action),
Jeff Sharkey50a05452015-04-29 11:24:52 -0700340 browseIntent))
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700341 .addAction(new Action(R.drawable.ic_eject_24dp,
342 mContext.getString(R.string.ext_media_unmount_action),
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700343 buildUnmountPendingIntent(vol)))
Jeff Sharkey50a05452015-04-29 11:24:52 -0700344 .setContentIntent(browseIntent)
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700345 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700346 .setCategory(Notification.CATEGORY_SYSTEM)
347 .setPriority(Notification.PRIORITY_LOW)
348 .build();
San Mehat64e6a452010-02-04 20:53:48 -0800349 }
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700350 }
351
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700352 private Notification onVolumeFormatting(VolumeInfo vol) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700353 // Ignored
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700354 return null;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700355 }
356
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700357 private Notification onVolumeEjecting(VolumeInfo vol) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700358 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700359 final CharSequence title = mContext.getString(
360 R.string.ext_media_unmounting_notification_title, disk.getDescription());
361 final CharSequence text = mContext.getString(
362 R.string.ext_media_unmounting_notification_message, disk.getDescription());
363
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700364 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700365 .setCategory(Notification.CATEGORY_PROGRESS)
366 .setPriority(Notification.PRIORITY_LOW)
367 .setOngoing(true)
368 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700369 }
370
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700371 private Notification onVolumeUnmountable(VolumeInfo vol) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700372 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700373 final CharSequence title = mContext.getString(
374 R.string.ext_media_unmountable_notification_title, disk.getDescription());
375 final CharSequence text = mContext.getString(
376 R.string.ext_media_unmountable_notification_message, disk.getDescription());
377
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700378 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey50a05452015-04-29 11:24:52 -0700379 .setContentIntent(buildVolumeSettingsPendingIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700380 .setCategory(Notification.CATEGORY_ERROR)
381 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700382 }
383
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700384 private Notification onVolumeRemoved(VolumeInfo vol) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700385 if (!vol.isPrimary()) {
386 // Ignore non-primary media
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700387 return null;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700388 }
389
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700390 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700391 final CharSequence title = mContext.getString(
392 R.string.ext_media_nomedia_notification_title, disk.getDescription());
393 final CharSequence text = mContext.getString(
394 R.string.ext_media_nomedia_notification_message, disk.getDescription());
395
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700396 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700397 .setCategory(Notification.CATEGORY_ERROR)
398 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700399 }
400
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700401 private Notification onVolumeBadRemoval(VolumeInfo vol) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700402 if (!vol.isPrimary()) {
403 // Ignore non-primary media
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700404 return null;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700405 }
406
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700407 final DiskInfo disk = vol.getDisk();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700408 final CharSequence title = mContext.getString(
409 R.string.ext_media_badremoval_notification_title, disk.getDescription());
410 final CharSequence text = mContext.getString(
411 R.string.ext_media_badremoval_notification_message, disk.getDescription());
412
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700413 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700414 .setCategory(Notification.CATEGORY_ERROR)
415 .build();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700416 }
417
Jeff Sharkey50a05452015-04-29 11:24:52 -0700418 private void onMoveProgress(MoveInfo move, int status, long estMillis) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700419 final CharSequence title;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700420 if (!TextUtils.isEmpty(move.label)) {
421 title = mContext.getString(R.string.ext_media_move_specific_title, move.label);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700422 } else {
423 title = mContext.getString(R.string.ext_media_move_title);
424 }
425
426 final CharSequence text;
427 if (estMillis < 0) {
428 text = null;
429 } else {
430 text = DateUtils.formatDuration(estMillis);
431 }
432
Jeff Sharkey50a05452015-04-29 11:24:52 -0700433 final PendingIntent intent;
434 if (move.packageName != null) {
435 intent = buildWizardMovePendingIntent(move);
436 } else {
437 intent = buildWizardMigratePendingIntent(move);
438 }
439
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700440 final Notification notif = new Notification.Builder(mContext)
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700441 .setSmallIcon(R.drawable.ic_sd_card_48dp)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700442 .setColor(mContext.getColor(R.color.system_notification_accent_color))
443 .setContentTitle(title)
444 .setContentText(text)
Jeff Sharkey50a05452015-04-29 11:24:52 -0700445 .setContentIntent(intent)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700446 .setStyle(new Notification.BigTextStyle().bigText(text))
447 .setVisibility(Notification.VISIBILITY_PUBLIC)
448 .setLocalOnly(true)
449 .setCategory(Notification.CATEGORY_PROGRESS)
450 .setPriority(Notification.PRIORITY_LOW)
451 .setProgress(100, status, false)
452 .setOngoing(true)
453 .build();
454
Jeff Sharkey50a05452015-04-29 11:24:52 -0700455 mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700456 }
457
Jeff Sharkey50a05452015-04-29 11:24:52 -0700458 private void onMoveFinished(MoveInfo move, int status) {
459 if (move.packageName != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700460 // We currently ignore finished app moves; just clear the last
461 // published progress
Jeff Sharkey50a05452015-04-29 11:24:52 -0700462 mNotificationManager.cancelAsUser(move.packageName, MOVE_ID, UserHandle.ALL);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700463 return;
464 }
465
Jeff Sharkey50a05452015-04-29 11:24:52 -0700466 final VolumeInfo privateVol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
467 final String descrip = mStorageManager.getBestVolumeDescription(privateVol);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700468
469 final CharSequence title;
470 final CharSequence text;
471 if (status == PackageManager.MOVE_SUCCEEDED) {
472 title = mContext.getString(R.string.ext_media_move_success_title);
473 text = mContext.getString(R.string.ext_media_move_success_message, descrip);
474 } else {
475 title = mContext.getString(R.string.ext_media_move_failure_title);
476 text = mContext.getString(R.string.ext_media_move_failure_message);
477 }
478
Jeff Sharkey50a05452015-04-29 11:24:52 -0700479 // Jump back into the wizard flow if we moved to a real disk
480 final PendingIntent intent;
481 if (privateVol != null && privateVol.getDisk() != null) {
482 intent = buildWizardReadyPendingIntent(privateVol.getDisk());
483 } else {
484 intent = buildVolumeSettingsPendingIntent(privateVol);
485 }
486
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700487 final Notification notif = new Notification.Builder(mContext)
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700488 .setSmallIcon(R.drawable.ic_sd_card_48dp)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700489 .setColor(mContext.getColor(R.color.system_notification_accent_color))
490 .setContentTitle(title)
491 .setContentText(text)
Jeff Sharkey50a05452015-04-29 11:24:52 -0700492 .setContentIntent(intent)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700493 .setStyle(new Notification.BigTextStyle().bigText(text))
494 .setVisibility(Notification.VISIBILITY_PUBLIC)
495 .setLocalOnly(true)
496 .setCategory(Notification.CATEGORY_SYSTEM)
497 .setPriority(Notification.PRIORITY_LOW)
Jeff Sharkey50a05452015-04-29 11:24:52 -0700498 .setAutoCancel(true)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700499 .build();
500
Jeff Sharkey50a05452015-04-29 11:24:52 -0700501 mNotificationManager.notifyAsUser(move.packageName, MOVE_ID, notif, UserHandle.ALL);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700502 }
503
504 private int getSmallIcon(DiskInfo disk, int state) {
505 if (disk.isSd()) {
506 switch (state) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700507 case VolumeInfo.STATE_CHECKING:
508 case VolumeInfo.STATE_EJECTING:
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700509 return R.drawable.ic_sd_card_48dp;
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700510 default:
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700511 return R.drawable.ic_sd_card_48dp;
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700512 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700513 } else if (disk.isUsb()) {
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700514 return R.drawable.ic_usb_48dp;
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700515 } else {
Jeff Sharkeya49d5fc2015-05-13 11:40:30 -0700516 return R.drawable.ic_sd_card_48dp;
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700517 }
518 }
519
520 private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
521 CharSequence text) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700522 return new Notification.Builder(mContext)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700523 .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700524 .setColor(mContext.getColor(R.color.system_notification_accent_color))
525 .setContentTitle(title)
526 .setContentText(text)
527 .setStyle(new Notification.BigTextStyle().bigText(text))
528 .setVisibility(Notification.VISIBILITY_PUBLIC)
529 .setLocalOnly(true);
530 }
531
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700532 private PendingIntent buildInitPendingIntent(DiskInfo disk) {
533 final Intent intent = new Intent();
534 intent.setClassName("com.android.settings",
535 "com.android.settings.deviceinfo.StorageWizardInit");
536 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
537
538 final int requestKey = disk.getId().hashCode();
539 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
540 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
541 }
542
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700543 private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
544 final Intent intent = new Intent();
545 intent.setClassName("com.android.settings",
546 "com.android.settings.deviceinfo.StorageWizardInit");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700547 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
548
549 final int requestKey = vol.getId().hashCode();
550 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
551 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700552 }
553
554 private PendingIntent buildUnmountPendingIntent(VolumeInfo vol) {
555 final Intent intent = new Intent();
556 intent.setClassName("com.android.settings",
557 "com.android.settings.deviceinfo.StorageUnmountReceiver");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700558 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
559
560 final int requestKey = vol.getId().hashCode();
561 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
562 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700563 }
564
565 private PendingIntent buildBrowsePendingIntent(VolumeInfo vol) {
566 final Intent intent = vol.buildBrowseIntent();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700567
568 final int requestKey = vol.getId().hashCode();
569 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
570 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700571 }
572
Jeff Sharkey50a05452015-04-29 11:24:52 -0700573 private PendingIntent buildVolumeSettingsPendingIntent(VolumeInfo vol) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700574 final Intent intent = new Intent();
Jeff Sharkey50a05452015-04-29 11:24:52 -0700575 switch (vol.getType()) {
576 case VolumeInfo.TYPE_PRIVATE:
577 intent.setClassName("com.android.settings",
578 "com.android.settings.Settings$PrivateVolumeSettingsActivity");
579 break;
580 case VolumeInfo.TYPE_PUBLIC:
581 intent.setClassName("com.android.settings",
582 "com.android.settings.Settings$PublicVolumeSettingsActivity");
583 break;
584 default:
585 return null;
586 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700587 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
588
589 final int requestKey = vol.getId().hashCode();
590 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
591 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
592 }
593
594 private PendingIntent buildSnoozeIntent(VolumeInfo vol) {
595 final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700596 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700597
598 final int requestKey = vol.getId().hashCode();
599 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
600 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
San Mehat64e6a452010-02-04 20:53:48 -0800601 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700602
603 private PendingIntent buildForgetPendingIntent(VolumeRecord rec) {
604 final Intent intent = new Intent();
605 intent.setClassName("com.android.settings",
606 "com.android.settings.Settings$PrivateVolumeForgetActivity");
607 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, rec.getFsUuid());
608
609 final int requestKey = rec.getFsUuid().hashCode();
610 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
611 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
612 }
Jeff Sharkey50a05452015-04-29 11:24:52 -0700613
614 private PendingIntent buildWizardMigratePendingIntent(MoveInfo move) {
615 final Intent intent = new Intent();
616 intent.setClassName("com.android.settings",
617 "com.android.settings.deviceinfo.StorageWizardMigrateProgress");
618 intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId);
619
620 final VolumeInfo vol = mStorageManager.findVolumeByQualifiedUuid(move.volumeUuid);
621 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
622
623 return PendingIntent.getActivityAsUser(mContext, move.moveId, intent,
624 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
625 }
626
627 private PendingIntent buildWizardMovePendingIntent(MoveInfo move) {
628 final Intent intent = new Intent();
629 intent.setClassName("com.android.settings",
630 "com.android.settings.deviceinfo.StorageWizardMoveProgress");
631 intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId);
632
633 return PendingIntent.getActivityAsUser(mContext, move.moveId, intent,
634 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
635 }
636
637 private PendingIntent buildWizardReadyPendingIntent(DiskInfo disk) {
638 final Intent intent = new Intent();
639 intent.setClassName("com.android.settings",
640 "com.android.settings.deviceinfo.StorageWizardReady");
641 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
642
643 final int requestKey = disk.getId().hashCode();
644 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
645 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
646 }
San Mehat64e6a452010-02-04 20:53:48 -0800647}