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 1734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockpackage com.android.internal.policy.impl; 1834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 19a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.animation.ArgbEvaluator; 20a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.animation.ValueAnimator; 21a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.app.ActivityManager; 22d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlockimport android.app.ActivityManagerNative; 23b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandlerimport android.content.BroadcastReceiver; 2434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.content.Context; 25b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandlerimport android.content.Intent; 26b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandlerimport android.content.IntentFilter; 27a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.graphics.PixelFormat; 28a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.graphics.drawable.ColorDrawable; 2934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.os.Handler; 304cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.os.Message; 31d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlockimport android.os.RemoteException; 32d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlockimport android.os.UserHandle; 33d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlockimport android.provider.Settings; 34a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.util.DisplayMetrics; 3534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.util.Slog; 36d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlockimport android.util.SparseBooleanArray; 37a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.Gravity; 38a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.MotionEvent; 3934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport android.view.View; 40a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.ViewGroup; 41a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.WindowManager; 424cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.view.animation.Animation; 434cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlockimport android.view.animation.AnimationUtils; 44a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.view.animation.DecelerateInterpolator; 45a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.widget.Button; 46a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandlerimport android.widget.FrameLayout; 4734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 4834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlockimport com.android.internal.R; 4934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 5034e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock/** 51f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock * Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden 52f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock * entering immersive mode. 5334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock */ 54f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlockpublic class ImmersiveModeConfirmation { 55f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock private static final String TAG = "ImmersiveModeConfirmation"; 564cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private static final boolean DEBUG = false; 57a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution 58d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private static final String CONFIRMED = "confirmed"; 5934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 6034e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock private final Context mContext; 614cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private final H mHandler; 624cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private final long mShowDelayMs; 63d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock private final long mPanicThresholdMs; 64d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private final SparseBooleanArray mUserPanicResets = new SparseBooleanArray(); 6534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 66d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private boolean mConfirmed; 67a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private ClingWindowView mClingWindow; 68d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock private long mPanicTime; 69a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private WindowManager mWindowManager; 70d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private int mCurrentUserId; 7134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 72f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock public ImmersiveModeConfirmation(Context context) { 7334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock mContext = context; 744cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mHandler = new H(); 754cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mShowDelayMs = getNavBarExitDuration() * 3; 76d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock mPanicThresholdMs = context.getResources() 77f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock .getInteger(R.integer.config_immersive_mode_confirmation_panic); 78a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager = (WindowManager) 79a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mContext.getSystemService(Context.WINDOW_SERVICE); 804cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 814cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 824cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private long getNavBarExitDuration() { 834cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock Animation exit = AnimationUtils.loadAnimation(mContext, R.anim.dock_bottom_exit); 844cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock return exit != null ? exit.getDuration() : 0; 8534e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 8634e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 874355a533bc9349c84d9ec6d7d67c57b5ca060ecbJohn Spurlock public void loadSetting(int currentUserId) { 88d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mConfirmed = false; 894355a533bc9349c84d9ec6d7d67c57b5ca060ecbJohn Spurlock mCurrentUserId = currentUserId; 90d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s", 91d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false))); 92d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock String value = null; 93d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock try { 94d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock value = Settings.Secure.getStringForUser(mContext.getContentResolver(), 95f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, 96d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock UserHandle.USER_CURRENT); 97d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mConfirmed = CONFIRMED.equals(value); 98d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Loaded mConfirmed=" + mConfirmed); 99d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } catch (Throwable t) { 100d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock Slog.w(TAG, "Error loading confirmations, value=" + value, t); 101d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 102d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 103d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 104d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock private void saveSetting() { 105d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock if (DEBUG) Slog.d(TAG, "saveSetting()"); 106d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock try { 107d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock final String value = mConfirmed ? CONFIRMED : null; 108d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock Settings.Secure.putStringForUser(mContext.getContentResolver(), 109f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS, 110d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock value, 111d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock UserHandle.USER_CURRENT); 112d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Saved value=" + value); 113d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } catch (Throwable t) { 114d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock Slog.w(TAG, "Error saving confirmations, mConfirmed=" + mConfirmed, t); 115d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 116d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 117d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 11899c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam public void immersiveModeChanged(String pkg, boolean isImmersiveMode, 11999c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam boolean userSetupComplete) { 1204cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mHandler.removeMessages(H.SHOW); 121f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock if (isImmersiveMode) { 122d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg); 123d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s", 124d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock disabled, mConfirmed)); 12599c6e072aa6681b581a4c2308d7cd4a72948e27cMaurice Lam if (!disabled && (DEBUG_SHOW_EVERY_TIME || !mConfirmed) && userSetupComplete) { 126d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs); 12734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 12834e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } else { 1294cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock mHandler.sendEmptyMessage(H.HIDE); 13034e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 13134e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 13234e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 133d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) { 134d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) { 135d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock // turning the screen back on within the panic threshold 136d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mHandler.sendEmptyMessage(H.PANIC); 137d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock return mClingWindow == null; 138d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 139f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock if (isScreenOn && inImmersiveMode) { 140f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock // turning the screen off, remember if we were in immersive mode 141d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock mPanicTime = time; 142d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } else { 143d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock mPanicTime = 0; 144d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 145d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock return false; 146d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 147d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 148d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock public void confirmCurrentPrompt() { 149d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (mClingWindow != null) { 150d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()"); 151d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mHandler.post(mConfirm); 152d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock } 153d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock } 154d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock 155d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private void handlePanic() { 156d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "handlePanic()"); 157d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (mUserPanicResets.get(mCurrentUserId, false)) return; // already reset for panic 158d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mUserPanicResets.put(mCurrentUserId, true); 159d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mConfirmed = false; 160d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock saveSetting(); 161d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock } 162d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 1634cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private void handleHide() { 164a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler if (mClingWindow != null) { 165d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation"); 166a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager.removeView(mClingWindow); 167a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mClingWindow = null; 168a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 169a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 170a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 171b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler public WindowManager.LayoutParams getClingWindowLayoutParams() { 172b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 173b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler ViewGroup.LayoutParams.MATCH_PARENT, 174b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler ViewGroup.LayoutParams.MATCH_PARENT, 175b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler WindowManager.LayoutParams.TYPE_TOAST, 176b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 0 177b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN 178b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 179b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED 180b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler , 181b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler PixelFormat.TRANSLUCENT); 1820513d5abb6f457cda3a279d63ce02a8fdaa8e32aJohn Spurlock lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 183f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock lp.setTitle("ImmersiveModeConfirmation"); 184b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; 185b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler lp.gravity = Gravity.FILL; 186b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler return lp; 187b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 188b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 189b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler public FrameLayout.LayoutParams getBubbleLayoutParams() { 190b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler return new FrameLayout.LayoutParams( 191b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler mContext.getResources().getDimensionPixelSize( 192b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler R.dimen.immersive_mode_cling_width), 193b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler ViewGroup.LayoutParams.WRAP_CONTENT, 194b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler Gravity.CENTER_HORIZONTAL | Gravity.TOP); 195b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 196b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 197a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private class ClingWindowView extends FrameLayout { 198a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private static final int BGCOLOR = 0x80000000; 199a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private static final int OFFSET_DP = 48; 200a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 20147e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock private final Runnable mConfirm; 202a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler private final ColorDrawable mColor = new ColorDrawable(0); 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 setClickable(true); 228a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler setBackground(mColor); 229a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 230a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 231a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 232a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler public void onAttachedToWindow() { 233a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler super.onAttachedToWindow(); 234a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 235a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler DisplayMetrics metrics = new DisplayMetrics(); 236a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager.getDefaultDisplay().getMetrics(metrics); 237a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler float density = metrics.density; 238a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 239a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler // create the confirmation cling 240b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler mClingLayout = (ViewGroup) 241f1a36648ca099d7ffa8a19e403673820d4b8417aJohn Spurlock View.inflate(getContext(), R.layout.immersive_mode_cling, null); 242a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 243b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler final Button ok = (Button) mClingLayout.findViewById(R.id.ok); 244a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler ok.setOnClickListener(new OnClickListener() { 245a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 246a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler public void onClick(View v) { 24747e3de2baa59b6d8ad7de0f569a814877f287a7eJohn Spurlock mConfirm.run(); 248a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 249a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler }); 250b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler addView(mClingLayout, getBubbleLayoutParams()); 251a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 252a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler if (ActivityManager.isHighEndGfx()) { 253b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler final View bubble = mClingLayout.findViewById(R.id.text); 254a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler bubble.setAlpha(0f); 255a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler bubble.setTranslationY(-OFFSET_DP*density); 256a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler bubble.animate() 257a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .alpha(1f) 258a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .translationY(0) 259a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .setDuration(300) 260a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .setInterpolator(new DecelerateInterpolator()) 261a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .start(); 262a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 263a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler ok.setAlpha(0f); 264a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler ok.setTranslationY(-OFFSET_DP*density); 265a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler ok.animate().alpha(1f) 266a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .translationY(0) 267a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .setDuration(300) 268a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .setStartDelay(200) 269a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .setInterpolator(new DecelerateInterpolator()) 270a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler .start(); 271a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 272a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mColorAnim = ValueAnimator.ofObject(new ArgbEvaluator(), 0, BGCOLOR); 273a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mColorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 274a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 275a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler public void onAnimationUpdate(ValueAnimator animation) { 276a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler final int c = (Integer) animation.getAnimatedValue(); 277a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mColor.setColor(c); 278a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 279a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler }); 280a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mColorAnim.setDuration(1000); 281a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mColorAnim.start(); 282a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } else { 283a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mColor.setColor(BGCOLOR); 284a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 285b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 286b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED)); 287b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler } 288b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler 289b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler @Override 290b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler public void onDetachedFromWindow() { 291b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler mContext.unregisterReceiver(mReceiver); 292a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler } 293a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler 294a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler @Override 295a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler public boolean onTouchEvent(MotionEvent motion) { 296a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler return true; 2974cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 2984cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 29934e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 300d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private void handleShow() { 301d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "Showing immersive mode confirmation"); 302d67ec25a9c4bf728e4805248d0b287cc3c3ab8aeJohn Spurlock 303d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mClingWindow = new ClingWindowView(mContext, mConfirm); 30434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 3054cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock // we will be hiding the nav bar, so layout as if it's already hidden 306a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mClingWindow.setSystemUiVisibility( 307a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 308a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 3094cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 3104cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock // show the confirmation 311b83f5c6a421c476a0f1af6e986a88f073581afd2Daniel Sandler WindowManager.LayoutParams lp = getClingWindowLayoutParams(); 312a953b6d968beba01baad095b9ed2e40dbb97f189Daniel Sandler mWindowManager.addView(mClingWindow, lp); 31334e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 31434e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock 315d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private final Runnable mConfirm = new Runnable() { 316d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock @Override 317d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock public void run() { 318d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (DEBUG) Slog.d(TAG, "mConfirm.run()"); 319d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock if (!mConfirmed) { 320d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock mConfirmed = true; 321d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock saveSetting(); 32234e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock } 323d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock handleHide(); 324d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock } 325d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock }; 3264cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 3274cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock private final class H extends Handler { 328d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private static final int SHOW = 1; 329d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private static final int HIDE = 2; 330d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock private static final int PANIC = 3; 3314cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock 3324cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock @Override 3334cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock public void handleMessage(Message msg) { 3344cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock switch(msg.what) { 3354cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock case SHOW: 336d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock handleShow(); 3374cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock break; 3384cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock case HIDE: 3394cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock handleHide(); 3404cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock break; 341d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock case PANIC: 342d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock handlePanic(); 343d9b70bdc1a1c6f366a8ea0dad909b6573214f4afJohn Spurlock break; 3444cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 3454cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 3464cf6a948f9998204d2bfdceebae89954b2b4ae7eJohn Spurlock } 34734e13d90eda9bfda7a70998d190a95c88aa3d3d1John Spurlock} 348