GlobalActions.java revision 7304c343821309dd15f769b18f1de2fa43751573
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.internal.policy.impl;
18
19import com.android.internal.telephony.TelephonyIntents;
20import com.android.internal.telephony.TelephonyProperties;
21import com.android.internal.R;
22
23import android.app.ActivityManagerNative;
24import android.app.AlertDialog;
25import android.content.BroadcastReceiver;
26import android.content.Context;
27import android.content.DialogInterface;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.pm.UserInfo;
31import android.media.AudioManager;
32import android.os.Handler;
33import android.os.IBinder;
34import android.os.Message;
35import android.os.RemoteException;
36import android.os.ServiceManager;
37import android.os.SystemProperties;
38import android.os.Vibrator;
39import android.provider.Settings;
40import android.telephony.PhoneStateListener;
41import android.telephony.ServiceState;
42import android.telephony.TelephonyManager;
43import android.util.Log;
44import android.view.IWindowManager;
45import android.view.LayoutInflater;
46import android.view.View;
47import android.view.ViewGroup;
48import android.view.WindowManager;
49import android.view.WindowManagerPolicy.WindowManagerFuncs;
50import android.widget.AdapterView;
51import android.widget.BaseAdapter;
52import android.widget.ImageView;
53import android.widget.TextView;
54
55import java.util.ArrayList;
56import java.util.List;
57
58/**
59 * Helper to show the global actions dialog.  Each item is an {@link Action} that
60 * may show depending on whether the keyguard is showing, and whether the device
61 * is provisioned.
62 */
63class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener  {
64
65    private static final String TAG = "GlobalActions";
66
67    private static final boolean SHOW_SILENT_TOGGLE = true;
68
69    private final Context mContext;
70    private final WindowManagerFuncs mWindowManagerFuncs;
71    private final AudioManager mAudioManager;
72
73    private ArrayList<Action> mItems;
74    private AlertDialog mDialog;
75
76    private SilentModeAction mSilentModeAction;
77    private ToggleAction mAirplaneModeOn;
78
79    private MyAdapter mAdapter;
80
81    private boolean mKeyguardShowing = false;
82    private boolean mDeviceProvisioned = false;
83    private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
84    private boolean mIsWaitingForEcmExit = false;
85
86    private IWindowManager mIWindowManager;
87
88    /**
89     * @param context everything needs a context :(
90     */
91    public GlobalActions(Context context, WindowManagerFuncs windowManagerFuncs) {
92        mContext = context;
93        mWindowManagerFuncs = windowManagerFuncs;
94        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
95
96        // receive broadcasts
97        IntentFilter filter = new IntentFilter();
98        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
99        filter.addAction(Intent.ACTION_SCREEN_OFF);
100        filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
101        context.registerReceiver(mBroadcastReceiver, filter);
102
103        // get notified of phone state changes
104        TelephonyManager telephonyManager =
105                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
106        telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
107    }
108
109    /**
110     * Show the global actions dialog (creating if necessary)
111     * @param keyguardShowing True if keyguard is showing
112     */
113    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
114        mKeyguardShowing = keyguardShowing;
115        mDeviceProvisioned = isDeviceProvisioned;
116        if (mDialog != null) {
117            mDialog.dismiss();
118            mDialog = null;
119            // Show delayed, so that the dismiss of the previous dialog completes
120            mHandler.sendEmptyMessage(MESSAGE_SHOW);
121        } else {
122            handleShow();
123        }
124    }
125
126    private void handleShow() {
127        mDialog = createDialog();
128        prepareDialog();
129
130        mDialog.show();
131        mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
132    }
133    /**
134     * Create the global actions dialog.
135     * @return A new dialog.
136     */
137    private AlertDialog createDialog() {
138        mSilentModeAction = new SilentModeAction(mContext, mAudioManager, mHandler);
139
140        mAirplaneModeOn = new ToggleAction(
141                R.drawable.ic_lock_airplane_mode,
142                R.drawable.ic_lock_airplane_mode_off,
143                R.string.global_actions_toggle_airplane_mode,
144                R.string.global_actions_airplane_mode_on_status,
145                R.string.global_actions_airplane_mode_off_status) {
146
147            void onToggle(boolean on) {
148                if (Boolean.parseBoolean(
149                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
150                    mIsWaitingForEcmExit = true;
151                    // Launch ECM exit dialog
152                    Intent ecmDialogIntent =
153                            new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
154                    ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
155                    mContext.startActivity(ecmDialogIntent);
156                } else {
157                    changeAirplaneModeSystemSetting(on);
158                }
159            }
160
161            @Override
162            protected void changeStateFromPress(boolean buttonOn) {
163                // In ECM mode airplane state cannot be changed
164                if (!(Boolean.parseBoolean(
165                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
166                    mState = buttonOn ? State.TurningOn : State.TurningOff;
167                    mAirplaneState = mState;
168                }
169            }
170
171            public boolean showDuringKeyguard() {
172                return true;
173            }
174
175            public boolean showBeforeProvisioning() {
176                return false;
177            }
178        };
179
180        mItems = new ArrayList<Action>();
181
182        // first: power off
183        mItems.add(
184            new SinglePressAction(
185                    com.android.internal.R.drawable.ic_lock_power_off,
186                    R.string.global_action_power_off) {
187
188                public void onPress() {
189                    // shutdown by making sure radio and power are handled accordingly.
190                    mWindowManagerFuncs.shutdown();
191                }
192
193                public boolean onLongPress() {
194                    mWindowManagerFuncs.rebootSafeMode();
195                    return true;
196                }
197
198                public boolean showDuringKeyguard() {
199                    return true;
200                }
201
202                public boolean showBeforeProvisioning() {
203                    return true;
204                }
205            });
206
207        // next: airplane mode
208        mItems.add(mAirplaneModeOn);
209
210        // last: silent mode
211        if (SHOW_SILENT_TOGGLE) {
212            mItems.add(mSilentModeAction);
213        }
214
215        List<UserInfo> users = mContext.getPackageManager().getUsers();
216        if (users.size() > 1) {
217            UserInfo currentUser;
218            try {
219                currentUser = ActivityManagerNative.getDefault().getCurrentUser();
220            } catch (RemoteException re) {
221                currentUser = null;
222            }
223            for (final UserInfo user : users) {
224                boolean isCurrentUser = currentUser == null
225                        ? user.id == 0 : (currentUser.id == user.id);
226                SinglePressAction switchToUser = new SinglePressAction(
227                        com.android.internal.R.drawable.ic_menu_cc,
228                        (user.name != null ? user.name : "Primary")
229                        + (isCurrentUser ? " \u2714" : "")) {
230                    public void onPress() {
231                        try {
232                            ActivityManagerNative.getDefault().switchUser(user.id);
233                            getWindowManager().lockNow();
234                        } catch (RemoteException re) {
235                            Log.e(TAG, "Couldn't switch user " + re);
236                        }
237                    }
238
239                    public boolean showDuringKeyguard() {
240                        return true;
241                    }
242
243                    public boolean showBeforeProvisioning() {
244                        return false;
245                    }
246                };
247                mItems.add(switchToUser);
248            }
249        }
250        mAdapter = new MyAdapter();
251
252        final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
253
254        ab.setAdapter(mAdapter, this)
255                .setInverseBackgroundForced(true);
256
257        final AlertDialog dialog = ab.create();
258        dialog.getListView().setItemsCanFocus(true);
259        dialog.getListView().setLongClickable(true);
260        dialog.getListView().setOnItemLongClickListener(
261                new AdapterView.OnItemLongClickListener() {
262                    @Override
263                    public boolean onItemLongClick(AdapterView<?> parent, View view, int position,
264                            long id) {
265                        return mAdapter.getItem(position).onLongPress();
266                    }
267        });
268        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
269
270        dialog.setOnDismissListener(this);
271
272        return dialog;
273    }
274
275    private void prepareDialog() {
276        final boolean silentModeOn =
277                mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
278        mAirplaneModeOn.updateState(mAirplaneState);
279        mAdapter.notifyDataSetChanged();
280        if (mKeyguardShowing) {
281            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
282        } else {
283            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
284        }
285        if (SHOW_SILENT_TOGGLE) {
286            IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
287            mContext.registerReceiver(mRingerModeReceiver, filter);
288        }
289    }
290
291    /** {@inheritDoc} */
292    public void onDismiss(DialogInterface dialog) {
293        if (SHOW_SILENT_TOGGLE) {
294            mContext.unregisterReceiver(mRingerModeReceiver);
295        }
296    }
297
298    /** {@inheritDoc} */
299    public void onClick(DialogInterface dialog, int which) {
300        if (!(mAdapter.getItem(which) instanceof SilentModeAction)) {
301            dialog.dismiss();
302        }
303        mAdapter.getItem(which).onPress();
304    }
305
306    /**
307     * The adapter used for the list within the global actions dialog, taking
308     * into account whether the keyguard is showing via
309     * {@link GlobalActions#mKeyguardShowing} and whether the device is provisioned
310     * via {@link GlobalActions#mDeviceProvisioned}.
311     */
312    private class MyAdapter extends BaseAdapter {
313
314        public int getCount() {
315            int count = 0;
316
317            for (int i = 0; i < mItems.size(); i++) {
318                final Action action = mItems.get(i);
319
320                if (mKeyguardShowing && !action.showDuringKeyguard()) {
321                    continue;
322                }
323                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
324                    continue;
325                }
326                count++;
327            }
328            return count;
329        }
330
331        @Override
332        public boolean isEnabled(int position) {
333            return getItem(position).isEnabled();
334        }
335
336        @Override
337        public boolean areAllItemsEnabled() {
338            return false;
339        }
340
341        public Action getItem(int position) {
342
343            int filteredPos = 0;
344            for (int i = 0; i < mItems.size(); i++) {
345                final Action action = mItems.get(i);
346                if (mKeyguardShowing && !action.showDuringKeyguard()) {
347                    continue;
348                }
349                if (!mDeviceProvisioned && !action.showBeforeProvisioning()) {
350                    continue;
351                }
352                if (filteredPos == position) {
353                    return action;
354                }
355                filteredPos++;
356            }
357
358            throw new IllegalArgumentException("position " + position
359                    + " out of range of showable actions"
360                    + ", filtered count=" + getCount()
361                    + ", keyguardshowing=" + mKeyguardShowing
362                    + ", provisioned=" + mDeviceProvisioned);
363        }
364
365
366        public long getItemId(int position) {
367            return position;
368        }
369
370        public View getView(int position, View convertView, ViewGroup parent) {
371            Action action = getItem(position);
372            return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
373        }
374    }
375
376    // note: the scheme below made more sense when we were planning on having
377    // 8 different things in the global actions dialog.  seems overkill with
378    // only 3 items now, but may as well keep this flexible approach so it will
379    // be easy should someone decide at the last minute to include something
380    // else, such as 'enable wifi', or 'enable bluetooth'
381
382    /**
383     * What each item in the global actions dialog must be able to support.
384     */
385    private interface Action {
386        View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
387
388        void onPress();
389
390        public boolean onLongPress();
391
392        /**
393         * @return whether this action should appear in the dialog when the keygaurd
394         *    is showing.
395         */
396        boolean showDuringKeyguard();
397
398        /**
399         * @return whether this action should appear in the dialog before the
400         *   device is provisioned.
401         */
402        boolean showBeforeProvisioning();
403
404        boolean isEnabled();
405    }
406
407    /**
408     * A single press action maintains no state, just responds to a press
409     * and takes an action.
410     */
411    private static abstract class SinglePressAction implements Action {
412        private final int mIconResId;
413        private final int mMessageResId;
414        private final CharSequence mMessage;
415
416        protected SinglePressAction(int iconResId, int messageResId) {
417            mIconResId = iconResId;
418            mMessageResId = messageResId;
419            mMessage = null;
420        }
421
422        protected SinglePressAction(int iconResId, CharSequence message) {
423            mIconResId = iconResId;
424            mMessageResId = 0;
425            mMessage = message;
426        }
427        public boolean isEnabled() {
428            return true;
429        }
430
431        abstract public void onPress();
432
433        public boolean onLongPress() {
434            return false;
435        }
436
437        public View create(
438                Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
439            View v = inflater.inflate(R.layout.global_actions_item, parent, false);
440
441            ImageView icon = (ImageView) v.findViewById(R.id.icon);
442            TextView messageView = (TextView) v.findViewById(R.id.message);
443
444            v.findViewById(R.id.status).setVisibility(View.GONE);
445
446            icon.setImageDrawable(context.getResources().getDrawable(mIconResId));
447            if (mMessage != null) {
448                messageView.setText(mMessage);
449            } else {
450                messageView.setText(mMessageResId);
451            }
452
453            return v;
454        }
455    }
456
457    /**
458     * A toggle action knows whether it is on or off, and displays an icon
459     * and status message accordingly.
460     */
461    private static abstract class ToggleAction implements Action {
462
463        enum State {
464            Off(false),
465            TurningOn(true),
466            TurningOff(true),
467            On(false);
468
469            private final boolean inTransition;
470
471            State(boolean intermediate) {
472                inTransition = intermediate;
473            }
474
475            public boolean inTransition() {
476                return inTransition;
477            }
478        }
479
480        protected State mState = State.Off;
481
482        // prefs
483        protected int mEnabledIconResId;
484        protected int mDisabledIconResid;
485        protected int mMessageResId;
486        protected int mEnabledStatusMessageResId;
487        protected int mDisabledStatusMessageResId;
488
489        /**
490         * @param enabledIconResId The icon for when this action is on.
491         * @param disabledIconResid The icon for when this action is off.
492         * @param essage The general information message, e.g 'Silent Mode'
493         * @param enabledStatusMessageResId The on status message, e.g 'sound disabled'
494         * @param disabledStatusMessageResId The off status message, e.g. 'sound enabled'
495         */
496        public ToggleAction(int enabledIconResId,
497                int disabledIconResid,
498                int essage,
499                int enabledStatusMessageResId,
500                int disabledStatusMessageResId) {
501            mEnabledIconResId = enabledIconResId;
502            mDisabledIconResid = disabledIconResid;
503            mMessageResId = essage;
504            mEnabledStatusMessageResId = enabledStatusMessageResId;
505            mDisabledStatusMessageResId = disabledStatusMessageResId;
506        }
507
508        /**
509         * Override to make changes to resource IDs just before creating the
510         * View.
511         */
512        void willCreate() {
513
514        }
515
516        public View create(Context context, View convertView, ViewGroup parent,
517                LayoutInflater inflater) {
518            willCreate();
519
520            View v = inflater.inflate(R
521                            .layout.global_actions_item, parent, false);
522
523            ImageView icon = (ImageView) v.findViewById(R.id.icon);
524            TextView messageView = (TextView) v.findViewById(R.id.message);
525            TextView statusView = (TextView) v.findViewById(R.id.status);
526            final boolean enabled = isEnabled();
527
528            if (messageView != null) {
529                messageView.setText(mMessageResId);
530                messageView.setEnabled(enabled);
531            }
532
533            boolean on = ((mState == State.On) || (mState == State.TurningOn));
534            if (icon != null) {
535                icon.setImageDrawable(context.getResources().getDrawable(
536                        (on ? mEnabledIconResId : mDisabledIconResid)));
537                icon.setEnabled(enabled);
538            }
539
540            if (statusView != null) {
541                statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
542                statusView.setVisibility(View.VISIBLE);
543                statusView.setEnabled(enabled);
544            }
545            v.setEnabled(enabled);
546
547            return v;
548        }
549
550        public final void onPress() {
551            if (mState.inTransition()) {
552                Log.w(TAG, "shouldn't be able to toggle when in transition");
553                return;
554            }
555
556            final boolean nowOn = !(mState == State.On);
557            onToggle(nowOn);
558            changeStateFromPress(nowOn);
559        }
560
561        public boolean onLongPress() {
562            return false;
563        }
564
565        public boolean isEnabled() {
566            return !mState.inTransition();
567        }
568
569        /**
570         * Implementations may override this if their state can be in on of the intermediate
571         * states until some notification is received (e.g airplane mode is 'turning off' until
572         * we know the wireless connections are back online
573         * @param buttonOn Whether the button was turned on or off
574         */
575        protected void changeStateFromPress(boolean buttonOn) {
576            mState = buttonOn ? State.On : State.Off;
577        }
578
579        abstract void onToggle(boolean on);
580
581        public void updateState(State state) {
582            mState = state;
583        }
584    }
585
586    private static class SilentModeAction implements Action, View.OnClickListener {
587
588        private final int[] ITEM_IDS = { R.id.option1, R.id.option2, R.id.option3 };
589
590        private final AudioManager mAudioManager;
591        private final Handler mHandler;
592        private final boolean mHasVibrator;
593        private final Context mContext;
594
595        SilentModeAction(Context context, AudioManager audioManager, Handler handler) {
596            mAudioManager = audioManager;
597            mHandler = handler;
598            mContext = context;
599            Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
600            mHasVibrator = vibrator != null && vibrator.hasVibrator();
601        }
602
603        private int ringerModeToIndex(int ringerMode) {
604            // They just happen to coincide
605            return ringerMode;
606        }
607
608        private int indexToRingerMode(int index) {
609            // They just happen to coincide
610            return index;
611        }
612
613        public View create(Context context, View convertView, ViewGroup parent,
614                LayoutInflater inflater) {
615            View v = inflater.inflate(R.layout.global_actions_silent_mode, parent, false);
616
617            int selectedIndex = ringerModeToIndex(mAudioManager.getRingerMode());
618            for (int i = 0; i < 3; i++) {
619                View itemView = v.findViewById(ITEM_IDS[i]);
620                itemView.setSelected(selectedIndex == i);
621                // Set up click handler
622                itemView.setTag(i);
623                itemView.setOnClickListener(this);
624                if (itemView.getId() == R.id.option2 && !mHasVibrator) {
625                    itemView.setVisibility(View.GONE);
626                }
627            }
628            return v;
629        }
630
631        public void onPress() {
632        }
633
634        public boolean onLongPress() {
635            return false;
636        }
637
638        public boolean showDuringKeyguard() {
639            return true;
640        }
641
642        public boolean showBeforeProvisioning() {
643            return false;
644        }
645
646        public boolean isEnabled() {
647            return true;
648        }
649
650        void willCreate() {
651        }
652
653        public void onClick(View v) {
654            if (!(v.getTag() instanceof Integer)) return;
655
656            int index = (Integer) v.getTag();
657            mAudioManager.setRingerMode(indexToRingerMode(index));
658            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
659        }
660    }
661
662    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
663        public void onReceive(Context context, Intent intent) {
664            String action = intent.getAction();
665            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
666                    || Intent.ACTION_SCREEN_OFF.equals(action)) {
667                String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY);
668                if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
669                    mHandler.sendEmptyMessage(MESSAGE_DISMISS);
670                }
671            } else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
672                // Airplane mode can be changed after ECM exits if airplane toggle button
673                // is pressed during ECM mode
674                if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
675                        mIsWaitingForEcmExit) {
676                    mIsWaitingForEcmExit = false;
677                    changeAirplaneModeSystemSetting(true);
678                }
679            }
680        }
681    };
682
683    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
684        @Override
685        public void onServiceStateChanged(ServiceState serviceState) {
686            final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
687            mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
688            mAirplaneModeOn.updateState(mAirplaneState);
689            mAdapter.notifyDataSetChanged();
690        }
691    };
692
693    private BroadcastReceiver mRingerModeReceiver = new BroadcastReceiver() {
694        @Override
695        public void onReceive(Context context, Intent intent) {
696            if (intent.getAction().equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
697                mHandler.sendEmptyMessage(MESSAGE_REFRESH);
698            }
699        }
700    };
701
702    private static final int MESSAGE_DISMISS = 0;
703    private static final int MESSAGE_REFRESH = 1;
704    private static final int MESSAGE_SHOW = 2;
705    private static final int DIALOG_DISMISS_DELAY = 300; // ms
706
707    private Handler mHandler = new Handler() {
708        public void handleMessage(Message msg) {
709            switch (msg.what) {
710            case MESSAGE_DISMISS:
711                if (mDialog != null) {
712                    mDialog.dismiss();
713                }
714                break;
715            case MESSAGE_REFRESH:
716                mAdapter.notifyDataSetChanged();
717                break;
718            case MESSAGE_SHOW:
719                handleShow();
720                break;
721            }
722        }
723    };
724
725    /**
726     * Change the airplane mode system setting
727     */
728    private void changeAirplaneModeSystemSetting(boolean on) {
729        Settings.System.putInt(
730                mContext.getContentResolver(),
731                Settings.System.AIRPLANE_MODE_ON,
732                on ? 1 : 0);
733        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
734        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
735        intent.putExtra("state", on);
736        mContext.sendBroadcast(intent);
737    }
738
739    private IWindowManager getWindowManager() {
740        if (mIWindowManager == null) {
741            IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
742            mIWindowManager = IWindowManager.Stub.asInterface(b);
743        }
744        return mIWindowManager;
745    }
746}
747