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; 393e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roosimport android.view.ViewTreeObserver; 40a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.WindowManager; 414cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.view.animation.Animation; 424cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.view.animation.AnimationUtils; 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; 6334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 64d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private boolean mConfirmed; 65a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private ClingWindowView mClingWindow; 66d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock private long mPanicTime; 67a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private WindowManager mWindowManager; 68d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private int mCurrentUserId; 6934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 70f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock public ImmersiveModeConfirmation(Context context) { 7134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock mContext = context; 724cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mHandler = new H(); 734cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mShowDelayMs = getNavBarExitDuration() * 3; 74d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock mPanicThresholdMs = context.getResources() 75f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock .getInteger(R.integer.config_immersive_mode_confirmation_panic); 76a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager = (WindowManager) 77a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mContext.getSystemService(Context.WINDOW_SERVICE); 784cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 794cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 804cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private long getNavBarExitDuration() { 814cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock Animation exit = AnimationUtils.loadAnimation(mContext, R.anim.dock_bottom_exit); 824cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock return exit != null ? exit.getDuration() : 0; 8334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 8434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 854355a533bc9349c84d9ec6d7d67c57b5ca060ecbJohn Spurlock public void loadSetting(int currentUserId) { 86d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mConfirmed = false; 874355a533bc9349c84d9ec6d7d67c57b5ca060ecbJohn Spurlock mCurrentUserId = currentUserId; 88c5d8fbcd2eb78b909f2282b9924992babd198b00Adrian Roos if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d", mCurrentUserId)); 89d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock String value = null; 90d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock try { 91d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock value = Settings.Secure.getStringForUser(mContext.getContentResolver(), 92f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, 93d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock UserHandle.USER_CURRENT); 94d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mConfirmed = CONFIRMED.equals(value); 95d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Loaded mConfirmed=" + mConfirmed); 96d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } catch (Throwable t) { 97d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock Slog.w(TAG, "Error loading confirmations, value=" + value, t); 98d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 99d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 100d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 101d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock private void saveSetting() { 102d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock if (DEBUG) Slog.d(TAG, "saveSetting()"); 103d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock try { 104d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock final String value = mConfirmed ? CONFIRMED : null; 105d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock Settings.Secure.putStringForUser(mContext.getContentResolver(), 106f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, 107d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock value, 108d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock UserHandle.USER_CURRENT); 109d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Saved value=" + value); 110d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } catch (Throwable t) { 111d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock Slog.w(TAG, "Error saving confirmations, mConfirmed=" + mConfirmed, t); 112d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 113d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 114d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 11599c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam public void immersiveModeChanged(String pkg, boolean isImmersiveMode, 11699c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam boolean userSetupComplete) { 1174cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mHandler.removeMessages(H.SHOW); 118f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock if (isImmersiveMode) { 119d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg); 120d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s", 121d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock disabled, mConfirmed)); 12299c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) { 123d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs); 12434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 12534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } else { 1264cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mHandler.sendEmptyMessage(H.HIDE); 12734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 12834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 12934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 130d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) { 131d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) { 132d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock // turning the screen back on within the panic threshold 133d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock return mClingWindow == null; 134d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 135f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock if (isScreenOn && inImmersiveMode) { 136f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock // turning the screen off, remember if we were in immersive mode 137d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock mPanicTime = time; 138d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } else { 139d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock mPanicTime = 0; 140d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 141d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock return false; 142d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 143d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 144d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock public void confirmCurrentPrompt() { 145d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (mClingWindow != null) { 146d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()"); 147d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mHandler.post(mConfirm); 148d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock } 149d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock } 150d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock 1514cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private void handleHide() { 152a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler if (mClingWindow != null) { 153d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation"); 154a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager.removeView(mClingWindow); 155a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mClingWindow = null; 156a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 157a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 158a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 159b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler public WindowManager.LayoutParams getClingWindowLayoutParams() { 160b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 161b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler ViewGroup.LayoutParams.MATCH_PARENT, 162b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler ViewGroup.LayoutParams.MATCH_PARENT, 16362b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, 164b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 0 165b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 166b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 167b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED 168b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler , 169b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler PixelFormat.TRANSLUCENT); 1700513d5abb6f457cda3a279d63ce02a8fdaa8e32aJohn Spurlock lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 171f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock lp.setTitle("ImmersiveModeConfirmation"); 17262b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos lp.windowAnimations = com.android.internal.R.style.Animation_ImmersiveModeConfirmation; 173b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler return lp; 174b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 175b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 176b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler public FrameLayout.LayoutParams getBubbleLayoutParams() { 177b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler return new FrameLayout.LayoutParams( 178b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler mContext.getResources().getDimensionPixelSize( 179b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler R.dimen.immersive_mode_cling_width), 180b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler ViewGroup.LayoutParams.WRAP_CONTENT, 181b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler Gravity.CENTER_HORIZONTAL | Gravity.TOP); 182b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 183b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 184a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private class ClingWindowView extends FrameLayout { 185a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private static final int BGCOLOR = 0x80000000; 18662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos private static final int OFFSET_DP = 96; 18762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos private static final int ANIMATION_DURATION = 250; 188a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 18947e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock private final Runnable mConfirm; 190a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private final ColorDrawable mColor = new ColorDrawable(0); 19162b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos private final Interpolator mInterpolator; 192a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private ValueAnimator mColorAnim; 193b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler private ViewGroup mClingLayout; 194b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 195da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler private Runnable mUpdateLayoutRunnable = new Runnable() { 196da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler @Override 197da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler public void run() { 198da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler if (mClingLayout != null && mClingLayout.getParent() != null) { 199da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler mClingLayout.setLayoutParams(getBubbleLayoutParams()); 200da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler } 201da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler } 202da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler }; 203da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler 2043e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos private ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = 2053e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos new ViewTreeObserver.OnComputeInternalInsetsListener() { 2063e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos private final int[] mTmpInt2 = new int[2]; 2073e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos 2083e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos @Override 2093e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos public void onComputeInternalInsets( 2103e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos ViewTreeObserver.InternalInsetsInfo inoutInfo) { 2113e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos // Set touchable region to cover the cling layout. 2123e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos mClingLayout.getLocationInWindow(mTmpInt2); 2133e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos inoutInfo.setTouchableInsets( 2143e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION); 2153e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos inoutInfo.touchableRegion.set( 2163e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos mTmpInt2[0], 2173e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos mTmpInt2[1], 2183e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos mTmpInt2[0] + mClingLayout.getWidth(), 2193e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos mTmpInt2[1] + mClingLayout.getHeight()); 2203e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos } 2213e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos }; 2223e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos 223b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler private BroadcastReceiver mReceiver = new BroadcastReceiver() { 224b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler @Override 225b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler public void onReceive(Context context, Intent intent) { 226b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) { 227da35dded4d7882567eab913b25a7cf2f456d2543Daniel Sandler post(mUpdateLayoutRunnable); 228b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 229b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 230b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler }; 231a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 23247e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock public ClingWindowView(Context context, Runnable confirm) { 233a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler super(context); 23447e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock mConfirm = confirm; 235a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler setBackground(mColor); 23662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); 23762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mInterpolator = AnimationUtils 23862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos .loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in); 239a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 240a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 241a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 242a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler public void onAttachedToWindow() { 243a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler super.onAttachedToWindow(); 244a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 245a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler DisplayMetrics metrics = new DisplayMetrics(); 246a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager.getDefaultDisplay().getMetrics(metrics); 247a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler float density = metrics.density; 248a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 2493e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener); 2503e8dd514a08773f3da306ca7b27ec4f71ecf7883Adrian Roos 251a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler // create the confirmation cling 252b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler mClingLayout = (ViewGroup) 253f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock View.inflate(getContext(), R.layout.immersive_mode_cling, null); 254a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 255b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler final Button ok = (Button) mClingLayout.findViewById(R.id.ok); 256a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler ok.setOnClickListener(new OnClickListener() { 257a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 258a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler public void onClick(View v) { 25947e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock mConfirm.run(); 260a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 261a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler }); 262b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler addView(mClingLayout, getBubbleLayoutParams()); 263a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 264a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler if (ActivityManager.isHighEndGfx()) { 26562b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos final View cling = mClingLayout; 26662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos cling.setAlpha(0f); 26762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos cling.setTranslationY(-OFFSET_DP * density); 26862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos 26962b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos postOnAnimation(new Runnable() { 270a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 27162b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos public void run() { 27262b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos cling.animate() 27362b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos .alpha(1f) 27462b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos .translationY(0) 27562b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos .setDuration(ANIMATION_DURATION) 27662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos .setInterpolator(mInterpolator) 27762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos .withLayer() 27862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos .start(); 27962b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos 28062b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, BGCOLOR); 28162b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 28262b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos @Override 28362b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos public void onAnimationUpdate(ValueAnimator animation) { 28462b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos final int c = (Integer) animation.getAnimatedValue(); 28562b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mColor.setColor(c); 28662b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos } 28762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos }); 28862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mColorAnim.setDuration(ANIMATION_DURATION); 28962b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mColorAnim.setInterpolator(mInterpolator); 29062b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mColorAnim.start(); 291a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 292a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler }); 293a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } else { 294a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mColor.setColor(BGCOLOR); 295a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 296b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 29762b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos mContext.registerReceiver(mReceiver, 29862b65e4a8f058787eb49ec1630dfca2d9cd2b751Adrian Roos new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED)); 299b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 300b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 301b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler @Override 302b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler public void onDetachedFromWindow() { 303b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler mContext.unregisterReceiver(mReceiver); 304a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 305a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 306a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 307a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler public boolean onTouchEvent(MotionEvent motion) { 308a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler return true; 3094cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 3104cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 31134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 312d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private void handleShow() { 313d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation"); 314d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 315d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mClingWindow = new ClingWindowView(mContext, mConfirm); 31634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 3174cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock // we will be hiding the nav bar, so layout as if it's already hidden 318a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mClingWindow.setSystemUiVisibility( 319a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 320a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 3214cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 3224cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock // show the confirmation 323b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler WindowManager.LayoutParams lp = getClingWindowLayoutParams(); 324a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager.addView(mClingWindow, lp); 32534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 32634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 327d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private final Runnable mConfirm = new Runnable() { 328d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock @Override 329d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock public void run() { 330d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "mConfirm.run()"); 331d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (!mConfirmed) { 332d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mConfirmed = true; 333d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock saveSetting(); 33434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 335d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock handleHide(); 336d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock } 337d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock }; 3384cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 3394cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private final class H extends Handler { 340d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private static final int SHOW = 1; 341d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private static final int HIDE = 2; 3424cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 3434cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock @Override 3444cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock public void handleMessage(Message msg) { 3454cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock switch(msg.what) { 3464cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock case SHOW: 347d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock handleShow(); 3484cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock break; 3494cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock case HIDE: 3504cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock handleHide(); 3514cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock break; 3524cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 3534cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 3544cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 35534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock} 356