blob: deed8957173dfdab9a51bb71f9a0555849a40af1 [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;
29import android.os.Handler;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070030import android.os.UserHandle;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070031import android.os.storage.DiskInfo;
San Mehatb1043402010-02-05 08:26:50 -080032import android.os.storage.StorageEventListener;
33import android.os.storage.StorageManager;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070034import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070035import android.os.storage.VolumeRecord;
36import android.text.TextUtils;
37import android.text.format.DateUtils;
John Spurlockcd686b52013-06-05 10:13:46 -040038import android.util.Log;
San Mehat64e6a452010-02-04 20:53:48 -080039
Jeff Sharkey56bd3122015-04-14 10:30:34 -070040import com.android.internal.R;
John Spurlock3e309b22013-06-25 11:01:29 -040041import com.android.systemui.SystemUI;
42
Jeff Sharkey56bd3122015-04-14 10:30:34 -070043import java.util.List;
44
John Spurlock3e309b22013-06-25 11:01:29 -040045public class StorageNotification extends SystemUI {
San Mehat64e6a452010-02-04 20:53:48 -080046 private static final String TAG = "StorageNotification";
47
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070048 private static final int PUBLIC_ID = 0x53505542; // SPUB
49 private static final int PRIVATE_ID = 0x53505256; // SPRV
50 private static final int DISK_ID = 0x5344534b; // SDSK
51 private static final int MOVE_ID = 0x534d4f56; // SMOV
Daniel Sandlerc07907e2010-02-22 15:08:41 -050052
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070053 private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
54
Jeff Sharkey56bd3122015-04-14 10:30:34 -070055 // TODO: delay some notifications to avoid bumpy fast operations
San Mehat64e6a452010-02-04 20:53:48 -080056
Jeff Sharkey56bd3122015-04-14 10:30:34 -070057 private NotificationManager mNotificationManager;
San Mehatb1043402010-02-05 08:26:50 -080058 private StorageManager mStorageManager;
San Mehat64e6a452010-02-04 20:53:48 -080059
Jeff Sharkey56bd3122015-04-14 10:30:34 -070060 private final StorageEventListener mListener = new StorageEventListener() {
61 @Override
62 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070063 onVolumeStateChangedInternal(vol);
John Spurlock3e309b22013-06-25 11:01:29 -040064 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070065
66 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070067 public void onVolumeMetadataChanged(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070068 // Avoid kicking notifications when getting early metadata before
69 // mounted. If already mounted, we're being kicked because of a
70 // nickname or init'ed change.
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070071 final VolumeInfo vol = mStorageManager.findVolumeByUuid(fsUuid);
72 if (vol != null && vol.isMountedReadable()) {
73 onVolumeStateChangedInternal(vol);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070074 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070075
76 final VolumeRecord rec = mStorageManager.findRecordByUuid(fsUuid);
77 if (rec == null) {
78 // Private volume was probably just forgotten
79 mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
80 }
81 }
82
83 @Override
84 public void onDiskScanned(DiskInfo disk, int volumeCount) {
85 onDiskScannedInternal(disk, volumeCount);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070086 }
87 };
88
89 private final BroadcastReceiver mSnoozeReceiver = new BroadcastReceiver() {
90 @Override
91 public void onReceive(Context context, Intent intent) {
92 // TODO: kick this onto background thread
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070093 final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID);
94 mStorageManager.setVolumeSnoozed(fsUuid, true);
95 }
96 };
97
98 private final MoveCallback mMoveCallback = new MoveCallback() {
99 @Override
100 public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) {
101 if (PackageManager.isMoveStatusFinished(status)) {
102 onMoveFinished(moveId, moveTitle, status);
103 } else {
104 onMoveProgress(moveId, moveTitle, status, estMillis);
105 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700106 }
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700107 };
San Mehat64e6a452010-02-04 20:53:48 -0800108
John Spurlock3e309b22013-06-25 11:01:29 -0400109 @Override
110 public void start() {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700111 mNotificationManager = mContext.getSystemService(NotificationManager.class);
John Spurlock3e309b22013-06-25 11:01:29 -0400112
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700113 mStorageManager = mContext.getSystemService(StorageManager.class);
114 mStorageManager.registerListener(mListener);
Daniel Sandler5b8743f2010-11-03 09:43:46 -0400115
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700116 mContext.registerReceiver(mSnoozeReceiver, new IntentFilter(ACTION_SNOOZE_VOLUME),
117 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
118
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700119 // Kick current state into place
120 final List<VolumeInfo> vols = mStorageManager.getVolumes();
121 for (VolumeInfo vol : vols) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700122 onVolumeStateChangedInternal(vol);
123 }
124
125 mContext.getPackageManager().registerMoveCallback(mMoveCallback, new Handler());
126
127 updateMissingPrivateVolumes();
128 }
129
130 private void updateMissingPrivateVolumes() {
131 final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
132 for (VolumeRecord rec : recs) {
133 if (rec.getType() != VolumeInfo.TYPE_PRIVATE) continue;
134
135 final String fsUuid = rec.getFsUuid();
136 final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
137 if (info != null && info.isMountedWritable()) {
138 // Yay, private volume is here!
139 mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
140
141 } else {
142 // Boo, annoy the user to reinsert the private volume
143 final CharSequence title = mContext.getString(R.string.ext_media_missing_title,
144 rec.getNickname());
145 final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
146
147 final Notification notif = new Notification.Builder(mContext)
148 .setSmallIcon(R.drawable.stat_notify_sdcard)
149 .setColor(mContext.getColor(R.color.system_notification_accent_color))
150 .setContentTitle(title)
151 .setContentText(text)
152 .setStyle(new Notification.BigTextStyle().bigText(text))
153 .setVisibility(Notification.VISIBILITY_PUBLIC)
154 .setLocalOnly(true)
155 .setContentIntent(buildForgetPendingIntent(rec))
156 .setCategory(Notification.CATEGORY_SYSTEM)
157 .setOngoing(true)
158 .build();
159
160 mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, notif, UserHandle.ALL);
161 }
San Mehat64e6a452010-02-04 20:53:48 -0800162 }
163 }
164
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700165 private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
166 if (volumeCount == 0) {
167 // No supported volumes found, give user option to format
168 final CharSequence title = mContext.getString(
169 R.string.ext_media_unmountable_notification_title, disk.getDescription());
170 final CharSequence text = mContext.getString(
171 R.string.ext_media_unmountable_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800172
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700173 final Notification notif = new Notification.Builder(mContext)
174 .setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
175 .setColor(mContext.getColor(R.color.system_notification_accent_color))
176 .setContentTitle(title)
177 .setContentText(text)
178 .setStyle(new Notification.BigTextStyle().bigText(text))
179 .setVisibility(Notification.VISIBILITY_PUBLIC)
180 .setLocalOnly(true)
181 .setContentIntent(buildInitPendingIntent(disk))
182 .setCategory(Notification.CATEGORY_ERROR)
183 .build();
184
185 mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, notif, UserHandle.ALL);
186
187 } else {
188 // Yay, we have volumes!
189 mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
190 }
191 }
192
193 private void onVolumeStateChangedInternal(VolumeInfo vol) {
194 switch (vol.getType()) {
195 case VolumeInfo.TYPE_PRIVATE:
196 onPrivateVolumeStateChangedInternal(vol);
197 break;
198 case VolumeInfo.TYPE_PUBLIC:
199 onPublicVolumeStateChangedInternal(vol);
200 break;
201 }
202 }
203
204 private void onPrivateVolumeStateChangedInternal(VolumeInfo vol) {
205 Log.d(TAG, "Notifying about private volume: " + vol.toString());
206
207 updateMissingPrivateVolumes();
208 }
209
210 private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
211 Log.d(TAG, "Notifying about public volume: " + vol.toString());
San Mehat64e6a452010-02-04 20:53:48 -0800212
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700213 final Notification notif;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700214 switch (vol.getState()) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700215 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700216 notif = onVolumeUnmounted(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700217 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700218 case VolumeInfo.STATE_CHECKING:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700219 notif = onVolumeChecking(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700220 break;
221 case VolumeInfo.STATE_MOUNTED:
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700222 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700223 notif = onVolumeMounted(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700224 break;
225 case VolumeInfo.STATE_FORMATTING:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700226 notif = onVolumeFormatting(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700227 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700228 case VolumeInfo.STATE_EJECTING:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700229 notif = onVolumeEjecting(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700230 break;
231 case VolumeInfo.STATE_UNMOUNTABLE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700232 notif = onVolumeUnmountable(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700233 break;
234 case VolumeInfo.STATE_REMOVED:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700235 notif = onVolumeRemoved(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700236 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700237 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700238 notif = onVolumeBadRemoval(vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700239 break;
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700240 default:
241 notif = null;
242 break;
243 }
244
245 if (notif != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700246 mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700247 } else {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700248 mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
San Mehat64e6a452010-02-04 20:53:48 -0800249 }
250 }
251
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700252 private Notification onVolumeUnmounted(VolumeInfo vol) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700253 // Ignored
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700254 return null;
San Mehat64e6a452010-02-04 20:53:48 -0800255 }
256
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700257 private Notification onVolumeChecking(VolumeInfo vol) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700258 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700259 final CharSequence title = mContext.getString(
260 R.string.ext_media_checking_notification_title, disk.getDescription());
261 final CharSequence text = mContext.getString(
262 R.string.ext_media_checking_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800263
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700264 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700265 .setCategory(Notification.CATEGORY_PROGRESS)
266 .setPriority(Notification.PRIORITY_LOW)
267 .setOngoing(true)
268 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700269 }
San Mehat64e6a452010-02-04 20:53:48 -0800270
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700271 private Notification onVolumeMounted(VolumeInfo vol) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700272 final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid());
273
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700274 // Don't annoy when user dismissed in past
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700275 if (rec.isSnoozed()) return null;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700276
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700277 final DiskInfo disk = vol.getDisk();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700278 if (disk.isAdoptable() && !rec.isInited()) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700279 final CharSequence title = disk.getDescription();
280 final CharSequence text = mContext.getString(
281 R.string.ext_media_new_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800282
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700283 final PendingIntent initAction = buildInitPendingIntent(vol);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700284 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700285 .addAction(new Action(0, mContext.getString(R.string.ext_media_init_action),
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700286 initAction))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700287 .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
288 buildUnmountPendingIntent(vol)))
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700289 .setContentIntent(initAction)
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700290 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700291 .setCategory(Notification.CATEGORY_SYSTEM)
292 .build();
John Spurlock209bede2013-07-17 12:23:27 -0400293
San Mehat64e6a452010-02-04 20:53:48 -0800294 } else {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700295 final CharSequence title = disk.getDescription();
296 final CharSequence text = mContext.getString(
297 R.string.ext_media_ready_notification_message, disk.getDescription());
298
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700299 final PendingIntent browseAction = buildBrowsePendingIntent(vol);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700300 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700301 .addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action),
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700302 browseAction))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700303 .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
304 buildUnmountPendingIntent(vol)))
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700305 .setContentIntent(browseAction)
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700306 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700307 .setCategory(Notification.CATEGORY_SYSTEM)
308 .setPriority(Notification.PRIORITY_LOW)
309 .build();
San Mehat64e6a452010-02-04 20:53:48 -0800310 }
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700311 }
312
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700313 private Notification onVolumeFormatting(VolumeInfo vol) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700314 // Ignored
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700315 return null;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700316 }
317
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700318 private Notification onVolumeEjecting(VolumeInfo vol) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700319 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700320 final CharSequence title = mContext.getString(
321 R.string.ext_media_unmounting_notification_title, disk.getDescription());
322 final CharSequence text = mContext.getString(
323 R.string.ext_media_unmounting_notification_message, disk.getDescription());
324
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700325 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700326 .setCategory(Notification.CATEGORY_PROGRESS)
327 .setPriority(Notification.PRIORITY_LOW)
328 .setOngoing(true)
329 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700330 }
331
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700332 private Notification onVolumeUnmountable(VolumeInfo vol) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700333 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700334 final CharSequence title = mContext.getString(
335 R.string.ext_media_unmountable_notification_title, disk.getDescription());
336 final CharSequence text = mContext.getString(
337 R.string.ext_media_unmountable_notification_message, disk.getDescription());
338
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700339 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700340 .setContentIntent(buildDetailsPendingIntent(vol))
341 .setCategory(Notification.CATEGORY_ERROR)
342 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700343 }
344
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700345 private Notification onVolumeRemoved(VolumeInfo vol) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700346 if (!vol.isPrimary()) {
347 // Ignore non-primary media
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700348 return null;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700349 }
350
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700351 final DiskInfo disk = vol.getDisk();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700352 final CharSequence title = mContext.getString(
353 R.string.ext_media_nomedia_notification_title, disk.getDescription());
354 final CharSequence text = mContext.getString(
355 R.string.ext_media_nomedia_notification_message, disk.getDescription());
356
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700357 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700358 .setCategory(Notification.CATEGORY_ERROR)
359 .build();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700360 }
361
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700362 private Notification onVolumeBadRemoval(VolumeInfo vol) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700363 if (!vol.isPrimary()) {
364 // Ignore non-primary media
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700365 return null;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700366 }
367
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700368 final DiskInfo disk = vol.getDisk();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700369 final CharSequence title = mContext.getString(
370 R.string.ext_media_badremoval_notification_title, disk.getDescription());
371 final CharSequence text = mContext.getString(
372 R.string.ext_media_badremoval_notification_message, disk.getDescription());
373
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700374 return buildNotificationBuilder(vol, title, text)
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700375 .setCategory(Notification.CATEGORY_ERROR)
376 .build();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700377 }
378
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700379 private void onMoveProgress(int moveId, String moveTitle, int status, long estMillis) {
380 final CharSequence title;
381 if (!TextUtils.isEmpty(moveTitle)) {
382 title = mContext.getString(R.string.ext_media_move_specific_title, moveTitle);
383 } else {
384 title = mContext.getString(R.string.ext_media_move_title);
385 }
386
387 final CharSequence text;
388 if (estMillis < 0) {
389 text = null;
390 } else {
391 text = DateUtils.formatDuration(estMillis);
392 }
393
394 final Notification notif = new Notification.Builder(mContext)
395 .setSmallIcon(R.drawable.stat_notify_sdcard)
396 .setColor(mContext.getColor(R.color.system_notification_accent_color))
397 .setContentTitle(title)
398 .setContentText(text)
399 .setStyle(new Notification.BigTextStyle().bigText(text))
400 .setVisibility(Notification.VISIBILITY_PUBLIC)
401 .setLocalOnly(true)
402 .setCategory(Notification.CATEGORY_PROGRESS)
403 .setPriority(Notification.PRIORITY_LOW)
404 .setProgress(100, status, false)
405 .setOngoing(true)
406 .build();
407
408 mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL);
409 }
410
411 private void onMoveFinished(int moveId, String moveTitle, int status) {
412 if (!TextUtils.isEmpty(moveTitle)) {
413 // We currently ignore finished app moves; just clear the last
414 // published progress
415 mNotificationManager.cancelAsUser(moveTitle, MOVE_ID, UserHandle.ALL);
416 return;
417 }
418
419 final VolumeInfo vol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
420 final String descrip = mStorageManager.getBestVolumeDescription(vol);
421
422 final CharSequence title;
423 final CharSequence text;
424 if (status == PackageManager.MOVE_SUCCEEDED) {
425 title = mContext.getString(R.string.ext_media_move_success_title);
426 text = mContext.getString(R.string.ext_media_move_success_message, descrip);
427 } else {
428 title = mContext.getString(R.string.ext_media_move_failure_title);
429 text = mContext.getString(R.string.ext_media_move_failure_message);
430 }
431
432 final Notification notif = new Notification.Builder(mContext)
433 .setSmallIcon(R.drawable.stat_notify_sdcard)
434 .setColor(mContext.getColor(R.color.system_notification_accent_color))
435 .setContentTitle(title)
436 .setContentText(text)
437 .setStyle(new Notification.BigTextStyle().bigText(text))
438 .setVisibility(Notification.VISIBILITY_PUBLIC)
439 .setLocalOnly(true)
440 .setCategory(Notification.CATEGORY_SYSTEM)
441 .setPriority(Notification.PRIORITY_LOW)
442 .build();
443
444 mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL);
445 }
446
447 private int getSmallIcon(DiskInfo disk, int state) {
448 if (disk.isSd()) {
449 switch (state) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700450 case VolumeInfo.STATE_CHECKING:
451 case VolumeInfo.STATE_EJECTING:
452 return R.drawable.stat_notify_sdcard_prepare;
453 default:
454 return R.drawable.stat_notify_sdcard;
455 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700456 } else if (disk.isUsb()) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -0700457 return R.drawable.stat_sys_data_usb;
458 } else {
459 return R.drawable.stat_notify_sdcard;
460 }
461 }
462
463 private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
464 CharSequence text) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700465 return new Notification.Builder(mContext)
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700466 .setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700467 .setColor(mContext.getColor(R.color.system_notification_accent_color))
468 .setContentTitle(title)
469 .setContentText(text)
470 .setStyle(new Notification.BigTextStyle().bigText(text))
471 .setVisibility(Notification.VISIBILITY_PUBLIC)
472 .setLocalOnly(true);
473 }
474
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700475 private PendingIntent buildInitPendingIntent(DiskInfo disk) {
476 final Intent intent = new Intent();
477 intent.setClassName("com.android.settings",
478 "com.android.settings.deviceinfo.StorageWizardInit");
479 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
480
481 final int requestKey = disk.getId().hashCode();
482 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
483 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
484 }
485
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700486 private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
487 final Intent intent = new Intent();
488 intent.setClassName("com.android.settings",
489 "com.android.settings.deviceinfo.StorageWizardInit");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700490 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
491
492 final int requestKey = vol.getId().hashCode();
493 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
494 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700495 }
496
497 private PendingIntent buildUnmountPendingIntent(VolumeInfo vol) {
498 final Intent intent = new Intent();
499 intent.setClassName("com.android.settings",
500 "com.android.settings.deviceinfo.StorageUnmountReceiver");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700501 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
502
503 final int requestKey = vol.getId().hashCode();
504 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
505 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700506 }
507
508 private PendingIntent buildBrowsePendingIntent(VolumeInfo vol) {
509 final Intent intent = vol.buildBrowseIntent();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700510
511 final int requestKey = vol.getId().hashCode();
512 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
513 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700514 }
515
516 private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) {
517 final Intent intent = new Intent();
518 intent.setClassName("com.android.settings",
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700519 "com.android.settings.Settings$PublicVolumeSettingsActivity");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700520 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
521
522 final int requestKey = vol.getId().hashCode();
523 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
524 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
525 }
526
527 private PendingIntent buildSnoozeIntent(VolumeInfo vol) {
528 final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700529 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700530
531 final int requestKey = vol.getId().hashCode();
532 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
533 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
San Mehat64e6a452010-02-04 20:53:48 -0800534 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700535
536 private PendingIntent buildForgetPendingIntent(VolumeRecord rec) {
537 final Intent intent = new Intent();
538 intent.setClassName("com.android.settings",
539 "com.android.settings.Settings$PrivateVolumeForgetActivity");
540 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, rec.getFsUuid());
541
542 final int requestKey = rec.getFsUuid().hashCode();
543 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
544 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
545 }
San Mehat64e6a452010-02-04 20:53:48 -0800546}