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;
2850cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackbornimport android.os.UserHandle;
29b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.StorageEventListener;
30b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.StorageManager;
31c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandlerimport android.provider.Settings;
32cd686b5b6d4166b510df8e32138479a9559bc117John Spurlockimport android.util.Log;
3364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
343e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlockimport com.android.systemui.SystemUI;
353e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock
363e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlockpublic class StorageNotification extends SystemUI {
3764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private static final String TAG = "StorageNotification";
3840e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn    private static final boolean DEBUG = false;
3964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
40c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler    private static final boolean POP_UMS_ACTIVITY_ON_CONNECT = true;
41c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler
4264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
4364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * The notification that is shown when a USB mass storage host
44209bede6b9edb9171e5bee4077b48e35004a37b4John Spurlock     * is connected.
4564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * <p>
4664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * This is lazily created, so use {@link #setUsbStorageNotification()}.
4764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
4864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private Notification mUsbStorageNotification;
4964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
5064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
5164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * The notification that is shown when the following media events occur:
5264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is being checked
5364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is blank (or unknown filesystem)
5464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is corrupt
5564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is safe to unmount
5664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is missing
5764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * <p>
5864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * This is lazily created, so use {@link #setMediaStorageNotification()}.
5964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
60b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private Notification   mMediaStorageNotification;
61b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean        mUmsAvailable;
62b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private StorageManager mStorageManager;
6364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
645b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private Handler        mAsyncEventHandler;
655b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
663e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock    private class StorageNotificationEventListener extends StorageEventListener {
673e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        public void onUsbMassStorageConnectionChanged(final boolean connected) {
683e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock            mAsyncEventHandler.post(new Runnable() {
693e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                @Override
703e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                public void run() {
713e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                    onUsbMassStorageConnectionChangedAsync(connected);
723e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                }
733e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock            });
743e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        }
753e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        public void onStorageStateChanged(final String path,
763e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                final String oldState, final String newState) {
773e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock            mAsyncEventHandler.post(new Runnable() {
783e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                @Override
793e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                public void run() {
803e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                    onStorageStateChangedAsync(path, oldState, newState);
813e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock                }
823e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock            });
833e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        }
843e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock    }
8564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
863e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock    @Override
873e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock    public void start() {
883e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
89fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato        final boolean connected = mStorageManager.isUsbMassStorageConnected();
90cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock        if (DEBUG) Log.d(TAG, String.format( "Startup with UMS connection %s (media state %s)",
9140e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn                mUmsAvailable, Environment.getExternalStorageState()));
923e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock
935b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        HandlerThread thr = new HandlerThread("SystemUI StorageNotification");
945b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        thr.start();
955b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        mAsyncEventHandler = new Handler(thr.getLooper());
965b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
973e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        StorageNotificationEventListener listener = new StorageNotificationEventListener();
983e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        listener.onUsbMassStorageConnectionChanged(connected);
993e309b2edc99cced870916a7a0fa0d27578cad6dJohn Spurlock        mStorageManager.registerListener(listener);
1005b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    }
1015b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
1025b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private void onUsbMassStorageConnectionChangedAsync(boolean connected) {
103b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mUmsAvailable = connected;
10464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        /*
105b104340496e3a531e26c8f428c808eca0e039f50San Mehat         * Even though we may have a UMS host connected, we the SD card
106b104340496e3a531e26c8f428c808eca0e039f50San Mehat         * may not be in a state for export.
10764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat         */
108b104340496e3a531e26c8f428c808eca0e039f50San Mehat        String st = Environment.getExternalStorageState();
10964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
110cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock        if (DEBUG) Log.i(TAG, String.format("UMS connection changed to %s (media state %s)",
11140e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn                connected, st));
112b104340496e3a531e26c8f428c808eca0e039f50San Mehat
113b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (connected && (st.equals(
114b104340496e3a531e26c8f428c808eca0e039f50San Mehat                Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) {
115b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
116b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * No card or card being checked = don't display
117b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
118b104340496e3a531e26c8f428c808eca0e039f50San Mehat            connected = false;
11964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
120b104340496e3a531e26c8f428c808eca0e039f50San Mehat        updateUsbMassStorageNotification(connected);
12164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
12264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
1235b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private void onStorageStateChangedAsync(String path, String oldState, String newState) {
124cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock        if (DEBUG) Log.i(TAG, String.format(
125b104340496e3a531e26c8f428c808eca0e039f50San Mehat                "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));
12664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (newState.equals(Environment.MEDIA_SHARED)) {
127b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
128b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now shared. Modify the UMS notification
129b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * for stopping UMS.
130b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
13164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
132fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
13364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
13464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(
13564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_stop_notification_title,
13664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_stop_notification_message,
13764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_sys_warning, false, true, pi);
13864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_CHECKING)) {
139b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
140b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now checking. Update media notification and disable
141b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * UMS notification.
142b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
14364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
14464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_checking_notification_title,
14564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_checking_notification_message,
14664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_prepare, true, false, null);
14764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(false);
14864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_MOUNTED)) {
149b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
150b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now mounted. Dismiss any media notifications,
151b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
152b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
15364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(0, 0, 0, false, false, null);
15464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
15564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_UNMOUNTED)) {
156b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
157b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now unmounted. We may have been unmounted
158b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * because the user is enabling/disabling UMS, in which case we don't
159b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * want to display the 'safe to unmount' notification.
160b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
161b104340496e3a531e26c8f428c808eca0e039f50San Mehat            if (!mStorageManager.isUsbMassStorageEnabled()) {
162b104340496e3a531e26c8f428c808eca0e039f50San Mehat                if (oldState.equals(Environment.MEDIA_SHARED)) {
163b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    /*
164b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * The unmount was due to UMS being enabled. Dismiss any
165b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * media notifications, and enable UMS notification if connected
166b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     */
167b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    setMediaStorageNotification(0, 0, 0, false, false, null);
168b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    updateUsbMassStorageNotification(mUmsAvailable);
169b104340496e3a531e26c8f428c808eca0e039f50San Mehat                } else {
170b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    /*
171b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * Show safe to unmount media notification, and enable UMS
172b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * notification if connected.
173b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     */
174d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    if (Environment.isExternalStorageRemovable()) {
175d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        setMediaStorageNotification(
176d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.string.ext_media_safe_unmount_notification_title,
177d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.string.ext_media_safe_unmount_notification_message,
178d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.drawable.stat_notify_sdcard, true, true, null);
179d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    } else {
180d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        // This device does not have removable storage, so
181d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        // don't tell the user they can remove it.
182d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        setMediaStorageNotification(0, 0, 0, false, false, null);
183d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    }
184b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    updateUsbMassStorageNotification(mUmsAvailable);
185b104340496e3a531e26c8f428c808eca0e039f50San Mehat                }
18664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
187b104340496e3a531e26c8f428c808eca0e039f50San Mehat                /*
188b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 * The unmount was due to UMS being enabled. Dismiss any
189b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 * media notifications, and disable the UMS notification
190b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 */
19164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                setMediaStorageNotification(0, 0, 0, false, false, null);
192b104340496e3a531e26c8f428c808eca0e039f50San Mehat                updateUsbMassStorageNotification(false);
19364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
19464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_NOFS)) {
195b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
196b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has no filesystem. Show blank media notification,
197b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
198b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
19964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
20064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
20164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
20264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
20364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
20464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_nofs_notification_title,
20564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_nofs_notification_message,
20664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
20764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
20864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_UNMOUNTABLE)) {
209b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
210b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is corrupt. Show corrupt media notification,
211b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
212b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
21364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
21464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
21564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
21664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
21764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
21864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_unmountable_notification_title,
21964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_unmountable_notification_message,
220209bede6b9edb9171e5bee4077b48e35004a37b4John Spurlock                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
22164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
222b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else if (newState.equals(Environment.MEDIA_REMOVED)) {
223b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
224b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has been removed. Show nomedia media notification,
225b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and disable UMS notification regardless of connection state.
226b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
227b104340496e3a531e26c8f428c808eca0e039f50San Mehat            setMediaStorageNotification(
228b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_nomedia_notification_title,
229b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_nomedia_notification_message,
230b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
231b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    true, false, null);
232b104340496e3a531e26c8f428c808eca0e039f50San Mehat            updateUsbMassStorageNotification(false);
233b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else if (newState.equals(Environment.MEDIA_BAD_REMOVAL)) {
234b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
235b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has been removed unsafely. Show bad removal media notification,
236b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and disable UMS notification regardless of connection state.
237b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
238b104340496e3a531e26c8f428c808eca0e039f50San Mehat            setMediaStorageNotification(
239b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_badremoval_notification_title,
240b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_badremoval_notification_message,
241b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.drawable.stat_sys_warning,
242b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    true, true, null);
243b104340496e3a531e26c8f428c808eca0e039f50San Mehat            updateUsbMassStorageNotification(false);
244b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else {
245cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock            Log.w(TAG, String.format("Ignoring unknown state {%s}", newState));
24664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
24764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
24864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
24964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
25064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Update the state of the USB mass storage notification
25164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
25264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    void updateUsbMassStorageNotification(boolean available) {
25364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
25464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (available) {
25564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
256fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
25764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
258c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler
25964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
26064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(
26164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_notification_title,
26264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_notification_message,
26364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_sys_data_usb,
26464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    false, true, pi);
26564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
26664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(0, 0, 0, false, false, null);
26764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
26864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
26964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
27064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
27164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Sets the USB storage notification.
27264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
2734154c07c5cabc74029a2df379075391d782a682cSan Mehat    private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon,
2744154c07c5cabc74029a2df379075391d782a682cSan Mehat            boolean sound, boolean visible, PendingIntent pi) {
27564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
27664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (!visible && mUsbStorageNotification == null) {
27764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
27864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
27964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        NotificationManager notificationManager = (NotificationManager) mContext
28164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                .getSystemService(Context.NOTIFICATION_SERVICE);
28264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (notificationManager == null) {
28464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
28564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
286209bede6b9edb9171e5bee4077b48e35004a37b4John Spurlock
28764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
28864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Resources r = Resources.getSystem();
28964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence title = r.getText(titleId);
29064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence message = r.getText(messageId);
29164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
29264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (mUsbStorageNotification == null) {
29364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification = new Notification();
29464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.icon = icon;
29564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.when = 0;
29664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
29764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
29864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (sound) {
29964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
30064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
30164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
30264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
303209bede6b9edb9171e5bee4077b48e35004a37b4John Spurlock
30464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
30564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
30664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.tickerText = title;
30764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (pi == null) {
30864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                Intent intent = new Intent();
30950cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                pi = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
31050cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                        UserHandle.CURRENT);
31164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
312255dd04271088590fedc46c8e22b2fd4ab142d39Selim Cinek            mUsbStorageNotification.color = mContext.getResources().getColor(
313255dd04271088590fedc46c8e22b2fd4ab142d39Selim Cinek                    com.android.internal.R.color.system_notification_accent_color);
31464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
315bfe61f696de3ceecda51612d3b26f20af33bc16cDan Sandler            mUsbStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
31659f0258a27ebaf8468919a9d2855c41f0429238dDan Sandler            mUsbStorageNotification.category = Notification.CATEGORY_SYSTEM;
317bfe61f696de3ceecda51612d3b26f20af33bc16cDan Sandler
318bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324Jeff Brown            final boolean adbOn = 1 == Settings.Global.getInt(
319f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                mContext.getContentResolver(),
320bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324Jeff Brown                Settings.Global.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        }
336209bede6b9edb9171e5bee4077b48e35004a37b4John Spurlock
33764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        final int notificationId = mUsbStorageNotification.icon;
33864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
33950cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.notifyAsUser(null, notificationId, mUsbStorageNotification,
34050cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    UserHandle.ALL);
34164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
34250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.cancelAsUser(null, notificationId, UserHandle.ALL);
34364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
34464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
34564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
34664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private synchronized boolean getMediaStorageNotificationDismissable() {
34764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if ((mMediaStorageNotification != null) &&
34864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
34964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    Notification.FLAG_AUTO_CANCEL))
35064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return true;
35164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
35264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        return false;
35364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
35464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
35564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
35664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Sets the media storage notification.
35764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
35864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
35964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                                                          boolean dismissable, PendingIntent pi) {
36064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (!visible && mMediaStorageNotification == null) {
36264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
36364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
36464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        NotificationManager notificationManager = (NotificationManager) mContext
36664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                .getSystemService(Context.NOTIFICATION_SERVICE);
36764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (notificationManager == null) {
36964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
37064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
37164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
37264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (mMediaStorageNotification != null && visible) {
37364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            /*
37464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             * Dismiss the previous notification - we're about to
37564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             * re-use it.
37664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             */
37764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            final int notificationId = mMediaStorageNotification.icon;
37864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            notificationManager.cancel(notificationId);
37964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
380209bede6b9edb9171e5bee4077b48e35004a37b4John Spurlock
38164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
38264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Resources r = Resources.getSystem();
38364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence title = r.getText(titleId);
38464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence message = r.getText(messageId);
38564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
38664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (mMediaStorageNotification == null) {
38764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification = new Notification();
38864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.when = 0;
38964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
39064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
39264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (dismissable) {
39464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
39564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
39664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
39764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
39864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.tickerText = title;
40064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (pi == null) {
40164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                Intent intent = new Intent();
40250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                pi = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
40350cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                        UserHandle.CURRENT);
40464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
40564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
40664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.icon = icon;
407255dd04271088590fedc46c8e22b2fd4ab142d39Selim Cinek            mMediaStorageNotification.color = mContext.getResources().getColor(
408255dd04271088590fedc46c8e22b2fd4ab142d39Selim Cinek                    com.android.internal.R.color.system_notification_accent_color);
40964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
410bfe61f696de3ceecda51612d3b26f20af33bc16cDan Sandler            mMediaStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
41159f0258a27ebaf8468919a9d2855c41f0429238dDan Sandler            mMediaStorageNotification.category = Notification.CATEGORY_SYSTEM;
41264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
413209bede6b9edb9171e5bee4077b48e35004a37b4John Spurlock
41464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        final int notificationId = mMediaStorageNotification.icon;
41564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
41650cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.notifyAsUser(null, notificationId,
41750cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    mMediaStorageNotification, UserHandle.ALL);
41864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
41950cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.cancelAsUser(null, notificationId, UserHandle.ALL);
42064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
42164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
42264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat}
423