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