164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat/*
264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * Copyright (C) 2010 Google Inc.
364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat *
464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * you may not use this file except in compliance with the License.
664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * You may obtain a copy of the License at
764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat *
864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat *
1064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * Unless required by applicable law or agreed to in writing, software
1164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
1264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * See the License for the specific language governing permissions and
1464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat * limitations under the License.
1564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat */
1664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
17fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onoratopackage com.android.systemui.usb;
1864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
1964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehatimport android.app.Notification;
2064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehatimport android.app.NotificationManager;
2164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehatimport android.app.PendingIntent;
2264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehatimport android.content.Context;
2364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehatimport android.content.Intent;
2464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehatimport android.content.res.Resources;
2564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehatimport android.os.Environment;
265b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandlerimport android.os.Handler;
275b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandlerimport android.os.HandlerThread;
28b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.StorageEventListener;
29b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.StorageManager;
30c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandlerimport android.provider.Settings;
318a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
3264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
33b104340496e3a531e26c8f428c808eca0e039f50San Mehatpublic class StorageNotification extends StorageEventListener {
3464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private static final String TAG = "StorageNotification";
3564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler    private static final boolean POP_UMS_ACTIVITY_ON_CONNECT = true;
37c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler
3864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
3964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Binder context for this service
4064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
4164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private Context mContext;
4264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
4364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
4464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * The notification that is shown when a USB mass storage host
4564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * is connected.
4664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * <p>
4764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * This is lazily created, so use {@link #setUsbStorageNotification()}.
4864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
4964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private Notification mUsbStorageNotification;
5064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
5164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
5264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * The notification that is shown when the following media events occur:
5364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is being checked
5464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is blank (or unknown filesystem)
5564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is corrupt
5664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is safe to unmount
5764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is missing
5864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * <p>
5964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * This is lazily created, so use {@link #setMediaStorageNotification()}.
6064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
61b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private Notification   mMediaStorageNotification;
62b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean        mUmsAvailable;
63b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private StorageManager mStorageManager;
6464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
655b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private Handler        mAsyncEventHandler;
665b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
6764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    public StorageNotification(Context context) {
6864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        mContext = context;
6964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
70b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
71fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato        final boolean connected = mStorageManager.isUsbMassStorageConnected();
728a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.d(TAG, String.format( "Startup with UMS connection %s (media state %s)", mUmsAvailable,
73b104340496e3a531e26c8f428c808eca0e039f50San Mehat                Environment.getExternalStorageState()));
745b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
755b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        HandlerThread thr = new HandlerThread("SystemUI StorageNotification");
765b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        thr.start();
775b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        mAsyncEventHandler = new Handler(thr.getLooper());
785b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
79fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato        onUsbMassStorageConnectionChanged(connected);
8064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
8164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
82b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
83b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @override com.android.os.storage.StorageEventListener
84b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
85b104340496e3a531e26c8f428c808eca0e039f50San Mehat    @Override
865b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    public void onUsbMassStorageConnectionChanged(final boolean connected) {
875b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        mAsyncEventHandler.post(new Runnable() {
885b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            @Override
895b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            public void run() {
905b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler                onUsbMassStorageConnectionChangedAsync(connected);
915b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            }
925b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        });
935b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    }
945b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
955b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private void onUsbMassStorageConnectionChangedAsync(boolean connected) {
96b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mUmsAvailable = connected;
9764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        /*
98b104340496e3a531e26c8f428c808eca0e039f50San Mehat         * Even though we may have a UMS host connected, we the SD card
99b104340496e3a531e26c8f428c808eca0e039f50San Mehat         * may not be in a state for export.
10064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat         */
101b104340496e3a531e26c8f428c808eca0e039f50San Mehat        String st = Environment.getExternalStorageState();
10264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
1038a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.i(TAG, String.format("UMS connection changed to %s (media state %s)", connected, st));
104b104340496e3a531e26c8f428c808eca0e039f50San Mehat
105b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (connected && (st.equals(
106b104340496e3a531e26c8f428c808eca0e039f50San Mehat                Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) {
107b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
108b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * No card or card being checked = don't display
109b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
110b104340496e3a531e26c8f428c808eca0e039f50San Mehat            connected = false;
11164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
112b104340496e3a531e26c8f428c808eca0e039f50San Mehat        updateUsbMassStorageNotification(connected);
11364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
11464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
115b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
116b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @override com.android.os.storage.StorageEventListener
117b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
118b104340496e3a531e26c8f428c808eca0e039f50San Mehat    @Override
1195b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    public void onStorageStateChanged(final String path, final String oldState, final String newState) {
1205b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        mAsyncEventHandler.post(new Runnable() {
1215b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            @Override
1225b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            public void run() {
1235b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler                onStorageStateChangedAsync(path, oldState, newState);
1245b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            }
1255b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        });
1265b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    }
1275b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
1285b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private void onStorageStateChangedAsync(String path, String oldState, String newState) {
1298a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.i(TAG, String.format(
130b104340496e3a531e26c8f428c808eca0e039f50San Mehat                "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));
13164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (newState.equals(Environment.MEDIA_SHARED)) {
132b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
133b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now shared. Modify the UMS notification
134b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * for stopping UMS.
135b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
13664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
137fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
13864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
13964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(
14064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_stop_notification_title,
14164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_stop_notification_message,
14264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_sys_warning, false, true, pi);
14364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_CHECKING)) {
144b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
145b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now checking. Update media notification and disable
146b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * UMS notification.
147b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
14864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
14964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_checking_notification_title,
15064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_checking_notification_message,
15164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_prepare, true, false, null);
15264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(false);
15364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_MOUNTED)) {
154b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
155b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now mounted. Dismiss any media notifications,
156b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
157b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
15864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(0, 0, 0, false, false, null);
15964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
16064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_UNMOUNTED)) {
161b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
162b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now unmounted. We may have been unmounted
163b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * because the user is enabling/disabling UMS, in which case we don't
164b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * want to display the 'safe to unmount' notification.
165b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
166b104340496e3a531e26c8f428c808eca0e039f50San Mehat            if (!mStorageManager.isUsbMassStorageEnabled()) {
167b104340496e3a531e26c8f428c808eca0e039f50San Mehat                if (oldState.equals(Environment.MEDIA_SHARED)) {
168b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    /*
169b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * The unmount was due to UMS being enabled. Dismiss any
170b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * media notifications, and enable UMS notification if connected
171b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     */
172b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    setMediaStorageNotification(0, 0, 0, false, false, null);
173b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    updateUsbMassStorageNotification(mUmsAvailable);
174b104340496e3a531e26c8f428c808eca0e039f50San Mehat                } else {
175b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    /*
176b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * Show safe to unmount media notification, and enable UMS
177b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * notification if connected.
178b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     */
179d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    if (Environment.isExternalStorageRemovable()) {
180d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        setMediaStorageNotification(
181d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.string.ext_media_safe_unmount_notification_title,
182d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.string.ext_media_safe_unmount_notification_message,
183d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.drawable.stat_notify_sdcard, true, true, null);
184d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    } else {
185d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        // This device does not have removable storage, so
186d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        // don't tell the user they can remove it.
187d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        setMediaStorageNotification(0, 0, 0, false, false, null);
188d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    }
189b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    updateUsbMassStorageNotification(mUmsAvailable);
190b104340496e3a531e26c8f428c808eca0e039f50San Mehat                }
19164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
192b104340496e3a531e26c8f428c808eca0e039f50San Mehat                /*
193b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 * The unmount was due to UMS being enabled. Dismiss any
194b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 * media notifications, and disable the UMS notification
195b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 */
19664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                setMediaStorageNotification(0, 0, 0, false, false, null);
197b104340496e3a531e26c8f428c808eca0e039f50San Mehat                updateUsbMassStorageNotification(false);
19864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
19964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_NOFS)) {
200b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
201b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has no filesystem. Show blank media notification,
202b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
203b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
20464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
20564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
20664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
20764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
20864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
20964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_nofs_notification_title,
21064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_nofs_notification_message,
21164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
21264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
21364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_UNMOUNTABLE)) {
214b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
215b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is corrupt. Show corrupt media notification,
216b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
217b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
21864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
21964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
22064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
22164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
22264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
22364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_unmountable_notification_title,
22464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_unmountable_notification_message,
22564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
22664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
227b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else if (newState.equals(Environment.MEDIA_REMOVED)) {
228b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
229b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has been removed. Show nomedia media notification,
230b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and disable UMS notification regardless of connection state.
231b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
232b104340496e3a531e26c8f428c808eca0e039f50San Mehat            setMediaStorageNotification(
233b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_nomedia_notification_title,
234b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_nomedia_notification_message,
235b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
236b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    true, false, null);
237b104340496e3a531e26c8f428c808eca0e039f50San Mehat            updateUsbMassStorageNotification(false);
238b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else if (newState.equals(Environment.MEDIA_BAD_REMOVAL)) {
239b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
240b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has been removed unsafely. Show bad removal media notification,
241b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and disable UMS notification regardless of connection state.
242b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
243b104340496e3a531e26c8f428c808eca0e039f50San Mehat            setMediaStorageNotification(
244b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_badremoval_notification_title,
245b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_badremoval_notification_message,
246b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.drawable.stat_sys_warning,
247b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    true, true, null);
248b104340496e3a531e26c8f428c808eca0e039f50San Mehat            updateUsbMassStorageNotification(false);
249b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else {
2508a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            Slog.w(TAG, String.format("Ignoring unknown state {%s}", newState));
25164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
25264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
25364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
25464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
25564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Update the state of the USB mass storage notification
25664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
25764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    void updateUsbMassStorageNotification(boolean available) {
25864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
25964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (available) {
26064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
261fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
26264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
263c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler
26464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
26564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(
26664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_notification_title,
26764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_notification_message,
26864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_sys_data_usb,
26964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    false, true, pi);
27064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
27164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(0, 0, 0, false, false, null);
27264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
27364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
27464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
27564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
27664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Sets the USB storage notification.
27764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
2784154c07c5cabc74029a2df379075391d782a682cSan Mehat    private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon,
2794154c07c5cabc74029a2df379075391d782a682cSan Mehat            boolean sound, boolean visible, PendingIntent pi) {
28064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (!visible && mUsbStorageNotification == null) {
28264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
28364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
28464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        NotificationManager notificationManager = (NotificationManager) mContext
28664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                .getSystemService(Context.NOTIFICATION_SERVICE);
28764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (notificationManager == null) {
28964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
29064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
29164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
29264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
29364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Resources r = Resources.getSystem();
29464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence title = r.getText(titleId);
29564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence message = r.getText(messageId);
29664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
29764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (mUsbStorageNotification == null) {
29864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification = new Notification();
29964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.icon = icon;
30064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.when = 0;
30164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
30264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
30364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (sound) {
30464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
30564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
30664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
30764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
30864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
30964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
31064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
31164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.tickerText = title;
31264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (pi == null) {
31364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                Intent intent = new Intent();
31464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
31564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
31664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
31764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
318f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler            final boolean adbOn = 1 == Settings.Secure.getInt(
319f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                mContext.getContentResolver(),
320f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                Settings.Secure.ADB_ENABLED,
321f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                0);
322f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler
323f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
324f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // Pop up a full-screen alert to coach the user through enabling UMS. The average
325f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // user has attached the device to USB either to charge the phone (in which case
326f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // this is harmless) or transfer files, and in the latter case this alert saves
327f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // several steps (as well as subtly indicates that you shouldn't mix UMS with other
328f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // activities on the device).
329f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                //
330f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // If ADB is enabled, however, we suppress this dialog (under the assumption that a
331f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // developer (a) knows how to enable UMS, and (b) is probably using USB to install
332f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // builds or use adb commands.
333f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                mUsbStorageNotification.fullScreenIntent = pi;
334f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler            }
33564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
33664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
33764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        final int notificationId = mUsbStorageNotification.icon;
33864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
33964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            notificationManager.notify(notificationId, mUsbStorageNotification);
34064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
34164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            notificationManager.cancel(notificationId);
34264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
34364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
34464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
34564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private synchronized boolean getMediaStorageNotificationDismissable() {
34664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if ((mMediaStorageNotification != null) &&
34764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
34864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    Notification.FLAG_AUTO_CANCEL))
34964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return true;
35064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
35164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        return false;
35264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
35364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
35464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
35564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Sets the media storage notification.
35664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
35764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
35864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                                                          boolean dismissable, PendingIntent pi) {
35964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (!visible && mMediaStorageNotification == null) {
36164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
36264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
36364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        NotificationManager notificationManager = (NotificationManager) mContext
36564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                .getSystemService(Context.NOTIFICATION_SERVICE);
36664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (notificationManager == null) {
36864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
36964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
37064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
37164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (mMediaStorageNotification != null && visible) {
37264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            /*
37364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             * Dismiss the previous notification - we're about to
37464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             * re-use it.
37564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             */
37664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            final int notificationId = mMediaStorageNotification.icon;
37764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            notificationManager.cancel(notificationId);
37864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
37964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
38064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
38164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Resources r = Resources.getSystem();
38264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence title = r.getText(titleId);
38364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence message = r.getText(messageId);
38464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
38564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (mMediaStorageNotification == null) {
38664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification = new Notification();
38764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.when = 0;
38864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
38964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
39164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (dismissable) {
39364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
39464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
39564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
39664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
39764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.tickerText = title;
39964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (pi == null) {
40064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                Intent intent = new Intent();
40164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
40264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
40364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
40464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.icon = icon;
40564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
40664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
40764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
40864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        final int notificationId = mMediaStorageNotification.icon;
40964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
41064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            notificationManager.notify(notificationId, mMediaStorageNotification);
41164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
41264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            notificationManager.cancel(notificationId);
41364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
41464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
41564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat}
416