OSDN Git Service

GlobalActions: Set the initial status of airplane mode toggle
[android-x86/frameworks-base.git] / services / core / java / com / android / server / policy / GlobalActions.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  * Copyright (C) 2010-2015 CyanogenMod Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package com.android.server.policy;
19
20 import com.android.internal.app.AlertController;
21 import com.android.internal.app.AlertController.AlertParams;
22 import com.android.internal.logging.MetricsLogger;
23 import com.android.internal.logging.MetricsProto.MetricsEvent;
24 import com.android.internal.telephony.TelephonyIntents;
25 import com.android.internal.telephony.TelephonyProperties;
26 import com.android.internal.R;
27 import com.android.internal.widget.LockPatternUtils;
28
29 import android.app.ActivityManager;
30 import android.app.ActivityManagerNative;
31 import android.app.AlertDialog;
32 import android.app.Dialog;
33 import android.content.BroadcastReceiver;
34 import android.content.ComponentName;
35 import android.content.Context;
36 import android.content.ContentResolver;
37 import android.content.DialogInterface;
38 import android.content.Intent;
39 import android.content.IntentFilter;
40 import android.content.pm.UserInfo;
41 import android.content.ServiceConnection;
42 import android.database.ContentObserver;
43 import android.graphics.drawable.Drawable;
44 import android.Manifest;
45 import android.media.AudioManager;
46 import android.net.ConnectivityManager;
47 import android.os.Build;
48 import android.os.Bundle;
49 import android.os.Handler;
50 import android.os.IBinder;
51 import android.os.IPowerManager;
52 import android.os.Message;
53 import android.os.Messenger;
54 import android.os.RemoteException;
55 import android.os.ServiceManager;
56 import android.os.SystemClock;
57 import android.os.SystemProperties;
58 import android.os.UserHandle;
59 import android.os.UserManager;
60 import android.os.Vibrator;
61 import android.provider.Settings;
62 import android.service.dreams.DreamService;
63 import android.service.dreams.IDreamManager;
64 import android.telephony.PhoneStateListener;
65 import android.telephony.ServiceState;
66 import android.telephony.TelephonyManager;
67 import android.text.TextUtils;
68 import android.util.ArraySet;
69 import android.util.Log;
70 import android.util.TypedValue;
71 import android.view.InputDevice;
72 import android.view.KeyEvent;
73 import android.view.LayoutInflater;
74 import android.view.MotionEvent;
75 import android.view.View;
76 import android.view.ViewConfiguration;
77 import android.view.ViewGroup;
78 import android.view.WindowManager;
79 import android.view.WindowManagerGlobal;
80 import android.view.WindowManagerPolicy.WindowManagerFuncs;
81 import android.view.accessibility.AccessibilityEvent;
82 import android.widget.AdapterView;
83 import android.widget.BaseAdapter;
84 import android.widget.ImageView;
85 import android.widget.ImageView.ScaleType;
86 import android.widget.ListView;
87 import android.widget.TextView;
88 import cyanogenmod.providers.CMSettings;
89
90 import java.util.ArrayList;
91 import java.util.List;
92 import java.util.UUID;
93
94 import static com.android.internal.util.cm.PowerMenuConstants.*;
95
96 /**
97  * Helper to show the global actions dialog.  Each item is an {@link Action} that
98  * may show depending on whether the keyguard is showing, and whether the device
99  * is provisioned.
100  */
101 class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
102
103     private static final String TAG = "GlobalActions";
104
105     private static final boolean SHOW_SILENT_TOGGLE = true;
106
107     private final Context mContext;
108     private final WindowManagerFuncs mWindowManagerFuncs;
109     private final AudioManager mAudioManager;
110     private final IDreamManager mDreamManager;
111
112     private ArrayList<Action> mItems;
113     private GlobalActionsDialog mDialog;
114
115     private Action mSilentModeAction;
116     private ToggleAction mAirplaneModeOn;
117
118     private MyAdapter mAdapter;
119
120     private boolean mKeyguardShowing = false;
121     private boolean mDeviceProvisioned = false;
122     private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
123     private boolean mIsWaitingForEcmExit = false;
124     private boolean mHasTelephony;
125     private boolean mHasVibrator;
126     private final boolean mShowSilentToggle;
127
128     // Power menu customizations
129     String mActions;
130
131     /**
132      * @param context everything needs a context :(
133      */
134     public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
135         mContext = context;
136         mWindowManagerFuncs = windowManagerFuncs;
137         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
138         mDreamManager = IDreamManager.Stub.asInterface(
139                 ServiceManager.getService(DreamService.DREAM_SERVICE));
140
141         // receive broadcasts
142         IntentFilter filter = new IntentFilter();
143         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
144         filter.addAction(Intent.ACTION_SCREEN_OFF);
145         filter.addAction(Intent.UPDATE_POWER_MENU);
146         filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
147         context.registerReceiver(mBroadcastReceiver, filter);
148
149         ConnectivityManager cm = (ConnectivityManager)
150                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
151         mHasTelephony = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
152
153         // get notified of phone state changes
154         TelephonyManager telephonyManager =
155                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
156         telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
157         mContext.getContentResolver().registerContentObserver(
158                 Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
159                 mAirplaneModeObserver);
160         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
161         mHasVibrator = vibrator != null && vibrator.hasVibrator();
162
163         mShowSilentToggle = SHOW_SILENT_TOGGLE && !mContext.getResources().getBoolean(
164                 com.android.internal.R.bool.config_useFixedVolume);
165
166         // Set the initial status of airplane mode toggle
167         mAirplaneState = getUpdatedAirplaneToggleState();
168
169         updatePowerMenuActions();
170     }
171
172     /**
173      * Show the global actions dialog (creating if necessary)
174      * @param keyguardShowing True if keyguard is showing
175      */
176     public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
177         mKeyguardShowing = keyguardShowing;
178         mDeviceProvisioned = isDeviceProvisioned;
179         if (mDialog != null) {
180             mDialog.dismiss();
181             mDialog = null;
182             mDialog = createDialog();
183             // Show delayed, so that the dismiss of the previous dialog completes
184             mHandler.sendEmptyMessage(MESSAGE_SHOW);
185         } else {
186             mDialog = createDialog();
187             handleShow();
188         }
189     }
190
191     private void awakenIfNecessary() {
192         if (mDreamManager != null) {
193             try {
194                 if (mDreamManager.isDreaming()) {
195                     mDreamManager.awaken();
196                 }
197             } catch (RemoteException e) {
198                 // we tried
199             }
200         }
201     }
202
203     private void handleShow() {
204         awakenIfNecessary();
205         prepareDialog();
206
207         // If we only have 1 item and it's a simple press action, just do this action.
208         if (mAdapter.getCount() == 1
209                 && mAdapter.getItem(0) instanceof SinglePressAction
210                 && !(mAdapter.getItem(0) instanceof LongPressAction)) {
211             ((SinglePressAction) mAdapter.getItem(0)).onPress();
212         } else {
213             WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
214             attrs.setTitle("GlobalActions");
215             mDialog.getWindow().setAttributes(attrs);
216             mDialog.show();
217             mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
218         }
219     }
220
221     /**
222      * Create the global actions dialog.
223      * @return A new dialog.
224      */
225     private GlobalActionsDialog createDialog() {
226         // Simple toggle style if there's no vibrator, otherwise use a tri-state
227         if (!mHasVibrator) {
228             mSilentModeAction = new SilentModeToggleAction();
229         } else {
230             mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);
231         }
232         mAirplaneModeOn = new ToggleAction(
233                 R.drawable.ic_lock_airplane_mode,
234                 R.drawable.ic_lock_airplane_mode_off,
235                 R.string.global_actions_toggle_airplane_mode,
236                 R.string.global_actions_airplane_mode_on_status,
237                 R.string.global_actions_airplane_mode_off_status) {
238
239             void onToggle(boolean on) {
240                 if (mHasTelephony && Boolean.parseBoolean(
241                         SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
242                     mIsWaitingForEcmExit = true;
243                     // Launch ECM exit dialog
244                     Intent ecmDialogIntent =
245                             new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
246                     ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
247                     mContext.startActivity(ecmDialogIntent);
248                 } else {
249                     changeAirplaneModeSystemSetting(on);
250                 }
251             }
252
253             @Override
254             protected void changeStateFromPress(boolean buttonOn) {
255                 if (!mHasTelephony) return;
256
257                 // In ECM mode airplane state cannot be changed
258                 if (!(Boolean.parseBoolean(
259                         SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
260                     mState = buttonOn ? State.TurningOn : State.TurningOff;
261                     mAirplaneState = mState;
262                 }
263             }
264
265             public boolean showDuringKeyguard() {
266                 return true;
267             }
268
269             public boolean showBeforeProvisioning() {
270                 return false;
271             }
272         };
273         onAirplaneModeChanged();
274
275         mItems = new ArrayList<Action>();
276
277         String[] actionsArray;
278         if (mActions == null) {
279             actionsArray = mContext.getResources().getStringArray(
280                     com.android.internal.R.array.config_globalActionsList);
281         } else {
282             actionsArray = mActions.split("\\|");
283         }
284
285         // Always add the power off option
286         mItems.add(new PowerAction());
287
288         ArraySet<String> addedKeys = new ArraySet<String>();
289         for (int i = 0; i < actionsArray.length; i++) {
290             String actionKey = actionsArray[i];
291             if (addedKeys.contains(actionKey)) {
292                 // If we already have added this, don't add it again.
293                 continue;
294             }
295             if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
296                 continue;
297             } else if (GLOBAL_ACTION_KEY_REBOOT.equals(actionKey)) {
298                 mItems.add(new RebootAction());
299             } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
300                 mItems.add(getScreenshotAction());
301             } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
302                 mItems.add(mAirplaneModeOn);
303             } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
304                 if (Settings.Global.getInt(mContext.getContentResolver(),
305                         Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
306                     mItems.add(new BugReportAction());
307                 }
308             } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
309                 if (mShowSilentToggle) {
310                     mItems.add(mSilentModeAction);
311                 }
312             } else if (GLOBAL_ACTION_KEY_USERS.equals(actionKey)) {
313                 List<UserInfo> users = ((UserManager) mContext.getSystemService(
314                         Context.USER_SERVICE)).getUsers();
315                 if (users.size() > 1) {
316                     addUsersToMenu(mItems);
317                 }
318             } else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
319                 mItems.add(getSettingsAction());
320             } else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
321                 mItems.add(getLockdownAction());
322             } else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
323                 mItems.add(getVoiceAssistAction());
324             } else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
325                 mItems.add(getAssistAction());
326             } else {
327                 Log.e(TAG, "Invalid global action key " + actionKey);
328             }
329             // Add here so we don't add more than one.
330             addedKeys.add(actionKey);
331         }
332
333         mAdapter = new MyAdapter();
334
335         AlertParams params = new AlertParams(mContext);
336         params.mAdapter = mAdapter;
337         params.mOnClickListener = this;
338         params.mForceInverseBackground = true;
339
340         GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);
341         dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
342
343         dialog.getListView().setItemsCanFocus(true);
344         dialog.getListView().setLongClickable(true);
345         dialog.getListView().setOnItemLongClickListener(
346                 new AdapterView.OnItemLongClickListener() {
347                     @Override
348                     public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
349                             long id) {
350                         final Action action = mAdapter.getItem(position);
351                         if (action instanceof LongPressAction) {
352                             return ((LongPressAction) action).onLongPress();
353                         }
354                         return false;
355                     }
356         });
357         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
358
359         dialog.setOnDismissListener(this);
360
361         return dialog;
362     }
363
364     private final class PowerAction extends SinglePressAction implements LongPressAction {
365         private PowerAction() {
366             super(com.android.internal.R.drawable.ic_lock_power_off,
367                 R.string.global_action_power_off);
368         }
369
370         @Override
371         public boolean onLongPress() {
372             UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
373             if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
374                 mWindowManagerFuncs.rebootSafeMode(true);
375                 return true;
376             }
377             return false;
378         }
379
380         @Override
381         public boolean showDuringKeyguard() {
382             return true;
383         }
384
385         @Override
386         public boolean showBeforeProvisioning() {
387             return true;
388         }
389
390         @Override
391         public void onPress() {
392             // shutdown by making sure radio and power are handled accordingly.
393             mWindowManagerFuncs.shutdown(false /* confirm */);
394         }
395     }
396
397     private final class RebootAction extends SinglePressAction {
398         private RebootAction() {
399             super(com.android.internal.R.drawable.ic_lock_power_reboot,
400                     R.string.global_action_reboot);
401         }
402
403         @Override
404         public boolean showDuringKeyguard() {
405             return true;
406         }
407
408         @Override
409         public boolean showBeforeProvisioning() {
410             return true;
411         }
412
413         @Override
414         public void onPress() {
415             try {
416                 IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager
417                         .getService(Context.POWER_SERVICE));
418                 pm.reboot(true, null, false);
419             } catch (RemoteException e) {
420                 Log.e(TAG, "PowerManager service died!", e);
421                 return;
422             }
423         }
424     }
425
426     private Action getScreenshotAction() {
427         return new SinglePressAction(com.android.internal.R.drawable.ic_lock_screenshot,
428                 R.string.global_action_screenshot) {
429
430             public void onPress() {
431                 takeScreenshot();
432             }
433
434             public boolean showDuringKeyguard() {
435                 return true;
436             }
437
438             public boolean showBeforeProvisioning() {
439                 return true;
440             }
441         };
442     }
443
444     private class BugReportAction extends SinglePressAction implements LongPressAction {
445         public BugReportAction() {
446             super(com.android.internal.R.drawable.ic_lock_bugreport, R.string.bugreport_title);
447         }
448
449         @Override
450         public void onPress() {
451             // don't actually trigger the bugreport if we are running stability
452             // tests via monkey
453             if (ActivityManager.isUserAMonkey()) {
454                 return;
455             }
456             // Add a little delay before executing, to give the
457             // dialog a chance to go away before it takes a
458             // screenshot.
459             mHandler.postDelayed(new Runnable() {
460                 @Override
461                 public void run() {
462                     try {
463                         // Take an "interactive" bugreport.
464                         MetricsLogger.action(mContext,
465                                 MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE);
466                         ActivityManagerNative.getDefault().requestBugReport(
467                                 ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
468                     } catch (RemoteException e) {
469                     }
470                 }
471             }, 500);
472         }
473
474         @Override
475         public boolean onLongPress() {
476             // don't actually trigger the bugreport if we are running stability
477             // tests via monkey
478             if (ActivityManager.isUserAMonkey()) {
479                 return false;
480             }
481             try {
482                 // Take a "full" bugreport.
483                 MetricsLogger.action(mContext, MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL);
484                 ActivityManagerNative.getDefault().requestBugReport(
485                         ActivityManager.BUGREPORT_OPTION_FULL);
486             } catch (RemoteException e) {
487             }
488             return false;
489         }
490
491         public boolean showDuringKeyguard() {
492             return true;
493         }
494
495         @Override
496         public boolean showBeforeProvisioning() {
497             return false;
498         }
499
500         @Override
501         public String getStatus() {
502             return mContext.getString(
503                     com.android.internal.R.string.bugreport_status,
504                     Build.VERSION.RELEASE,
505                     Build.ID);
506         }
507     }
508
509     private Action getSettingsAction() {
510         return new SinglePressAction(com.android.internal.R.drawable.ic_lock_settings,
511                 R.string.global_action_settings) {
512
513             @Override
514             public void onPress() {
515                 Intent intent = new Intent(Settings.ACTION_SETTINGS);
516                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
517                 mContext.startActivity(intent);
518             }
519
520             @Override
521             public boolean showDuringKeyguard() {
522                 return true;
523             }
524
525             @Override
526             public boolean showBeforeProvisioning() {
527                 return true;
528             }
529         };
530     }
531
532     private Action getAssistAction() {
533         return new SinglePressAction(com.android.internal.R.drawable.ic_action_assist_focused,
534                 R.string.global_action_assist) {
535             @Override
536             public void onPress() {
537                 Intent intent = new Intent(Intent.ACTION_ASSIST);
538                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
539                 mContext.startActivity(intent);
540             }
541
542             @Override
543             public boolean showDuringKeyguard() {
544                 return true;
545             }
546
547             @Override
548             public boolean showBeforeProvisioning() {
549                 return true;
550             }
551         };
552     }
553
554     private Action getVoiceAssistAction() {
555         return new SinglePressAction(com.android.internal.R.drawable.ic_voice_search,
556                 R.string.global_action_voice_assist) {
557             @Override
558             public void onPress() {
559                 Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST);
560                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
561                 mContext.startActivity(intent);
562             }
563
564             @Override
565             public boolean showDuringKeyguard() {
566                 return true;
567             }
568
569             @Override
570             public boolean showBeforeProvisioning() {
571                 return true;
572             }
573         };
574     }
575
576     private Action getLockdownAction() {
577         return new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock,
578                 R.string.global_action_lockdown) {
579
580             @Override
581             public void onPress() {
582                 new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
583                 try {
584                     WindowManagerGlobal.getWindowManagerService().lockNow(null);
585                 } catch (RemoteException e) {
586                     Log.e(TAG, "Error while trying to lock device.", e);
587                 }
588             }
589
590             @Override
591             public boolean showDuringKeyguard() {
592                 return true;
593             }
594
595             @Override
596             public boolean showBeforeProvisioning() {
597                 return false;
598             }
599         };
600     }
601
602     private UserInfo getCurrentUser() {
603         try {
604             return ActivityManagerNative.getDefault().getCurrentUser();
605         } catch (RemoteException re) {
606             return null;
607         }
608     }
609
610     private boolean isCurrentUserOwner() {
611         UserInfo currentUser = getCurrentUser();
612         return currentUser == null || currentUser.isPrimary();
613     }
614
615     private void addUsersToMenu(ArrayList<Action> items) {
616         UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
617         if (um.isUserSwitcherEnabled()) {
618             List<UserInfo> users = um.getUsers();
619             UserInfo currentUser = getCurrentUser();
620             for (final UserInfo user : users) {
621                 if (user.supportsSwitchToByUser()) {
622                     boolean isCurrentUser = currentUser == null
623                             ? user.id == 0 : (currentUser.id == user.id);
624                     Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
625                             : null;
626                     SinglePressAction switchToUser = new SinglePressAction(
627                             com.android.internal.R.drawable.ic_lock_user, icon,
628                             (user.name != null ? user.name : "Primary")
629                             + (isCurrentUser ? " \u2714" : "")) {
630                         public void onPress() {
631                             try {
632                                 ActivityManagerNative.getDefault().switchUser(user.id);
633                             } catch (RemoteException re) {
634                                 Log.e(TAG, "Couldn't switch user " + re);
635                             }
636                         }
637
638                         public boolean showDuringKeyguard() {
639                             return true;
640                         }
641
642                         public boolean showBeforeProvisioning() {
643                             return false;
644                         }
645                     };
646                     items.add(switchToUser);
647                 }
648             }
649         }
650     }
651
652     /**
653      * functions needed for taking screenhots.
654      * This leverages the built in ICS screenshot functionality
655      */
656     final Object mScreenshotLock = new Object();
657     ServiceConnection mScreenshotConnection = null;
658
659     final Runnable mScreenshotTimeout = new Runnable() {
660         @Override public void run() {
661             synchronized (mScreenshotLock) {
662                 if (mScreenshotConnection != null) {
663                     mContext.unbindService(mScreenshotConnection);
664                     mScreenshotConnection = null;
665                 }
666             }
667         }
668     };
669
670     private void takeScreenshot() {
671         synchronized (mScreenshotLock) {
672             if (mScreenshotConnection != null) {
673                 return;
674             }
675             ComponentName cn = new ComponentName("com.android.systemui",
676                     "com.android.systemui.screenshot.TakeScreenshotService");
677             Intent intent = new Intent();
678             intent.setComponent(cn);
679             ServiceConnection conn = new ServiceConnection() {
680                 @Override
681                 public void onServiceConnected(ComponentName name, IBinder service) {
682                     synchronized (mScreenshotLock) {
683                         if (mScreenshotConnection != this) {
684                             return;
685                         }
686                         Messenger messenger = new Messenger(service);
687                         Message msg = Message.obtain(null, 1);
688                         final ServiceConnection myConn = this;
689                         Handler h = new Handler(mHandler.getLooper()) {
690                             @Override
691                             public void handleMessage(Message msg) {
692                                 synchronized (mScreenshotLock) {
693                                     if (mScreenshotConnection == myConn) {
694                                         mContext.unbindService(mScreenshotConnection);
695                                         mScreenshotConnection = null;
696                                         mHandler.removeCallbacks(mScreenshotTimeout);
697                                     }
698                                 }
699                             }
700                         };
701                         msg.replyTo = new Messenger(h);
702                         msg.arg1 = msg.arg2 = 0;
703
704                         /*  remove for the time being
705                         if (mStatusBar != null && mStatusBar.isVisibleLw())
706                             msg.arg1 = 1;
707                         if (mNavigationBar != null && mNavigationBar.isVisibleLw())
708                             msg.arg2 = 1;
709                          */
710
711                         /* wait for the dialog box to close */
712                         try {
713                             Thread.sleep(1000);
714                         } catch (InterruptedException ie) {
715                             // Do nothing
716                         }
717
718                         /* take the screenshot */
719                         try {
720                             messenger.send(msg);
721                         } catch (RemoteException e) {
722                             // Do nothing
723                         }
724                     }
725                 }
726                 @Override
727                 public void onServiceDisconnected(ComponentName name) {}
728             };
729             if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
730                 mScreenshotConnection = conn;
731                 mHandler.postDelayed(mScreenshotTimeout, 10000);
732             }
733         }
734     }
735
736     private void prepareDialog() {
737         refreshSilentMode();
738         mAirplaneModeOn.updateState(mAirplaneState);
739         mAdapter.notifyDataSetChanged();
740         mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
741         if (mShowSilentToggle) {
742             IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
743             mContext.registerReceiver(mRingerModeReceiver, filter);
744         }
745     }
746
747     private void refreshSilentMode() {
748         if (!mHasVibrator) {
749             final boolean silentModeOn =
750                     mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
751             ((ToggleAction)mSilentModeAction).updateState(
752                     silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
753         }
754     }
755
756     /** {@inheritDoc} */
757     public void onDismiss(DialogInterface dialog) {
758         if (mShowSilentToggle) {
759             try {
760                 mContext.unregisterReceiver(mRingerModeReceiver);
761             } catch (IllegalArgumentException ie) {
762                 // ignore this
763                 Log.w(TAG, ie);
764             }
765         }
766     }
767
768     /** {@inheritDoc} */
769     public void onClick(DialogInterface dialog, int which) {
770         if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
771             dialog.dismiss();
772         }
773         mAdapter.getItem(which).onPress();
774     }
775
776     /**
777      * The adapter used for the list within the global actions dialog, taking
778      * into account whether the keyguard is showing via
779      * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned
780      * via {@link GlobalActions#mDeviceProvisioned}.
781      */
782     private class MyAdapter extends BaseAdapter {
783
784         public int getCount() {
785             int count = 0;
786
787             for (int i = 0; i < mItems.size(); i++) {
788                 final Action action = mItems.get(i);
789
790                 if (mKeyguardShowing && !action.showDuringKeyguard()) {
791                     continue;
792                 }
793                 if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
794                     continue;
795                 }
796                 count++;
797             }
798             return count;
799         }
800
801         @Override
802         public boolean isEnabled(int position) {
803             return getItem(position).isEnabled();
804         }
805
806         @Override
807         public boolean areAllItemsEnabled() {
808             return false;
809         }
810
811         public Action getItem(int position) {
812
813             int filteredPos = 0;
814             for (int i = 0; i < mItems.size(); i++) {
815                 final Action action = mItems.get(i);
816                 if (mKeyguardShowing && !action.showDuringKeyguard()) {
817                     continue;
818                 }
819                 if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
820                     continue;
821                 }
822                 if (filteredPos == position) {
823                     return action;
824                 }
825                 filteredPos++;
826             }
827
828             throw new IllegalArgumentException("position " + position
829                     + " out of range of showable actions"
830                     + ", filtered count=" + getCount()
831                     + ", keyguardshowing=" + mKeyguardShowing
832                     + ", provisioned=" + mDeviceProvisioned);
833         }
834
835
836         public long getItemId(int position) {
837             return position;
838         }
839
840         public View getView(int position, View convertView, ViewGroup parent) {
841             Action action = getItem(position);
842             return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
843         }
844     }
845
846     // note: the scheme below made more sense when we were planning on having
847     // 8 different things in the global actions dialog.  seems overkill with
848     // only 3 items now, but may as well keep this flexible approach so it will
849     // be easy should someone decide at the last minute to include something
850     // else, such as 'enable wifi', or 'enable bluetooth'
851
852     /**
853      * What each item in the global actions dialog must be able to support.
854      */
855     private interface Action {
856         /**
857          * @return Text that will be announced when dialog is created.  null
858          *     for none.
859          */
860         CharSequence getLabelForAccessibility(Context context);
861
862         View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
863
864         void onPress();
865
866         /**
867          * @return whether this action should appear in the dialog when the keygaurd
868          *    is showing.
869          */
870         boolean showDuringKeyguard();
871
872         /**
873          * @return whether this action should appear in the dialog before the
874          *   device is provisioned.
875          */
876         boolean showBeforeProvisioning();
877
878         boolean isEnabled();
879     }
880
881     /**
882      * An action that also supports long press.
883      */
884     private interface LongPressAction extends Action {
885         boolean onLongPress();
886     }
887
888     /**
889      * A single press action maintains no state, just responds to a press
890      * and takes an action.
891      */
892     private static abstract class SinglePressAction implements Action {
893         private final int mIconResId;
894         private final Drawable mIcon;
895         private final int mMessageResId;
896         private final CharSequence mMessage;
897
898         protected SinglePressAction(int iconResId, int messageResId) {
899             mIconResId = iconResId;
900             mMessageResId = messageResId;
901             mMessage = null;
902             mIcon = null;
903         }
904
905         protected SinglePressAction(int iconResId, Drawable icon, CharSequence message) {
906             mIconResId = iconResId;
907             mMessageResId = 0;
908             mMessage = message;
909             mIcon = icon;
910         }
911
912         public boolean isEnabled() {
913             return true;
914         }
915
916         public String getStatus() {
917             return null;
918         }
919
920         abstract public void onPress();
921
922         public CharSequence getLabelForAccessibility(Context context) {
923             if (mMessage != null) {
924                 return mMessage;
925             } else {
926                 return context.getString(mMessageResId);
927             }
928         }
929
930         public View create(
931                 Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
932             View v = inflater.inflate(R.layout.global_actions_item, parent, false);
933
934             ImageView icon = (ImageView) v.findViewById(R.id.icon);
935             TextView messageView = (TextView) v.findViewById(R.id.message);
936
937             TextView statusView = (TextView) v.findViewById(R.id.status);
938             final String status = getStatus();
939             if (!TextUtils.isEmpty(status)) {
940                 statusView.setText(status);
941             } else {
942                 statusView.setVisibility(View.GONE);
943             }
944             if (mIcon != null) {
945                 icon.setImageDrawable(mIcon);
946                 icon.setScaleType(ScaleType.CENTER_CROP);
947             } else if (mIconResId != 0) {
948                 icon.setImageDrawable(context.getDrawable(mIconResId));
949             }
950             if (mMessage != null) {
951                 messageView.setText(mMessage);
952             } else {
953                 messageView.setText(mMessageResId);
954             }
955
956             return v;
957         }
958     }
959
960     /**
961      * A toggle action knows whether it is on or off, and displays an icon
962      * and status message accordingly.
963      */
964     private static abstract class ToggleAction implements Action {
965
966         enum State {
967             Off(false),
968             TurningOn(true),
969             TurningOff(true),
970             On(false);
971
972             private final boolean inTransition;
973
974             State(boolean intermediate) {
975                 inTransition = intermediate;
976             }
977
978             public boolean inTransition() {
979                 return inTransition;
980             }
981         }
982
983         protected State mState = State.Off;
984
985         // prefs
986         protected int mEnabledIconResId;
987         protected int mDisabledIconResid;
988         protected int mMessageResId;
989         protected int mEnabledStatusMessageResId;
990         protected int mDisabledStatusMessageResId;
991
992         /**
993          * @param enabledIconResId The icon for when this action is on.
994          * @param disabledIconResid The icon for when this action is off.
995          * @param essage The general information message, e.g 'Silent Mode'
996          * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
997          * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
998          */
999         public ToggleAction(int enabledIconResId,
1000                 int disabledIconResid,
1001                 int message,
1002                 int enabledStatusMessageResId,
1003                 int disabledStatusMessageResId) {
1004             mEnabledIconResId = enabledIconResId;
1005             mDisabledIconResid = disabledIconResid;
1006             mMessageResId = message;
1007             mEnabledStatusMessageResId = enabledStatusMessageResId;
1008             mDisabledStatusMessageResId = disabledStatusMessageResId;
1009         }
1010
1011         /**
1012          * Override to make changes to resource IDs just before creating the
1013          * View.
1014          */
1015         void willCreate() {
1016
1017         }
1018
1019         @Override
1020         public CharSequence getLabelForAccessibility(Context context) {
1021             return context.getString(mMessageResId);
1022         }
1023
1024         public View create(Context context, View convertView, ViewGroup parent,
1025                 LayoutInflater inflater) {
1026             willCreate();
1027
1028             View v = inflater.inflate(R
1029                             .layout.global_actions_item, parent, false);
1030
1031             ImageView icon = (ImageView) v.findViewById(R.id.icon);
1032             TextView messageView = (TextView) v.findViewById(R.id.message);
1033             TextView statusView = (TextView) v.findViewById(R.id.status);
1034             final boolean enabled = isEnabled();
1035
1036             if (messageView != null) {
1037                 messageView.setText(mMessageResId);
1038                 messageView.setEnabled(enabled);
1039             }
1040
1041             boolean on = ((mState == State.On) || (mState == State.TurningOn));
1042             if (icon != null) {
1043                 icon.setImageDrawable(context.getDrawable(
1044                         (on ? mEnabledIconResId : mDisabledIconResid)));
1045                 icon.setEnabled(enabled);
1046             }
1047
1048             if (statusView != null) {
1049                 statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
1050                 statusView.setVisibility(View.VISIBLE);
1051                 statusView.setEnabled(enabled);
1052             }
1053             v.setEnabled(enabled);
1054
1055             return v;
1056         }
1057
1058         public final void onPress() {
1059             if (mState.inTransition()) {
1060                 Log.w(TAG, "shouldn't be able to toggle when in transition");
1061                 return;
1062             }
1063
1064             final boolean nowOn = !(mState == State.On);
1065             onToggle(nowOn);
1066             changeStateFromPress(nowOn);
1067         }
1068
1069         public boolean isEnabled() {
1070             return !mState.inTransition();
1071         }
1072
1073         /**
1074          * Implementations may override this if their state can be in on of the intermediate
1075          * states until some notification is received (e.g airplane mode is 'turning off' until
1076          * we know the wireless connections are back online
1077          * @param buttonOn Whether the button was turned on or off
1078          */
1079         protected void changeStateFromPress(boolean buttonOn) {
1080             mState = buttonOn ? State.On : State.Off;
1081         }
1082
1083         abstract void onToggle(boolean on);
1084
1085         public void updateState(State state) {
1086             mState = state;
1087         }
1088     }
1089
1090     private class SilentModeToggleAction extends ToggleAction {
1091         public SilentModeToggleAction() {
1092             super(R.drawable.ic_audio_vol_mute,
1093                     R.drawable.ic_audio_vol,
1094                     R.string.global_action_toggle_silent_mode,
1095                     R.string.global_action_silent_mode_on_status,
1096                     R.string.global_action_silent_mode_off_status);
1097         }
1098
1099         void onToggle(boolean on) {
1100             if (on) {
1101                 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
1102             } else {
1103                 mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
1104             }
1105         }
1106
1107         public boolean showDuringKeyguard() {
1108             return true;
1109         }
1110
1111         public boolean showBeforeProvisioning() {
1112             return false;
1113         }
1114     }
1115
1116     private static class SilentModeTriStateAction implements Action, View.OnClickListener {
1117
1118         private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
1119
1120         private final AudioManager mAudioManager;
1121         private final Handler mHandler;
1122         private final Context mContext;
1123
1124         SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) {
1125             mAudioManager = audioManager;
1126             mHandler = handler;
1127             mContext = context;
1128         }
1129
1130         private int ringerModeToIndex(int ringerMode) {
1131             // They just happen to coincide
1132             return ringerMode;
1133         }
1134
1135         private int indexToRingerMode(int index) {
1136             // They just happen to coincide
1137             return index;
1138         }
1139
1140         @Override
1141         public CharSequence getLabelForAccessibility(Context context) {
1142             return null;
1143         }
1144
1145         public View create(Context context, View convertView, ViewGroup parent,
1146                 LayoutInflater inflater) {
1147             View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
1148
1149             int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
1150             for (int i = 0; i < 3; i++) {
1151                 View itemView = v.findViewById(ITEM_IDS[i]);
1152                 itemView.setSelected(selectedIndex == i);
1153                 // Set up click handler
1154                 itemView.setTag(i);
1155                 itemView.setOnClickListener(this);
1156             }
1157             return v;
1158         }
1159
1160         public void onPress() {
1161         }
1162
1163         public boolean showDuringKeyguard() {
1164             return true;
1165         }
1166
1167         public boolean showBeforeProvisioning() {
1168             return false;
1169         }
1170
1171         public boolean isEnabled() {
1172             return true;
1173         }
1174
1175         void willCreate() {
1176         }
1177
1178         public void onClick(View v) {
1179             if (!(v.getTag() instanceof Integer)) return;
1180
1181             int index = (Integer) v.getTag();
1182             mAudioManager.setRingerMode(indexToRingerMode(index));
1183             mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
1184         }
1185     }
1186
1187     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1188         public void onReceive(Context context, Intent intent) {
1189             String action = intent.getAction();
1190             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
1191                     || Intent.ACTION_SCREEN_OFF.equals(action)) {
1192                 String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
1193                 if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
1194                     mHandler.sendEmptyMessage(MESSAGE_DISMISS);
1195                 }
1196             } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
1197                 // Airplane mode can be changed after ECM exits if airplane toggle button
1198                 // is pressed during ECM mode
1199                 if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
1200                         mIsWaitingForEcmExit) {
1201                     mIsWaitingForEcmExit = false;
1202                     changeAirplaneModeSystemSetting(true);
1203                 }
1204             } else if (Intent.UPDATE_POWER_MENU.equals(action)) {
1205                 updatePowerMenuActions();
1206             }
1207         }
1208     };
1209
1210     protected void updatePowerMenuActions() {
1211         ContentResolver resolver = mContext.getContentResolver();
1212         mActions = CMSettings.Secure.getStringForUser(resolver,
1213                 CMSettings.Secure.POWER_MENU_ACTIONS, UserHandle.USER_CURRENT);
1214     }
1215
1216     PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
1217         @Override
1218         public void onServiceStateChanged(ServiceState serviceState) {
1219             if (!mHasTelephony) return;
1220             final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
1221             mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
1222             mAirplaneModeOn.updateState(mAirplaneState);
1223             mAdapter.notifyDataSetChanged();
1224         }
1225     };
1226
1227     private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
1228         @Override
1229         public void onReceive(Context context, Intent intent) {
1230             if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
1231                 mHandler.sendEmptyMessage(MESSAGE_REFRESH);
1232             }
1233         }
1234     };
1235
1236     private ContentObserver mAirplaneModeObserver = new ContentObserver(new Handler()) {
1237         @Override
1238         public void onChange(boolean selfChange) {
1239             onAirplaneModeChanged();
1240         }
1241     };
1242
1243     private static final int MESSAGE_DISMISS = 0;
1244     private static final int MESSAGE_REFRESH = 1;
1245     private static final int MESSAGE_SHOW = 2;
1246     private static final int DIALOG_DISMISS_DELAY = 300; // ms
1247
1248     private Handler mHandler = new Handler() {
1249         public void handleMessage(Message msg) {
1250             switch (msg.what) {
1251             case MESSAGE_DISMISS:
1252                 if (mDialog != null) {
1253                     mDialog.dismiss();
1254                     mDialog = null;
1255                 }
1256                 break;
1257             case MESSAGE_REFRESH:
1258                 refreshSilentMode();
1259                 mAdapter.notifyDataSetChanged();
1260                 break;
1261             case MESSAGE_SHOW:
1262                 handleShow();
1263                 break;
1264             }
1265         }
1266     };
1267
1268     private ToggleAction.State getUpdatedAirplaneToggleState() {
1269         return (Settings.Global.getInt(mContext.getContentResolver(),
1270                     Settings.Global.AIRPLANE_MODE_ON, 0) == 1) ?
1271                 ToggleAction.State.On : ToggleAction.State.Off;
1272     }
1273
1274     private void onAirplaneModeChanged() {
1275         // Let the service state callbacks handle the state.
1276         if (mHasTelephony) return;
1277
1278         mAirplaneState = getUpdatedAirplaneToggleState();
1279         mAirplaneModeOn.updateState(mAirplaneState);
1280     }
1281
1282     /**
1283      * Change the airplane mode system setting
1284      */
1285     private void changeAirplaneModeSystemSetting(boolean on) {
1286         Settings.Global.putInt(
1287                 mContext.getContentResolver(),
1288                 Settings.Global.AIRPLANE_MODE_ON,
1289                 on ? 1 : 0);
1290         Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
1291         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1292         intent.putExtra("state", on);
1293         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1294         if (!mHasTelephony) {
1295             mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
1296         }
1297     }
1298
1299     private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
1300         private final Context mContext;
1301         private final int mWindowTouchSlop;
1302         private final AlertController mAlert;
1303         private final MyAdapter mAdapter;
1304
1305         private EnableAccessibilityController mEnableAccessibilityController;
1306
1307         private boolean mIntercepted;
1308         private boolean mCancelOnUp;
1309
1310         public GlobalActionsDialog(Context context, AlertParams params) {
1311             super(context, getDialogTheme(context));
1312             mContext = getContext();
1313             mAlert = new AlertController(mContext, this, getWindow());
1314             mAdapter = (MyAdapter) params.mAdapter;
1315             mWindowTouchSlop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
1316             params.apply(mAlert);
1317         }
1318
1319         private static int getDialogTheme(Context context) {
1320             TypedValue outValue = new TypedValue();
1321             context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
1322                     outValue, true);
1323             return outValue.resourceId;
1324         }
1325
1326         @Override
1327         protected void onStart() {
1328             // If global accessibility gesture can be performed, we will take care
1329             // of dismissing the dialog on touch outside. This is because the dialog
1330             // is dismissed on the first down while the global gesture is a long press
1331             // with two fingers anywhere on the screen.
1332             if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) {
1333                 mEnableAccessibilityController = new EnableAccessibilityController(mContext,
1334                         new Runnable() {
1335                     @Override
1336                     public void run() {
1337                         dismiss();
1338                     }
1339                 });
1340                 super.setCanceledOnTouchOutside(false);
1341             } else {
1342                 mEnableAccessibilityController = null;
1343                 super.setCanceledOnTouchOutside(true);
1344             }
1345
1346             super.onStart();
1347         }
1348
1349         @Override
1350         protected void onStop() {
1351             if (mEnableAccessibilityController != null) {
1352                 mEnableAccessibilityController.onDestroy();
1353             }
1354             super.onStop();
1355         }
1356
1357         @Override
1358         public boolean dispatchTouchEvent(MotionEvent event) {
1359             if (mEnableAccessibilityController != null) {
1360                 final int action = event.getActionMasked();
1361                 if (action == MotionEvent.ACTION_DOWN) {
1362                     View decor = getWindow().getDecorView();
1363                     final int eventX = (int) event.getX();
1364                     final int eventY = (int) event.getY();
1365                     if (eventX < -mWindowTouchSlop
1366                             || eventY < -mWindowTouchSlop
1367                             || eventX >= decor.getWidth() + mWindowTouchSlop
1368                             || eventY >= decor.getHeight() + mWindowTouchSlop) {
1369                         mCancelOnUp = true;
1370                     }
1371                 }
1372                 try {
1373                     if (!mIntercepted) {
1374                         mIntercepted = mEnableAccessibilityController.onInterceptTouchEvent(event);
1375                         if (mIntercepted) {
1376                             final long now = SystemClock.uptimeMillis();
1377                             event = MotionEvent.obtain(now, now,
1378                                     MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1379                             event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1380                             mCancelOnUp = true;
1381                         }
1382                     } else {
1383                         return mEnableAccessibilityController.onTouchEvent(event);
1384                     }
1385                 } finally {
1386                     if (action == MotionEvent.ACTION_UP) {
1387                         if (mCancelOnUp) {
1388                             cancel();
1389                         }
1390                         mCancelOnUp = false;
1391                         mIntercepted = false;
1392                     }
1393                 }
1394             }
1395             return super.dispatchTouchEvent(event);
1396         }
1397
1398         public ListView getListView() {
1399             return mAlert.getListView();
1400         }
1401
1402         @Override
1403         protected void onCreate(Bundle savedInstanceState) {
1404             super.onCreate(savedInstanceState);
1405             mAlert.installContent();
1406         }
1407
1408         @Override
1409         public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1410             if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
1411                 for (int i = 0; i < mAdapter.getCount(); ++i) {
1412                     CharSequence label =
1413                             mAdapter.getItem(i).getLabelForAccessibility(getContext());
1414                     if (label != null) {
1415                         event.getText().add(label);
1416                     }
1417                 }
1418             }
1419             return super.dispatchPopulateAccessibilityEvent(event);
1420         }
1421
1422         @Override
1423         public boolean onKeyDown(int keyCode, KeyEvent event) {
1424             if (mAlert.onKeyDown(keyCode, event)) {
1425                 return true;
1426             }
1427             return super.onKeyDown(keyCode, event);
1428         }
1429
1430         @Override
1431         public boolean onKeyUp(int keyCode, KeyEvent event) {
1432             if (mAlert.onKeyUp(keyCode, event)) {
1433                 return true;
1434             }
1435             return super.onKeyUp(keyCode, event);
1436         }
1437     }
1438 }