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;
328a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog;
3364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
34b104340496e3a531e26c8f428c808eca0e039f50San Mehatpublic class StorageNotification extends StorageEventListener {
3564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private static final String TAG = "StorageNotification";
3664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
37c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler    private static final boolean POP_UMS_ACTIVITY_ON_CONNECT = true;
38c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler
3964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
4064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Binder context for this service
4164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
4264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private Context mContext;
4364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
4464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
4564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * The notification that is shown when a USB mass storage host
4664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * is connected.
4764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * <p>
4864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * This is lazily created, so use {@link #setUsbStorageNotification()}.
4964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
5064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private Notification mUsbStorageNotification;
5164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
5264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
5364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * The notification that is shown when the following media events occur:
5464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is being checked
5564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is blank (or unknown filesystem)
5664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is corrupt
5764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is safe to unmount
5864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     *     - Media is missing
5964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * <p>
6064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * This is lazily created, so use {@link #setMediaStorageNotification()}.
6164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
62b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private Notification   mMediaStorageNotification;
63b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean        mUmsAvailable;
64b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private StorageManager mStorageManager;
6564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
665b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private Handler        mAsyncEventHandler;
675b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
6864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    public StorageNotification(Context context) {
6964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        mContext = context;
7064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
71b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
72fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato        final boolean connected = mStorageManager.isUsbMassStorageConnected();
738a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.d(TAG, String.format( "Startup with UMS connection %s (media state %s)", mUmsAvailable,
74b104340496e3a531e26c8f428c808eca0e039f50San Mehat                Environment.getExternalStorageState()));
755b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
765b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        HandlerThread thr = new HandlerThread("SystemUI StorageNotification");
775b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        thr.start();
785b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        mAsyncEventHandler = new Handler(thr.getLooper());
795b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
80fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato        onUsbMassStorageConnectionChanged(connected);
8164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
8264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
83b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
84b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @override com.android.os.storage.StorageEventListener
85b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
86b104340496e3a531e26c8f428c808eca0e039f50San Mehat    @Override
875b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    public void onUsbMassStorageConnectionChanged(final boolean connected) {
885b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        mAsyncEventHandler.post(new Runnable() {
895b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            @Override
905b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            public void run() {
915b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler                onUsbMassStorageConnectionChangedAsync(connected);
925b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            }
935b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        });
945b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    }
955b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
965b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private void onUsbMassStorageConnectionChangedAsync(boolean connected) {
97b104340496e3a531e26c8f428c808eca0e039f50San Mehat        mUmsAvailable = connected;
9864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        /*
99b104340496e3a531e26c8f428c808eca0e039f50San Mehat         * Even though we may have a UMS host connected, we the SD card
100b104340496e3a531e26c8f428c808eca0e039f50San Mehat         * may not be in a state for export.
10164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat         */
102b104340496e3a531e26c8f428c808eca0e039f50San Mehat        String st = Environment.getExternalStorageState();
10364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
1048a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.i(TAG, String.format("UMS connection changed to %s (media state %s)", connected, st));
105b104340496e3a531e26c8f428c808eca0e039f50San Mehat
106b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (connected && (st.equals(
107b104340496e3a531e26c8f428c808eca0e039f50San Mehat                Environment.MEDIA_REMOVED) || st.equals(Environment.MEDIA_CHECKING))) {
108b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
109b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * No card or card being checked = don't display
110b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
111b104340496e3a531e26c8f428c808eca0e039f50San Mehat            connected = false;
11264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
113b104340496e3a531e26c8f428c808eca0e039f50San Mehat        updateUsbMassStorageNotification(connected);
11464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
11564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
116b104340496e3a531e26c8f428c808eca0e039f50San Mehat    /*
117b104340496e3a531e26c8f428c808eca0e039f50San Mehat     * @override com.android.os.storage.StorageEventListener
118b104340496e3a531e26c8f428c808eca0e039f50San Mehat     */
119b104340496e3a531e26c8f428c808eca0e039f50San Mehat    @Override
1205b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    public void onStorageStateChanged(final String path, final String oldState, final String newState) {
1215b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        mAsyncEventHandler.post(new Runnable() {
1225b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            @Override
1235b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            public void run() {
1245b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler                onStorageStateChangedAsync(path, oldState, newState);
1255b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler            }
1265b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler        });
1275b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    }
1285b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler
1295b8743f3d6a0ba23dce533072f92acd7ec3210e9Daniel Sandler    private void onStorageStateChangedAsync(String path, String oldState, String newState) {
1308a9b22056b13477f59df934928c00c58b5871c95Joe Onorato        Slog.i(TAG, String.format(
131b104340496e3a531e26c8f428c808eca0e039f50San Mehat                "Media {%s} state changed from {%s} -> {%s}", path, oldState, newState));
13264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (newState.equals(Environment.MEDIA_SHARED)) {
133b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
134b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now shared. Modify the UMS notification
135b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * for stopping UMS.
136b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
13764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
138fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
13964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
14064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(
14164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_stop_notification_title,
14264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_stop_notification_message,
14364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_sys_warning, false, true, pi);
14464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_CHECKING)) {
145b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
146b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now checking. Update media notification and disable
147b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * UMS notification.
148b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
14964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
15064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_checking_notification_title,
15164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_checking_notification_message,
15264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_prepare, true, false, null);
15364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(false);
15464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_MOUNTED)) {
155b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
156b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now mounted. Dismiss any media notifications,
157b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
158b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
15964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(0, 0, 0, false, false, null);
16064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
16164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_UNMOUNTED)) {
162b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
163b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is now unmounted. We may have been unmounted
164b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * because the user is enabling/disabling UMS, in which case we don't
165b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * want to display the 'safe to unmount' notification.
166b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
167b104340496e3a531e26c8f428c808eca0e039f50San Mehat            if (!mStorageManager.isUsbMassStorageEnabled()) {
168b104340496e3a531e26c8f428c808eca0e039f50San Mehat                if (oldState.equals(Environment.MEDIA_SHARED)) {
169b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    /*
170b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * The unmount was due to UMS being enabled. Dismiss any
171b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * media notifications, and enable UMS notification if connected
172b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     */
173b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    setMediaStorageNotification(0, 0, 0, false, false, null);
174b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    updateUsbMassStorageNotification(mUmsAvailable);
175b104340496e3a531e26c8f428c808eca0e039f50San Mehat                } else {
176b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    /*
177b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * Show safe to unmount media notification, and enable UMS
178b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     * notification if connected.
179b104340496e3a531e26c8f428c808eca0e039f50San Mehat                     */
180d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    if (Environment.isExternalStorageRemovable()) {
181d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        setMediaStorageNotification(
182d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.string.ext_media_safe_unmount_notification_title,
183d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.string.ext_media_safe_unmount_notification_message,
184d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                                com.android.internal.R.drawable.stat_notify_sdcard, true, true, null);
185d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    } else {
186d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        // This device does not have removable storage, so
187d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        // don't tell the user they can remove it.
188d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                        setMediaStorageNotification(0, 0, 0, false, false, null);
189d39d515b9110d7405d0f03dbf612ba5c9b8ac566Dianne Hackborn                    }
190b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    updateUsbMassStorageNotification(mUmsAvailable);
191b104340496e3a531e26c8f428c808eca0e039f50San Mehat                }
19264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
193b104340496e3a531e26c8f428c808eca0e039f50San Mehat                /*
194b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 * The unmount was due to UMS being enabled. Dismiss any
195b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 * media notifications, and disable the UMS notification
196b104340496e3a531e26c8f428c808eca0e039f50San Mehat                 */
19764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                setMediaStorageNotification(0, 0, 0, false, false, null);
198b104340496e3a531e26c8f428c808eca0e039f50San Mehat                updateUsbMassStorageNotification(false);
19964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
20064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_NOFS)) {
201b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
202b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has no filesystem. Show blank media notification,
203b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
204b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
20564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
20664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
20764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
20864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
20964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
21064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_nofs_notification_title,
21164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_nofs_notification_message,
21264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
21364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
21464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else if (newState.equals(Environment.MEDIA_UNMOUNTABLE)) {
215b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
216b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage is corrupt. Show corrupt media notification,
217b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and enable UMS notification if connected.
218b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
21964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
22064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
22164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
22264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
22364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setMediaStorageNotification(
22464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_unmountable_notification_title,
22564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.ext_media_unmountable_notification_message,
22664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb, true, false, pi);
22764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            updateUsbMassStorageNotification(mUmsAvailable);
228b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else if (newState.equals(Environment.MEDIA_REMOVED)) {
229b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
230b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has been removed. Show nomedia media notification,
231b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and disable UMS notification regardless of connection state.
232b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
233b104340496e3a531e26c8f428c808eca0e039f50San Mehat            setMediaStorageNotification(
234b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_nomedia_notification_title,
235b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_nomedia_notification_message,
236b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
237b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    true, false, null);
238b104340496e3a531e26c8f428c808eca0e039f50San Mehat            updateUsbMassStorageNotification(false);
239b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else if (newState.equals(Environment.MEDIA_BAD_REMOVAL)) {
240b104340496e3a531e26c8f428c808eca0e039f50San Mehat            /*
241b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * Storage has been removed unsafely. Show bad removal media notification,
242b104340496e3a531e26c8f428c808eca0e039f50San Mehat             * and disable UMS notification regardless of connection state.
243b104340496e3a531e26c8f428c808eca0e039f50San Mehat             */
244b104340496e3a531e26c8f428c808eca0e039f50San Mehat            setMediaStorageNotification(
245b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_badremoval_notification_title,
246b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.string.ext_media_badremoval_notification_message,
247b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    com.android.internal.R.drawable.stat_sys_warning,
248b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    true, true, null);
249b104340496e3a531e26c8f428c808eca0e039f50San Mehat            updateUsbMassStorageNotification(false);
250b104340496e3a531e26c8f428c808eca0e039f50San Mehat        } else {
2518a9b22056b13477f59df934928c00c58b5871c95Joe Onorato            Slog.w(TAG, String.format("Ignoring unknown state {%s}", newState));
25264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
25364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
25464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
25564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
25664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Update the state of the USB mass storage notification
25764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
25864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    void updateUsbMassStorageNotification(boolean available) {
25964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
26064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (available) {
26164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Intent intent = new Intent();
262fe4f3ae33c8da86585399b4167fd7987c8a16066Joe Onorato            intent.setClass(mContext, com.android.systemui.usb.UsbStorageActivity.class);
26364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
264c07907e0389f20f83fdfe01319023b8c7d5e4bbdDaniel Sandler
26564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
26664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(
26764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_notification_title,
26864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.string.usb_storage_notification_message,
26964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    com.android.internal.R.drawable.stat_sys_data_usb,
27064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    false, true, pi);
27164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
27264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            setUsbStorageNotification(0, 0, 0, false, false, null);
27364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
27464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
27564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
27664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
27764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Sets the USB storage notification.
27864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
2794154c07c5cabc74029a2df379075391d782a682cSan Mehat    private synchronized void setUsbStorageNotification(int titleId, int messageId, int icon,
2804154c07c5cabc74029a2df379075391d782a682cSan Mehat            boolean sound, boolean visible, PendingIntent pi) {
28164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (!visible && mUsbStorageNotification == null) {
28364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
28464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
28564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        NotificationManager notificationManager = (NotificationManager) mContext
28764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                .getSystemService(Context.NOTIFICATION_SERVICE);
28864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
28964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (notificationManager == null) {
29064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
29164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
29264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
29364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
29464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Resources r = Resources.getSystem();
29564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence title = r.getText(titleId);
29664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence message = r.getText(messageId);
29764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
29864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (mUsbStorageNotification == null) {
29964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification = new Notification();
30064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.icon = icon;
30164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.when = 0;
30264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
30364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
30464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (sound) {
30564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.defaults |= Notification.DEFAULT_SOUND;
30664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
30764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mUsbStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
30864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
30964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
31064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
31164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
31264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.tickerText = title;
31364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (pi == null) {
31464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                Intent intent = new Intent();
31550cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                pi = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
31650cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                        UserHandle.CURRENT);
31764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
31864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
31964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
320bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324Jeff Brown            final boolean adbOn = 1 == Settings.Global.getInt(
321f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                mContext.getContentResolver(),
322bf6f6f9de72c9fd15e6bda9f228c05a9b37d6324Jeff Brown                Settings.Global.ADB_ENABLED,
323f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                0);
324f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler
325f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler            if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
326f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // Pop up a full-screen alert to coach the user through enabling UMS. The average
327f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // user has attached the device to USB either to charge the phone (in which case
328f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // this is harmless) or transfer files, and in the latter case this alert saves
329f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // several steps (as well as subtly indicates that you shouldn't mix UMS with other
330f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // activities on the device).
331f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                //
332f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // If ADB is enabled, however, we suppress this dialog (under the assumption that a
333f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // developer (a) knows how to enable UMS, and (b) is probably using USB to install
334f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                // builds or use adb commands.
335f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler                mUsbStorageNotification.fullScreenIntent = pi;
336f7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732Daniel Sandler            }
33764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
33864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
33964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        final int notificationId = mUsbStorageNotification.icon;
34064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
34150cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.notifyAsUser(null, notificationId, mUsbStorageNotification,
34250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    UserHandle.ALL);
34364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
34450cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.cancelAsUser(null, notificationId, UserHandle.ALL);
34564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
34664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
34764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
34864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private synchronized boolean getMediaStorageNotificationDismissable() {
34964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if ((mMediaStorageNotification != null) &&
35064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            ((mMediaStorageNotification.flags & Notification.FLAG_AUTO_CANCEL) ==
35164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                    Notification.FLAG_AUTO_CANCEL))
35264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return true;
35364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
35464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        return false;
35564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
35664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
35764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    /**
35864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     * Sets the media storage notification.
35964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat     */
36064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    private synchronized void setMediaStorageNotification(int titleId, int messageId, int icon, boolean visible,
36164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                                                          boolean dismissable, PendingIntent pi) {
36264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (!visible && mMediaStorageNotification == null) {
36464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
36564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
36664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
36764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        NotificationManager notificationManager = (NotificationManager) mContext
36864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                .getSystemService(Context.NOTIFICATION_SERVICE);
36964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
37064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (notificationManager == null) {
37164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            return;
37264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
37364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
37464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (mMediaStorageNotification != null && visible) {
37564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            /*
37664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             * Dismiss the previous notification - we're about to
37764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             * re-use it.
37864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat             */
37964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            final int notificationId = mMediaStorageNotification.icon;
38064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            notificationManager.cancel(notificationId);
38164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
38264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
38364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
38464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            Resources r = Resources.getSystem();
38564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence title = r.getText(titleId);
38664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            CharSequence message = r.getText(messageId);
38764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
38864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (mMediaStorageNotification == null) {
38964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification = new Notification();
39064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.when = 0;
39164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
39264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.defaults &= ~Notification.DEFAULT_SOUND;
39464e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
39564e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (dismissable) {
39664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.flags = Notification.FLAG_AUTO_CANCEL;
39764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            } else {
39864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                mMediaStorageNotification.flags = Notification.FLAG_ONGOING_EVENT;
39964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
40064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
40164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.tickerText = title;
40264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            if (pi == null) {
40364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat                Intent intent = new Intent();
40450cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                pi = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
40550cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                        UserHandle.CURRENT);
40664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            }
40764e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
40864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.icon = icon;
40964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat            mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
41064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
41164e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat
41264e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        final int notificationId = mMediaStorageNotification.icon;
41364e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        if (visible) {
41450cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.notifyAsUser(null, notificationId,
41550cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    mMediaStorageNotification, UserHandle.ALL);
41664e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        } else {
41750cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            notificationManager.cancelAsUser(null, notificationId, UserHandle.ALL);
41864e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat        }
41964e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat    }
42064e6a45ed45e0d096a1490408ee1cab2a4626950San Mehat}
421