blob: 818f5ee6f9851269de72f034d4388ab4888f393c [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;
110 case VolumeInfo.STATE_MOUNTING:
111 onVolumeMounting(vol);
112 break;
113 case VolumeInfo.STATE_MOUNTED:
114 onVolumeMounted(vol);
115 break;
116 case VolumeInfo.STATE_FORMATTING:
117 onVolumeFormatting(vol);
118 break;
119 case VolumeInfo.STATE_UNMOUNTING:
120 onVolumeUnmounting(vol);
121 break;
122 case VolumeInfo.STATE_UNMOUNTABLE:
123 onVolumeUnmountable(vol);
124 break;
125 case VolumeInfo.STATE_REMOVED:
126 onVolumeRemoved(vol);
127 break;
San Mehat64e6a452010-02-04 20:53:48 -0800128 }
129 }
130
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700131 private void onVolumeUnmounted(VolumeInfo vol) {
132 // Ignored
San Mehat64e6a452010-02-04 20:53:48 -0800133 }
134
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700135 private void onVolumeMounting(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700136 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700137 final CharSequence title = mContext.getString(
138 R.string.ext_media_checking_notification_title, disk.getDescription());
139 final CharSequence text = mContext.getString(
140 R.string.ext_media_checking_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800141
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700142 final Notification notif = buildNotificationBuilder(title, text)
143 .setSmallIcon(R.drawable.stat_notify_sdcard_prepare)
144 .setCategory(Notification.CATEGORY_PROGRESS)
145 .setPriority(Notification.PRIORITY_LOW)
146 .setOngoing(true)
147 .build();
San Mehat64e6a452010-02-04 20:53:48 -0800148
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700149 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700150 }
San Mehat64e6a452010-02-04 20:53:48 -0800151
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700152 private void onVolumeMounted(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700153 // Don't annoy when user dismissed in past
154 if (vol.isSnoozed()) return;
155
156 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700157 final Notification notif;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700158 if (disk.isAdoptable() && !vol.isInited()) {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700159 final CharSequence title = disk.getDescription();
160 final CharSequence text = mContext.getString(
161 R.string.ext_media_new_notification_message, disk.getDescription());
San Mehat64e6a452010-02-04 20:53:48 -0800162
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700163 notif = buildNotificationBuilder(title, text)
164 .setSmallIcon(R.drawable.stat_notify_sdcard)
165 .addAction(new Action(0, mContext.getString(R.string.ext_media_init_action),
166 buildInitPendingIntent(vol)))
167 .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
168 buildUnmountPendingIntent(vol)))
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700169 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700170 .setCategory(Notification.CATEGORY_SYSTEM)
171 .build();
John Spurlock209bede2013-07-17 12:23:27 -0400172
San Mehat64e6a452010-02-04 20:53:48 -0800173 } else {
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700174 final CharSequence title = disk.getDescription();
175 final CharSequence text = mContext.getString(
176 R.string.ext_media_ready_notification_message, disk.getDescription());
177
178 notif = buildNotificationBuilder(title, text)
179 .setSmallIcon(R.drawable.stat_notify_sdcard)
180 .addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action),
181 buildBrowsePendingIntent(vol)))
182 .addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
183 buildUnmountPendingIntent(vol)))
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700184 .setDeleteIntent(buildSnoozeIntent(vol))
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700185 .setCategory(Notification.CATEGORY_SYSTEM)
186 .setPriority(Notification.PRIORITY_LOW)
187 .build();
San Mehat64e6a452010-02-04 20:53:48 -0800188 }
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700189
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700190 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700191 }
192
193 private void onVolumeFormatting(VolumeInfo vol) {
194 // Ignored
195 }
196
197 private void onVolumeUnmounting(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700198 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700199 final CharSequence title = mContext.getString(
200 R.string.ext_media_unmounting_notification_title, disk.getDescription());
201 final CharSequence text = mContext.getString(
202 R.string.ext_media_unmounting_notification_message, disk.getDescription());
203
204 final Notification notif = buildNotificationBuilder(title, text)
205 .setSmallIcon(R.drawable.stat_notify_sdcard_prepare)
206 .setCategory(Notification.CATEGORY_PROGRESS)
207 .setPriority(Notification.PRIORITY_LOW)
208 .setOngoing(true)
209 .build();
210
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700211 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700212 }
213
214 private void onVolumeUnmountable(VolumeInfo vol) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700215 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700216 final CharSequence title = mContext.getString(
217 R.string.ext_media_unmountable_notification_title, disk.getDescription());
218 final CharSequence text = mContext.getString(
219 R.string.ext_media_unmountable_notification_message, disk.getDescription());
220
221 final Notification notif = buildNotificationBuilder(title, text)
222 .setSmallIcon(R.drawable.stat_notify_sdcard)
223 .setContentIntent(buildDetailsPendingIntent(vol))
224 .setCategory(Notification.CATEGORY_ERROR)
225 .build();
226
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700227 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700228 }
229
230 private void onVolumeRemoved(VolumeInfo vol) {
231 if (!vol.isPrimary()) {
232 // Ignore non-primary media
233 return;
234 }
235
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700236 final DiskInfo disk = mStorageManager.findDiskById(vol.getDiskId());
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700237 final CharSequence title = mContext.getString(
238 R.string.ext_media_nomedia_notification_title, disk.getDescription());
239 final CharSequence text = mContext.getString(
240 R.string.ext_media_nomedia_notification_message, disk.getDescription());
241
242 final Notification notif = buildNotificationBuilder(title, text)
243 .setSmallIcon(R.drawable.stat_notify_sdcard)
244 .setCategory(Notification.CATEGORY_ERROR)
245 .build();
246
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700247 mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700248 }
249
250 private Notification.Builder buildNotificationBuilder(CharSequence title, CharSequence text) {
251 return new Notification.Builder(mContext)
252 .setColor(mContext.getColor(R.color.system_notification_accent_color))
253 .setContentTitle(title)
254 .setContentText(text)
255 .setStyle(new Notification.BigTextStyle().bigText(text))
256 .setVisibility(Notification.VISIBILITY_PUBLIC)
257 .setLocalOnly(true);
258 }
259
260 private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
261 final Intent intent = new Intent();
262 intent.setClassName("com.android.settings",
263 "com.android.settings.deviceinfo.StorageWizardInit");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700264 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
265
266 final int requestKey = vol.getId().hashCode();
267 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
268 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700269 }
270
271 private PendingIntent buildUnmountPendingIntent(VolumeInfo vol) {
272 final Intent intent = new Intent();
273 intent.setClassName("com.android.settings",
274 "com.android.settings.deviceinfo.StorageUnmountReceiver");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700275 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
276
277 final int requestKey = vol.getId().hashCode();
278 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
279 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700280 }
281
282 private PendingIntent buildBrowsePendingIntent(VolumeInfo vol) {
283 final Intent intent = vol.buildBrowseIntent();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700284
285 final int requestKey = vol.getId().hashCode();
286 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
287 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700288 }
289
290 private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) {
291 final Intent intent = new Intent();
292 intent.setClassName("com.android.settings",
293 "com.android.settings.Settings$StorageVolumeSettingsActivity");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700294 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
295
296 final int requestKey = vol.getId().hashCode();
297 return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
298 PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
299 }
300
301 private PendingIntent buildSnoozeIntent(VolumeInfo vol) {
302 final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
303 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
304
305 final int requestKey = vol.getId().hashCode();
306 return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
307 PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
San Mehat64e6a452010-02-04 20:53:48 -0800308 }
309}