blob: 4a441c7bf3512c531b8c26c1e7c0b75941d4464d [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;
Dianne Hackborn50cdf7c32012-09-23 17:08:57 -070027import android.os.UserHandle;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070028import android.os.storage.DiskInfo;
San Mehatb1043402010-02-05 08:26:50 -080029import android.os.storage.StorageEventListener;
30import android.os.storage.StorageManager;
Jeff Sharkey56bd3122015-04-14 10:30:34 -070031import android.os.storage.VolumeInfo;
John Spurlockcd686b52013-06-05 10:13:46 -040032import android.util.Log;
San Mehat64e6a452010-02-04 20:53:48 -080033
Jeff Sharkey56bd3122015-04-14 10:30:34 -070034import com.android.internal.R;
John Spurlock3e309b22013-06-25 11:01:29 -040035import com.android.systemui.SystemUI;
36
Jeff Sharkey56bd3122015-04-14 10:30:34 -070037import java.util.List;
38
John Spurlock3e309b22013-06-25 11:01:29 -040039public class StorageNotification extends SystemUI {
San Mehat64e6a452010-02-04 20:53:48 -080040 private static final String TAG = "StorageNotification";
41
Jeff Sharkey56bd3122015-04-14 10:30:34 -070042 private static final int NOTIF_ID = 0x53544f52; // STOR
Daniel Sandlerc07907e2010-02-22 15:08:41 -050043
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070044 private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
45
Jeff Sharkey56bd3122015-04-14 10:30:34 -070046 // TODO: delay some notifications to avoid bumpy fast operations
47 // TODO: annoy user when private media is missing
San Mehat64e6a452010-02-04 20:53:48 -080048
Jeff Sharkey56bd3122015-04-14 10:30:34 -070049 private NotificationManager mNotificationManager;
San Mehatb1043402010-02-05 08:26:50 -080050 private StorageManager mStorageManager;
San Mehat64e6a452010-02-04 20:53:48 -080051
Jeff Sharkey56bd3122015-04-14 10:30:34 -070052 private final StorageEventListener mListener = new StorageEventListener() {
53 @Override
54 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
55 onVolumeStateChangedInternal(vol, oldState, newState);
John Spurlock3e309b22013-06-25 11:01:29 -040056 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070057
58 @Override
59 public void onVolumeMetadataChanged(VolumeInfo vol) {
60 // Avoid kicking notifications when getting early metadata before
61 // mounted. If already mounted, we're being kicked because of a
62 // nickname or init'ed change.
63 if (vol.getState() == VolumeInfo.STATE_MOUNTED) {
64 onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
65 }
66 }
67 };
68
69 private final BroadcastReceiver mSnoozeReceiver = new BroadcastReceiver() {
70 @Override
71 public void onReceive(Context context, Intent intent) {
72 // TODO: kick this onto background thread
73 final String volId = intent.getStringExtra(VolumeInfo.EXTRA_VOLUME_ID);
74 mStorageManager.setVolumeSnoozed(volId, true);
75 }
Jeff Sharkey56bd3122015-04-14 10:30:34 -070076 };
San Mehat64e6a452010-02-04 20:53:48 -080077
John Spurlock3e309b22013-06-25 11:01:29 -040078 @Override
79 public void start() {
Jeff Sharkey56bd3122015-04-14 10:30:34 -070080 mNotificationManager = mContext.getSystemService(NotificationManager.class);
John Spurlock3e309b22013-06-25 11:01:29 -040081
Jeff Sharkey56bd3122015-04-14 10:30:34 -070082 mStorageManager = mContext.getSystemService(StorageManager.class);
83 mStorageManager.registerListener(mListener);
Daniel Sandler5b8743f2010-11-03 09:43:46 -040084
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070085 mContext.registerReceiver(mSnoozeReceiver, new IntentFilter(ACTION_SNOOZE_VOLUME),
86 android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
87
Jeff Sharkey56bd3122015-04-14 10:30:34 -070088 // Kick current state into place
89 final List<VolumeInfo> vols = mStorageManager.getVolumes();
90 for (VolumeInfo vol : vols) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070091 onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
San Mehat64e6a452010-02-04 20:53:48 -080092 }
93 }
94
Jeff Sharkey56bd3122015-04-14 10:30:34 -070095 public void onVolumeStateChangedInternal(VolumeInfo vol, int oldState, int newState) {
96 // We only care about public volumes
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070097 if (vol.getType() != VolumeInfo.TYPE_PUBLIC) {
San Mehat64e6a452010-02-04 20:53:48 -080098 return;
99 }
100
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700101 Log.d(TAG, vol.toString());
San Mehat64e6a452010-02-04 20:53:48 -0800102
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700103 // New state means we tear down any old notifications
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700104 mNotificationManager.cancelAsUser(vol.getId(), NOTIF_ID, UserHandle.ALL);
John Spurlock209bede2013-07-17 12:23:27 -0400105
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700106 switch (newState) {
107 case VolumeInfo.STATE_UNMOUNTED:
108 onVolumeUnmounted(vol);
109 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700110 case VolumeInfo.STATE_CHECKING:
111 onVolumeChecking(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700112 break;
113 case VolumeInfo.STATE_MOUNTED:
114 onVolumeMounted(vol);
115 break;
116 case VolumeInfo.STATE_FORMATTING:
117 onVolumeFormatting(vol);
118 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700119 case VolumeInfo.STATE_EJECTING:
120 onVolumeEjecting(vol);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700121 break;
122 case VolumeInfo.STATE_UNMOUNTABLE:
123 onVolumeUnmountable(vol);
124 break;
125 case VolumeInfo.STATE_REMOVED:
126 onVolumeRemoved(vol);
127 break;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700128 case VolumeInfo.STATE_BAD_REMOVAL:
129 onVolumeBadRemoval(vol);
130 break;
San Mehat64e6a452010-02-04 20:53:48 -0800131 }
132 }
133
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700134 private void onVolumeUnmounted(VolumeInfo vol) {
135 // Ignored
San Mehat64e6a452010-02-04 20:53:48 -0800136 }
137
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700138 private void onVolumeChecking(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700139 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700140 final CharSequence title = mContext.getString(
141 R.string.ext_media_checking_notification_title, disk.getDescription());
142 final CharSequence text = mContext.getString(
143 R.string.ext_media_checking_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800144
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700145 final Notification notif = buildNotificationBuilder(title, text)
146 .setSmallIcon(R.drawable.stat_notify_sdcard_prepare)
147 .setCategory(Notification.CATEGORY_PROGRESS)
148 .setPriority(Notification.PRIORITY_LOW)
149 .setOngoing(true)
150 .build();
San Mehat64e6a452010-02-04 20:53:48 -0800151
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700152 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700153 }
San Mehat64e6a452010-02-04 20:53:48 -0800154
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700155 private void onVolumeMounted(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700156 // Don't annoy when user dismissed in past
157 if (vol.isSnoozed()) return;
158
159 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700160 final Notification notif;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700161 if (disk.isAdoptable() && !vol.isInited()) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700162 final CharSequence title = disk.getDescription();
163 final CharSequence text = mContext.getString(
164 R.string.ext_media_new_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800165
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700166 notif = buildNotificationBuilder(title, text)
167 .setSmallIcon(R.drawable.stat_notify_sdcard)
168 .addAction(new Action(0, mContext.getString(R.string.ext_media_init_action),
169 buildInitPendingIntent(vol)))
170 .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
171 buildUnmountPendingIntent(vol)))
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700172 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700173 .setCategory(Notification.CATEGORY_SYSTEM)
174 .build();
John Spurlock209bede2013-07-17 12:23:27 -0400175
San Mehat64e6a452010-02-04 20:53:48 -0800176 } else {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700177 final CharSequence title = disk.getDescription();
178 final CharSequence text = mContext.getString(
179 R.string.ext_media_ready_notification_message, disk.getDescription());
180
181 notif = buildNotificationBuilder(title, text)
182 .setSmallIcon(R.drawable.stat_notify_sdcard)
183 .addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action),
184 buildBrowsePendingIntent(vol)))
185 .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
186 buildUnmountPendingIntent(vol)))
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700187 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700188 .setCategory(Notification.CATEGORY_SYSTEM)
189 .setPriority(Notification.PRIORITY_LOW)
190 .build();
San Mehat64e6a452010-02-04 20:53:48 -0800191 }
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700192
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700193 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700194 }
195
196 private void onVolumeFormatting(VolumeInfo vol) {
197 // Ignored
198 }
199
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700200 private void onVolumeEjecting(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700201 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700202 final CharSequence title = mContext.getString(
203 R.string.ext_media_unmounting_notification_title, disk.getDescription());
204 final CharSequence text = mContext.getString(
205 R.string.ext_media_unmounting_notification_message, disk.getDescription());
206
207 final Notification notif = buildNotificationBuilder(title, text)
208 .setSmallIcon(R.drawable.stat_notify_sdcard_prepare)
209 .setCategory(Notification.CATEGORY_PROGRESS)
210 .setPriority(Notification.PRIORITY_LOW)
211 .setOngoing(true)
212 .build();
213
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700214 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700215 }
216
217 private void onVolumeUnmountable(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700218 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700219 final CharSequence title = mContext.getString(
220 R.string.ext_media_unmountable_notification_title, disk.getDescription());
221 final CharSequence text = mContext.getString(
222 R.string.ext_media_unmountable_notification_message, disk.getDescription());
223
224 final Notification notif = buildNotificationBuilder(title, text)
225 .setSmallIcon(R.drawable.stat_notify_sdcard)
226 .setContentIntent(buildDetailsPendingIntent(vol))
227 .setCategory(Notification.CATEGORY_ERROR)
228 .build();
229
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700230 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700231 }
232
233 private void onVolumeRemoved(VolumeInfo vol) {
234 if (!vol.isPrimary()) {
235 // Ignore non-primary media
236 return;
237 }
238
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700239 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700240 final CharSequence title = mContext.getString(
241 R.string.ext_media_nomedia_notification_title, disk.getDescription());
242 final CharSequence text = mContext.getString(
243 R.string.ext_media_nomedia_notification_message, disk.getDescription());
244
245 final Notification notif = buildNotificationBuilder(title, text)
246 .setSmallIcon(R.drawable.stat_notify_sdcard)
247 .setCategory(Notification.CATEGORY_ERROR)
248 .build();
249
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700250 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700251 }
252
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700253 private void onVolumeBadRemoval(VolumeInfo vol) {
254 if (!vol.isPrimary()) {
255 // Ignore non-primary media
256 return;
257 }
258
259 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
260 final CharSequence title = mContext.getString(
261 R.string.ext_media_badremoval_notification_title, disk.getDescription());
262 final CharSequence text = mContext.getString(
263 R.string.ext_media_badremoval_notification_message, disk.getDescription());
264
265 final Notification notif = buildNotificationBuilder(title, text)
266 .setSmallIcon(R.drawable.stat_notify_sdcard)
267 .setCategory(Notification.CATEGORY_ERROR)
268 .build();
269
270 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
271 }
272
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700273 private Notification.Builder buildNotificationBuilder(CharSequence title, CharSequence text) {
274 return new Notification.Builder(mContext)
275 .setColor(mContext.getColor(R.color.system_notification_accent_color))
276 .setContentTitle(title)
277 .setContentText(text)
278 .setStyle(new Notification.BigTextStyle().bigText(text))
279 .setVisibility(Notification.VISIBILITY_PUBLIC)
280 .setLocalOnly(true);
281 }
282
283 private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
284 final Intent intent = new Intent();
285 intent.setClassName("com.android.settings",
286 "com.android.settings.deviceinfo.StorageWizardInit");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700287 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
288
289 final int requestKey = vol.getId().hashCode();
290 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
291 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700292 }
293
294 private PendingIntent buildUnmountPendingIntent(VolumeInfo vol) {
295 final Intent intent = new Intent();
296 intent.setClassName("com.android.settings",
297 "com.android.settings.deviceinfo.StorageUnmountReceiver");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700298 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
299
300 final int requestKey = vol.getId().hashCode();
301 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
302 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700303 }
304
305 private PendingIntent buildBrowsePendingIntent(VolumeInfo vol) {
306 final Intent intent = vol.buildBrowseIntent();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700307
308 final int requestKey = vol.getId().hashCode();
309 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
310 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700311 }
312
313 private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) {
314 final Intent intent = new Intent();
315 intent.setClassName("com.android.settings",
316 "com.android.settings.Settings$StorageVolumeSettingsActivity");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700317 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
318
319 final int requestKey = vol.getId().hashCode();
320 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
321 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
322 }
323
324 private PendingIntent buildSnoozeIntent(VolumeInfo vol) {
325 final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
326 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
327
328 final int requestKey = vol.getId().hashCode();
329 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
330 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
San Mehat64e6a452010-02-04 20:53:48 -0800331 }
332}