ImmersiveModeConfirmation.java revision 62b65e4a8f058787eb49ec1630dfca2d9cd2b751
134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock/*
234e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * Copyright (C) 2013 The Android Open Source Project
334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock *
434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * Licensed under the Apache License, Version 2.0 (the "License");
534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * you may not use this file except in compliance with the License.
634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * You may obtain a copy of the License at
734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock *
834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock *      http://www.apache.org/licenses/LICENSE-2.0
934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock *
1034e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * Unless required by applicable law or agreed to in writing, software
1134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * distributed under the License is distributed on an "AS IS" BASIS,
1234e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * See the License for the specific language governing permissions and
1434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock * limitations under the License.
1534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock */
1634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
17b10e33ff804a831c71be9303146cea892b9aeb5dJorim Jaggipackage com.android.server.policy;
1834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
19a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.animation.ArgbEvaluator;
20a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.animation.ValueAnimator;
21a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.app.ActivityManager;
22b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandlerimport android.content.BroadcastReceiver;
2334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.content.Context;
24b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandlerimport android.content.Intent;
25b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandlerimport android.content.IntentFilter;
26a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.graphics.PixelFormat;
27a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.graphics.drawable.ColorDrawable;
2834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.os.Handler;
294cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.os.Message;
30d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlockimport android.os.UserHandle;
31d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlockimport android.provider.Settings;
32a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.util.DisplayMetrics;
3334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.util.Slog;
34d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlockimport android.util.SparseBooleanArray;
35a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.Gravity;
36a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.MotionEvent;
3734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.view.View;
38a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.ViewGroup;
39a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.WindowManager;
404cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.view.animation.Animation;
414cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.view.animation.AnimationUtils;
42a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.animation.DecelerateInterpolator;
4362b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roosimport android.view.animation.Interpolator;
44a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.widget.Button;
45a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.widget.FrameLayout;
4634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
4734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport com.android.internal.R;
4834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
4934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock/**
50f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock *  Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
51f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock *  entering immersive mode.
5234e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock */
53f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlockpublic class ImmersiveModeConfirmation {
54f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock    private static final String TAG = "ImmersiveModeConfirmation";
554cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    private static final boolean DEBUG = false;
56a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler    private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution
57d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    private static final String CONFIRMED = "confirmed";
5834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
5934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock    private final Context mContext;
604cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    private final H mHandler;
614cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    private final long mShowDelayMs;
62d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    private final long mPanicThresholdMs;
63d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    private final SparseBooleanArray mUserPanicResets = new SparseBooleanArray();
6434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
65d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    private boolean mConfirmed;
66a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler    private ClingWindowView mClingWindow;
67d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    private long mPanicTime;
68a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler    private WindowManager mWindowManager;
69d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    private int mCurrentUserId;
7034e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
71f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock    public ImmersiveModeConfirmation(Context context) {
7234e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock        mContext = context;
734cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        mHandler = new H();
744cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        mShowDelayMs = getNavBarExitDuration() * 3;
75d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        mPanicThresholdMs = context.getResources()
76f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock                .getInteger(R.integer.config_immersive_mode_confirmation_panic);
77a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        mWindowManager = (WindowManager)
78a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                mContext.getSystemService(Context.WINDOW_SERVICE);
794cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    }
804cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock
814cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    private long getNavBarExitDuration() {
824cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        Animation exit = AnimationUtils.loadAnimation(mContext, R.anim.dock_bottom_exit);
834cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        return exit != null ? exit.getDuration() : 0;
8434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock    }
8534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
864355a533bc9349c84d9ec6d7d67c57b5ca060ecbJohn Spurlock    public void loadSetting(int currentUserId) {
87d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        mConfirmed = false;
884355a533bc9349c84d9ec6d7d67c57b5ca060ecbJohn Spurlock        mCurrentUserId = currentUserId;
89d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s",
90d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false)));
91d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        String value = null;
92d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        try {
93d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            value = Settings.Secure.getStringForUser(mContext.getContentResolver(),
94f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
95d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock                    UserHandle.USER_CURRENT);
96d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            mConfirmed = CONFIRMED.equals(value);
97d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            if (DEBUG) Slog.d(TAG, "Loaded mConfirmed=" + mConfirmed);
98d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        } catch (Throwable t) {
99d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            Slog.w(TAG, "Error loading confirmations, value=" + value, t);
100d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        }
101d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    }
102d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock
103d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    private void saveSetting() {
104d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        if (DEBUG) Slog.d(TAG, "saveSetting()");
105d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        try {
106d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            final String value = mConfirmed ? CONFIRMED : null;
107d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock            Settings.Secure.putStringForUser(mContext.getContentResolver(),
108f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock                    Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
109d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                    value,
110d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock                    UserHandle.USER_CURRENT);
111d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            if (DEBUG) Slog.d(TAG, "Saved value=" + value);
112d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        } catch (Throwable t) {
113d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            Slog.w(TAG, "Error saving confirmations, mConfirmed=" + mConfirmed, t);
114d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        }
115d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    }
116d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock
11799c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam    public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
11899c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam            boolean userSetupComplete) {
1194cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        mHandler.removeMessages(H.SHOW);
120f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock        if (isImmersiveMode) {
121d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
122d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s",
123d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                    disabled, mConfirmed));
12499c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam            if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) {
125d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
12634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock            }
12734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock        } else {
1284cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock            mHandler.sendEmptyMessage(H.HIDE);
12934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock        }
13034e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock    }
13134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
132d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) {
133d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
134d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock            // turning the screen back on within the panic threshold
135d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            mHandler.sendEmptyMessage(H.PANIC);
136d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            return mClingWindow == null;
137d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        }
138f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock        if (isScreenOn && inImmersiveMode) {
139f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock            // turning the screen off, remember if we were in immersive mode
140d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock            mPanicTime = time;
141d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        } else {
142d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock            mPanicTime = 0;
143d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock        }
144d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        return false;
145d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    }
146d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock
147d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    public void confirmCurrentPrompt() {
148d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        if (mClingWindow != null) {
149d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()");
150d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            mHandler.post(mConfirm);
151d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        }
152d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    }
153d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock
154d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    private void handlePanic() {
155d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        if (DEBUG) Slog.d(TAG, "handlePanic()");
156d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        if (mUserPanicResets.get(mCurrentUserId, false)) return;  // already reset for panic
157d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        mUserPanicResets.put(mCurrentUserId, true);
158d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        mConfirmed = false;
159d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        saveSetting();
160d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock    }
161d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock
1624cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    private void handleHide() {
163a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        if (mClingWindow != null) {
164d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
165a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            mWindowManager.removeView(mClingWindow);
166a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            mClingWindow = null;
167a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        }
168a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler    }
169a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
170b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler    public WindowManager.LayoutParams getClingWindowLayoutParams() {
171b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
172b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                ViewGroup.LayoutParams.MATCH_PARENT,
173b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                ViewGroup.LayoutParams.MATCH_PARENT,
17462b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
175b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                0
176b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
177b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
178b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                        | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
179b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                ,
180b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                PixelFormat.TRANSLUCENT);
1810513d5abb6f457cda3a279d63ce02a8fdaa8e32aJohn Spurlock        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
182f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock        lp.setTitle("ImmersiveModeConfirmation");
18362b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos        lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation;
184b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        return lp;
185b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler    }
186b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler
187b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler    public FrameLayout.LayoutParams getBubbleLayoutParams() {
188b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        return new FrameLayout.LayoutParams(
189b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                mContext.getResources().getDimensionPixelSize(
190b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                        R.dimen.immersive_mode_cling_width),
191b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                ViewGroup.LayoutParams.WRAP_CONTENT,
192b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                Gravity.CENTER_HORIZONTAL | Gravity.TOP);
193b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler    }
194b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler
195a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler    private class ClingWindowView extends FrameLayout {
196a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        private static final int BGCOLOR = 0x80000000;
19762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos        private static final int OFFSET_DP = 96;
19862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos        private static final int ANIMATION_DURATION = 250;
199a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
20047e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock        private final Runnable mConfirm;
201a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        private final ColorDrawable mColor = new ColorDrawable(0);
20262b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos        private final Interpolator mInterpolator;
203a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        private ValueAnimator mColorAnim;
204b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        private ViewGroup mClingLayout;
205b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler
206da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler        private Runnable mUpdateLayoutRunnable = new Runnable() {
207da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler            @Override
208da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler            public void run() {
209da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler                if (mClingLayout != null && mClingLayout.getParent() != null) {
210da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler                    mClingLayout.setLayoutParams(getBubbleLayoutParams());
211da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler                }
212da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler            }
213da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler        };
214da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler
215b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        private BroadcastReceiver mReceiver = new BroadcastReceiver() {
216b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler            @Override
217b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler            public void onReceive(Context context, Intent intent) {
218b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
219da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler                    post(mUpdateLayoutRunnable);
220b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler                }
221b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler            }
222b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        };
223a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
22447e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock        public ClingWindowView(Context context, Runnable confirm) {
225a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            super(context);
22647e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock            mConfirm = confirm;
227a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            setBackground(mColor);
22862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos            setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
22962b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos            mInterpolator = AnimationUtils
23062b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                    .loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in);
231a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        }
232a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
233a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        @Override
234a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        public void onAttachedToWindow() {
235a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            super.onAttachedToWindow();
236a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
237a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            DisplayMetrics metrics = new DisplayMetrics();
238a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            mWindowManager.getDefaultDisplay().getMetrics(metrics);
239a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            float density = metrics.density;
240a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
241a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            // create the confirmation cling
242b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler            mClingLayout = (ViewGroup)
243f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock                    View.inflate(getContext(), R.layout.immersive_mode_cling, null);
244a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
245b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler            final Button ok = (Button) mClingLayout.findViewById(R.id.ok);
246a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            ok.setOnClickListener(new OnClickListener() {
247a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                @Override
248a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                public void onClick(View v) {
24947e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock                    mConfirm.run();
250a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                }
251a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            });
252b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler            addView(mClingLayout, getBubbleLayoutParams());
253a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
254a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            if (ActivityManager.isHighEndGfx()) {
25562b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                final View cling = mClingLayout;
25662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                cling.setAlpha(0f);
25762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                cling.setTranslationY(-OFFSET_DP * density);
25862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos
25962b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                postOnAnimation(new Runnable() {
260a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                    @Override
26162b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                    public void run() {
26262b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                        cling.animate()
26362b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                .alpha(1f)
26462b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                .translationY(0)
26562b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                .setDuration(ANIMATION_DURATION)
26662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                .setInterpolator(mInterpolator)
26762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                .withLayer()
26862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                .start();
26962b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos
27062b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                        mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, BGCOLOR);
27162b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                        mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
27262b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                            @Override
27362b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                            public void onAnimationUpdate(ValueAnimator animation) {
27462b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                final int c = (Integer) animation.getAnimatedValue();
27562b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                                mColor.setColor(c);
27662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                            }
27762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                        });
27862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                        mColorAnim.setDuration(ANIMATION_DURATION);
27962b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                        mColorAnim.setInterpolator(mInterpolator);
28062b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                        mColorAnim.start();
281a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                    }
282a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                });
283a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            } else {
284a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                mColor.setColor(BGCOLOR);
285a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            }
286b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler
28762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos            mContext.registerReceiver(mReceiver,
28862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos                    new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
289b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        }
290b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler
291b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        @Override
292b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        public void onDetachedFromWindow() {
293b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler            mContext.unregisterReceiver(mReceiver);
294a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        }
295a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler
296a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        @Override
297a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        public boolean onTouchEvent(MotionEvent motion) {
298a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler            return true;
2994cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        }
3004cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    }
30134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
302d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    private void handleShow() {
303d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation");
304d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock
305d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        mClingWindow = new ClingWindowView(mContext, mConfirm);
30634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
3074cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        // we will be hiding the nav bar, so layout as if it's already hidden
308a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        mClingWindow.setSystemUiVisibility(
309a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
310a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler              | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
3114cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock
3124cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        // show the confirmation
313b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler        WindowManager.LayoutParams lp = getClingWindowLayoutParams();
314a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler        mWindowManager.addView(mClingWindow, lp);
31534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock    }
31634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock
317d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    private final Runnable mConfirm = new Runnable() {
318d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        @Override
319d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        public void run() {
320d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            if (DEBUG) Slog.d(TAG, "mConfirm.run()");
321d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            if (!mConfirmed) {
322d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                mConfirmed = true;
323d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                saveSetting();
32434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock            }
325d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock            handleHide();
326d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        }
327d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock    };
3284cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock
3294cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    private final class H extends Handler {
330d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        private static final int SHOW = 1;
331d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        private static final int HIDE = 2;
332d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock        private static final int PANIC = 3;
3334cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock
3344cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        @Override
3354cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        public void handleMessage(Message msg) {
3364cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock            switch(msg.what) {
3374cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock                case SHOW:
338d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                    handleShow();
3394cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock                    break;
3404cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock                case HIDE:
3414cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock                    handleHide();
3424cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock                    break;
343d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                case PANIC:
344d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                    handlePanic();
345d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock                    break;
3464cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock            }
3474cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock        }
3484cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock    }
34934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock}
350