nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 16 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 17 | package com.android.nfc.beam; |
| 18 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 19 | import com.android.nfc.R; |
| 20 | import com.android.nfc.beam.FireflyRenderer; |
| 21 | |
| 22 | import android.animation.Animator; |
| 23 | import android.animation.AnimatorSet; |
| 24 | import android.animation.ObjectAnimator; |
| 25 | import android.animation.PropertyValuesHolder; |
| 26 | import android.animation.TimeAnimator; |
| 27 | import android.app.ActivityManager; |
| 28 | import android.app.StatusBarManager; |
nxpandroid | b781980 | 2017-09-14 11:55:40 +0530 | [diff] [blame] | 29 | import android.content.BroadcastReceiver; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 30 | import android.content.Context; |
nxpandroid | b781980 | 2017-09-14 11:55:40 +0530 | [diff] [blame] | 31 | import android.content.Intent; |
| 32 | import android.content.IntentFilter; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 33 | import android.content.pm.ActivityInfo; |
| 34 | import android.content.res.Configuration; |
| 35 | import android.graphics.Bitmap; |
| 36 | import android.graphics.Canvas; |
| 37 | import android.graphics.Matrix; |
| 38 | import android.graphics.PixelFormat; |
Ganesh Deva | 0e6fd38 | 2018-08-07 13:13:23 +0530 | [diff] [blame] | 39 | import android.graphics.Rect; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 40 | import android.graphics.SurfaceTexture; |
| 41 | import android.os.AsyncTask; |
| 42 | import android.os.Binder; |
| 43 | import android.util.DisplayMetrics; |
| 44 | import android.util.Log; |
| 45 | import android.view.ActionMode; |
| 46 | import android.view.Display; |
| 47 | import android.view.KeyEvent; |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 48 | import android.view.KeyboardShortcutGroup; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 49 | import android.view.LayoutInflater; |
| 50 | import android.view.Menu; |
| 51 | import android.view.MenuItem; |
| 52 | import android.view.MotionEvent; |
nxpandroid | 1153eb3 | 2015-11-06 18:46:58 +0530 | [diff] [blame] | 53 | import com.android.internal.policy.PhoneWindow; |
| 54 | import android.view.SearchEvent; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 55 | import android.view.Surface; |
| 56 | import android.view.SurfaceControl; |
| 57 | import android.view.TextureView; |
| 58 | import android.view.View; |
| 59 | import android.view.ViewGroup; |
| 60 | import android.view.Window; |
| 61 | import android.view.WindowManager; |
| 62 | import android.view.WindowManager.LayoutParams; |
| 63 | import android.view.accessibility.AccessibilityEvent; |
| 64 | import android.view.animation.AccelerateDecelerateInterpolator; |
| 65 | import android.view.animation.DecelerateInterpolator; |
| 66 | import android.widget.ImageView; |
| 67 | import android.widget.TextView; |
| 68 | import android.widget.Toast; |
| 69 | |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 70 | import java.util.List; |
| 71 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 72 | /** |
| 73 | * This class is responsible for handling the UI animation |
| 74 | * around Android Beam. The animation consists of the following |
| 75 | * animators: |
| 76 | * |
| 77 | * mPreAnimator: scales the screenshot down to INTERMEDIATE_SCALE |
| 78 | * mSlowSendAnimator: scales the screenshot down to 0.2f (used as a "send in progress" animation) |
| 79 | * mFastSendAnimator: quickly scales the screenshot down to 0.0f (used for send success) |
| 80 | * mFadeInAnimator: fades the current activity back in (used after mFastSendAnimator completes) |
| 81 | * mScaleUpAnimator: scales the screenshot back up to full screen (used for failure or receiving) |
| 82 | * mHintAnimator: Slowly turns up the alpha of the "Touch to Beam" hint |
| 83 | * |
| 84 | * Possible sequences are: |
| 85 | * |
| 86 | * mPreAnimator => mSlowSendAnimator => mFastSendAnimator => mFadeInAnimator (send success) |
| 87 | * mPreAnimator => mSlowSendAnimator => mScaleUpAnimator (send failure) |
| 88 | * mPreAnimator => mScaleUpAnimator (p2p link broken, or data received) |
| 89 | * |
| 90 | * Note that mFastSendAnimator and mFadeInAnimator are combined in a set, as they |
| 91 | * are an atomic animation that cannot be interrupted. |
| 92 | * |
| 93 | * All methods of this class must be called on the UI thread |
| 94 | */ |
| 95 | public class SendUi implements Animator.AnimatorListener, View.OnTouchListener, |
| 96 | TimeAnimator.TimeListener, TextureView.SurfaceTextureListener, android.view.Window.Callback { |
| 97 | static final String TAG = "SendUi"; |
| 98 | |
| 99 | static final float INTERMEDIATE_SCALE = 0.6f; |
| 100 | |
| 101 | static final float[] PRE_SCREENSHOT_SCALE = {1.0f, INTERMEDIATE_SCALE}; |
| 102 | static final int PRE_DURATION_MS = 350; |
| 103 | |
| 104 | static final float[] SEND_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 0.2f}; |
| 105 | static final int SLOW_SEND_DURATION_MS = 8000; // Stretch out sending over 8s |
| 106 | static final int FAST_SEND_DURATION_MS = 350; |
| 107 | |
| 108 | static final float[] SCALE_UP_SCREENSHOT_SCALE = {INTERMEDIATE_SCALE, 1.0f}; |
| 109 | static final int SCALE_UP_DURATION_MS = 300; |
| 110 | |
| 111 | static final int FADE_IN_DURATION_MS = 250; |
| 112 | static final int FADE_IN_START_DELAY_MS = 350; |
| 113 | |
| 114 | static final int SLIDE_OUT_DURATION_MS = 300; |
| 115 | |
| 116 | static final float[] BLACK_LAYER_ALPHA_DOWN_RANGE = {0.9f, 0.0f}; |
| 117 | static final float[] BLACK_LAYER_ALPHA_UP_RANGE = {0.0f, 0.9f}; |
| 118 | |
| 119 | static final float[] TEXT_HINT_ALPHA_RANGE = {0.0f, 1.0f}; |
| 120 | static final int TEXT_HINT_ALPHA_DURATION_MS = 500; |
| 121 | static final int TEXT_HINT_ALPHA_START_DELAY_MS = 300; |
| 122 | |
| 123 | public static final int FINISH_SCALE_UP = 0; |
| 124 | public static final int FINISH_SEND_SUCCESS = 1; |
| 125 | |
| 126 | static final int STATE_IDLE = 0; |
| 127 | static final int STATE_W4_SCREENSHOT = 1; |
| 128 | static final int STATE_W4_SCREENSHOT_PRESEND_REQUESTED = 2; |
| 129 | static final int STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED = 3; |
| 130 | static final int STATE_W4_SCREENSHOT_THEN_STOP = 4; |
| 131 | static final int STATE_W4_PRESEND = 5; |
| 132 | static final int STATE_W4_TOUCH = 6; |
| 133 | static final int STATE_W4_NFC_TAP = 7; |
| 134 | static final int STATE_SENDING = 8; |
| 135 | static final int STATE_COMPLETE = 9; |
| 136 | |
| 137 | // all members are only used on UI thread |
| 138 | final WindowManager mWindowManager; |
| 139 | final Context mContext; |
| 140 | final Display mDisplay; |
| 141 | final DisplayMetrics mDisplayMetrics; |
| 142 | final Matrix mDisplayMatrix; |
| 143 | final WindowManager.LayoutParams mWindowLayoutParams; |
| 144 | final LayoutInflater mLayoutInflater; |
| 145 | final StatusBarManager mStatusBarManager; |
| 146 | final View mScreenshotLayout; |
| 147 | final ImageView mScreenshotView; |
| 148 | final ImageView mBlackLayer; |
| 149 | final TextureView mTextureView; |
| 150 | final TextView mTextHint; |
| 151 | final TextView mTextRetry; |
| 152 | final Callback mCallback; |
| 153 | |
| 154 | // The mFrameCounter animation is purely used to count down a certain |
| 155 | // number of (vsync'd) frames. This is needed because the first 3 |
| 156 | // times the animation internally calls eglSwapBuffers(), large buffers |
| 157 | // are allocated by the graphics drivers. This causes the animation |
| 158 | // to look janky. So on platforms where we can use hardware acceleration, |
| 159 | // the animation order is: |
| 160 | // Wait for hw surface => start frame counter => start pre-animation after 3 frames |
| 161 | // For platforms where no hw acceleration can be used, the pre-animation |
| 162 | // is started immediately. |
| 163 | final TimeAnimator mFrameCounterAnimator; |
| 164 | |
| 165 | final ObjectAnimator mPreAnimator; |
| 166 | final ObjectAnimator mSlowSendAnimator; |
| 167 | final ObjectAnimator mFastSendAnimator; |
| 168 | final ObjectAnimator mFadeInAnimator; |
| 169 | final ObjectAnimator mHintAnimator; |
| 170 | final ObjectAnimator mScaleUpAnimator; |
| 171 | final ObjectAnimator mAlphaDownAnimator; |
| 172 | final ObjectAnimator mAlphaUpAnimator; |
| 173 | final AnimatorSet mSuccessAnimatorSet; |
| 174 | |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 175 | // Besides animating the screenshot, the Beam UI also renders |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 176 | // fireflies on platforms where we can do hardware-acceleration. |
| 177 | // Firefly rendering is only started once the initial |
| 178 | // "pre-animation" has scaled down the screenshot, to avoid |
| 179 | // that animation becoming janky. Likewise, the fireflies are |
| 180 | // stopped in their tracks as soon as we finish the animation, |
| 181 | // to make the finishing animation smooth. |
| 182 | final boolean mHardwareAccelerated; |
| 183 | final FireflyRenderer mFireflyRenderer; |
| 184 | |
| 185 | String mToastString; |
| 186 | Bitmap mScreenshotBitmap; |
| 187 | |
| 188 | int mState; |
| 189 | int mRenderedFrames; |
| 190 | |
| 191 | View mDecor; |
| 192 | |
| 193 | // Used for holding the surface |
| 194 | SurfaceTexture mSurface; |
| 195 | int mSurfaceWidth; |
| 196 | int mSurfaceHeight; |
| 197 | |
| 198 | public interface Callback { |
| 199 | public void onSendConfirmed(); |
| 200 | public void onCanceled(); |
| 201 | } |
| 202 | |
| 203 | public SendUi(Context context, Callback callback) { |
| 204 | mContext = context; |
| 205 | mCallback = callback; |
| 206 | |
| 207 | mDisplayMetrics = new DisplayMetrics(); |
| 208 | mDisplayMatrix = new Matrix(); |
| 209 | mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); |
| 210 | mStatusBarManager = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); |
| 211 | |
| 212 | mDisplay = mWindowManager.getDefaultDisplay(); |
| 213 | |
| 214 | mLayoutInflater = (LayoutInflater) |
| 215 | context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
| 216 | mScreenshotLayout = mLayoutInflater.inflate(R.layout.screenshot, null); |
| 217 | |
| 218 | mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.screenshot); |
| 219 | mScreenshotLayout.setFocusable(true); |
| 220 | |
| 221 | mTextHint = (TextView) mScreenshotLayout.findViewById(R.id.calltoaction); |
| 222 | mTextRetry = (TextView) mScreenshotLayout.findViewById(R.id.retrytext); |
| 223 | mBlackLayer = (ImageView) mScreenshotLayout.findViewById(R.id.blacklayer); |
| 224 | mTextureView = (TextureView) mScreenshotLayout.findViewById(R.id.fireflies); |
| 225 | mTextureView.setSurfaceTextureListener(this); |
| 226 | |
| 227 | // We're only allowed to use hardware acceleration if |
| 228 | // isHighEndGfx() returns true - otherwise, we're too limited |
| 229 | // on resources to do it. |
| 230 | mHardwareAccelerated = ActivityManager.isHighEndGfx(); |
| 231 | int hwAccelerationFlags = mHardwareAccelerated ? |
| 232 | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED : 0; |
| 233 | |
| 234 | mWindowLayoutParams = new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, |
| 235 | ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, |
| 236 | WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, |
| 237 | WindowManager.LayoutParams.FLAG_FULLSCREEN |
| 238 | | hwAccelerationFlags |
| 239 | | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, |
| 240 | PixelFormat.OPAQUE); |
| 241 | mWindowLayoutParams.privateFlags |= |
| 242 | WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; |
| 243 | mWindowLayoutParams.token = new Binder(); |
| 244 | |
| 245 | mFrameCounterAnimator = new TimeAnimator(); |
| 246 | mFrameCounterAnimator.setTimeListener(this); |
| 247 | |
| 248 | PropertyValuesHolder preX = PropertyValuesHolder.ofFloat("scaleX", PRE_SCREENSHOT_SCALE); |
| 249 | PropertyValuesHolder preY = PropertyValuesHolder.ofFloat("scaleY", PRE_SCREENSHOT_SCALE); |
| 250 | mPreAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, preX, preY); |
| 251 | mPreAnimator.setInterpolator(new DecelerateInterpolator()); |
| 252 | mPreAnimator.setDuration(PRE_DURATION_MS); |
| 253 | mPreAnimator.addListener(this); |
| 254 | |
| 255 | PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", SEND_SCREENSHOT_SCALE); |
| 256 | PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", SEND_SCREENSHOT_SCALE); |
| 257 | PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha", |
| 258 | new float[]{1.0f, 0.0f}); |
| 259 | |
| 260 | mSlowSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX, postY); |
| 261 | mSlowSendAnimator.setInterpolator(new DecelerateInterpolator()); |
| 262 | mSlowSendAnimator.setDuration(SLOW_SEND_DURATION_MS); |
| 263 | |
| 264 | mFastSendAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, postX, |
| 265 | postY, alphaDown); |
| 266 | mFastSendAnimator.setInterpolator(new DecelerateInterpolator()); |
| 267 | mFastSendAnimator.setDuration(FAST_SEND_DURATION_MS); |
| 268 | mFastSendAnimator.addListener(this); |
| 269 | |
| 270 | PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", SCALE_UP_SCREENSHOT_SCALE); |
| 271 | PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", SCALE_UP_SCREENSHOT_SCALE); |
| 272 | |
| 273 | mScaleUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, scaleUpX, scaleUpY); |
| 274 | mScaleUpAnimator.setInterpolator(new DecelerateInterpolator()); |
| 275 | mScaleUpAnimator.setDuration(SCALE_UP_DURATION_MS); |
| 276 | mScaleUpAnimator.addListener(this); |
| 277 | |
| 278 | PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha", 1.0f); |
| 279 | mFadeInAnimator = ObjectAnimator.ofPropertyValuesHolder(mScreenshotView, fadeIn); |
| 280 | mFadeInAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); |
| 281 | mFadeInAnimator.setDuration(FADE_IN_DURATION_MS); |
| 282 | mFadeInAnimator.setStartDelay(FADE_IN_START_DELAY_MS); |
| 283 | mFadeInAnimator.addListener(this); |
| 284 | |
| 285 | PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha", TEXT_HINT_ALPHA_RANGE); |
| 286 | mHintAnimator = ObjectAnimator.ofPropertyValuesHolder(mTextHint, alphaUp); |
| 287 | mHintAnimator.setInterpolator(null); |
| 288 | mHintAnimator.setDuration(TEXT_HINT_ALPHA_DURATION_MS); |
| 289 | mHintAnimator.setStartDelay(TEXT_HINT_ALPHA_START_DELAY_MS); |
| 290 | |
| 291 | alphaDown = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_DOWN_RANGE); |
| 292 | mAlphaDownAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaDown); |
| 293 | mAlphaDownAnimator.setInterpolator(new DecelerateInterpolator()); |
| 294 | mAlphaDownAnimator.setDuration(400); |
| 295 | |
| 296 | alphaUp = PropertyValuesHolder.ofFloat("alpha", BLACK_LAYER_ALPHA_UP_RANGE); |
| 297 | mAlphaUpAnimator = ObjectAnimator.ofPropertyValuesHolder(mBlackLayer, alphaUp); |
| 298 | mAlphaUpAnimator.setInterpolator(new DecelerateInterpolator()); |
| 299 | mAlphaUpAnimator.setDuration(200); |
| 300 | |
| 301 | mSuccessAnimatorSet = new AnimatorSet(); |
| 302 | mSuccessAnimatorSet.playSequentially(mFastSendAnimator, mFadeInAnimator); |
| 303 | |
| 304 | // Create a Window with a Decor view; creating a window allows us to get callbacks |
| 305 | // on key events (which require a decor view to be dispatched). |
| 306 | mContext.setTheme(android.R.style.Theme_Black_NoTitleBar_Fullscreen); |
nxpandroid | 1153eb3 | 2015-11-06 18:46:58 +0530 | [diff] [blame] | 307 | Window window = new PhoneWindow(mContext); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 308 | window.setCallback(this); |
| 309 | window.requestFeature(Window.FEATURE_NO_TITLE); |
| 310 | mDecor = window.getDecorView(); |
| 311 | window.setContentView(mScreenshotLayout, mWindowLayoutParams); |
| 312 | |
| 313 | if (mHardwareAccelerated) { |
| 314 | mFireflyRenderer = new FireflyRenderer(context); |
| 315 | } else { |
| 316 | mFireflyRenderer = null; |
| 317 | } |
| 318 | mState = STATE_IDLE; |
| 319 | } |
| 320 | |
| 321 | public void takeScreenshot() { |
| 322 | // There's no point in taking the screenshot if |
| 323 | // we're still finishing the previous animation. |
| 324 | if (mState >= STATE_W4_TOUCH) { |
| 325 | return; |
| 326 | } |
| 327 | mState = STATE_W4_SCREENSHOT; |
| 328 | new ScreenshotTask().execute(); |
nxpandroid | b781980 | 2017-09-14 11:55:40 +0530 | [diff] [blame] | 329 | |
| 330 | final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); |
| 331 | mContext.registerReceiver(mReceiver, filter); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | /** Show pre-send animation */ |
| 335 | public void showPreSend(boolean promptToNfcTap) { |
| 336 | switch (mState) { |
| 337 | case STATE_IDLE: |
| 338 | Log.e(TAG, "Unexpected showPreSend() in STATE_IDLE"); |
| 339 | return; |
| 340 | case STATE_W4_SCREENSHOT: |
| 341 | // Still waiting for screenshot, store request in state |
| 342 | // and wait for screenshot completion. |
| 343 | if (promptToNfcTap) { |
| 344 | mState = STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED; |
| 345 | } else { |
| 346 | mState = STATE_W4_SCREENSHOT_PRESEND_REQUESTED; |
| 347 | } |
| 348 | return; |
| 349 | case STATE_W4_SCREENSHOT_PRESEND_REQUESTED: |
| 350 | case STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED: |
| 351 | Log.e(TAG, "Unexpected showPreSend() in STATE_W4_SCREENSHOT_PRESEND_REQUESTED"); |
| 352 | return; |
| 353 | case STATE_W4_PRESEND: |
| 354 | // Expected path, continue below |
| 355 | break; |
| 356 | default: |
| 357 | Log.e(TAG, "Unexpected showPreSend() in state " + Integer.toString(mState)); |
| 358 | return; |
| 359 | } |
| 360 | // Update display metrics |
| 361 | mDisplay.getRealMetrics(mDisplayMetrics); |
| 362 | |
| 363 | final int statusBarHeight = mContext.getResources().getDimensionPixelSize( |
| 364 | com.android.internal.R.dimen.status_bar_height); |
| 365 | |
| 366 | mBlackLayer.setVisibility(View.GONE); |
| 367 | mBlackLayer.setAlpha(0f); |
| 368 | mScreenshotLayout.setOnTouchListener(this); |
| 369 | mScreenshotView.setImageBitmap(mScreenshotBitmap); |
| 370 | mScreenshotView.setTranslationX(0f); |
| 371 | mScreenshotView.setAlpha(1.0f); |
| 372 | mScreenshotView.setPadding(0, statusBarHeight, 0, 0); |
| 373 | |
| 374 | mScreenshotLayout.requestFocus(); |
| 375 | |
| 376 | if (promptToNfcTap) { |
| 377 | mTextHint.setText(mContext.getResources().getString(R.string.ask_nfc_tap)); |
| 378 | } else { |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 379 | mTextHint.setText(mContext.getResources().getString(R.string.tap_to_beam)); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 380 | } |
| 381 | mTextHint.setAlpha(0.0f); |
| 382 | mTextHint.setVisibility(View.VISIBLE); |
| 383 | mHintAnimator.start(); |
| 384 | |
| 385 | // Lock the orientation. |
| 386 | // The orientation from the configuration does not specify whether |
| 387 | // the orientation is reverse or not (ie landscape or reverse landscape). |
| 388 | // So we have to use SENSOR_LANDSCAPE or SENSOR_PORTRAIT to make sure |
| 389 | // we lock in portrait / landscape and have the sensor determine |
| 390 | // which way is up. |
| 391 | int orientation = mContext.getResources().getConfiguration().orientation; |
| 392 | |
| 393 | switch (orientation) { |
| 394 | case Configuration.ORIENTATION_LANDSCAPE: |
| 395 | mWindowLayoutParams.screenOrientation = |
| 396 | ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE; |
| 397 | break; |
| 398 | case Configuration.ORIENTATION_PORTRAIT: |
| 399 | mWindowLayoutParams.screenOrientation = |
| 400 | ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; |
| 401 | break; |
| 402 | default: |
| 403 | mWindowLayoutParams.screenOrientation = |
| 404 | ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT; |
| 405 | break; |
| 406 | } |
| 407 | |
| 408 | mWindowManager.addView(mDecor, mWindowLayoutParams); |
| 409 | // Disable statusbar pull-down |
| 410 | mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); |
| 411 | |
| 412 | mToastString = null; |
| 413 | |
| 414 | if (!mHardwareAccelerated) { |
| 415 | mPreAnimator.start(); |
| 416 | } // else, we will start the animation once we get the hardware surface |
| 417 | mState = promptToNfcTap ? STATE_W4_NFC_TAP : STATE_W4_TOUCH; |
| 418 | } |
| 419 | |
| 420 | /** Show starting send animation */ |
| 421 | public void showStartSend() { |
| 422 | if (mState < STATE_SENDING) return; |
| 423 | |
| 424 | mTextRetry.setVisibility(View.GONE); |
| 425 | // Update the starting scale - touchscreen-mashers may trigger |
| 426 | // this before the pre-animation completes. |
| 427 | float currentScale = mScreenshotView.getScaleX(); |
| 428 | PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", |
| 429 | new float[] {currentScale, 0.0f}); |
| 430 | PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", |
| 431 | new float[] {currentScale, 0.0f}); |
| 432 | |
| 433 | mSlowSendAnimator.setValues(postX, postY); |
| 434 | |
| 435 | float currentAlpha = mBlackLayer.getAlpha(); |
| 436 | if (mBlackLayer.isShown() && currentAlpha > 0.0f) { |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 437 | PropertyValuesHolder alphaDown = PropertyValuesHolder.ofFloat("alpha", |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 438 | new float[] {currentAlpha, 0.0f}); |
| 439 | mAlphaDownAnimator.setValues(alphaDown); |
| 440 | mAlphaDownAnimator.start(); |
| 441 | } |
| 442 | mSlowSendAnimator.start(); |
| 443 | } |
| 444 | |
| 445 | public void finishAndToast(int finishMode, String toast) { |
| 446 | mToastString = toast; |
| 447 | |
| 448 | finish(finishMode); |
| 449 | } |
| 450 | |
| 451 | /** Return to initial state */ |
| 452 | public void finish(int finishMode) { |
| 453 | switch (mState) { |
| 454 | case STATE_IDLE: |
| 455 | return; |
| 456 | case STATE_W4_SCREENSHOT: |
| 457 | case STATE_W4_SCREENSHOT_PRESEND_REQUESTED: |
| 458 | case STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED: |
| 459 | // Screenshot is still being captured on a separate thread. |
| 460 | // Update state, and stop everything when the capture is done. |
| 461 | mState = STATE_W4_SCREENSHOT_THEN_STOP; |
| 462 | return; |
| 463 | case STATE_W4_SCREENSHOT_THEN_STOP: |
| 464 | Log.e(TAG, "Unexpected call to finish() in STATE_W4_SCREENSHOT_THEN_STOP"); |
| 465 | return; |
| 466 | case STATE_W4_PRESEND: |
| 467 | // We didn't build up any animation state yet, but |
| 468 | // did store the bitmap. Clear out the bitmap, reset |
| 469 | // state and bail. |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 470 | mScreenshotBitmap = null; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 471 | mState = STATE_IDLE; |
| 472 | return; |
| 473 | default: |
| 474 | // We've started animations and attached a view; tear stuff down below. |
| 475 | break; |
| 476 | } |
| 477 | |
| 478 | // Stop rendering the fireflies |
| 479 | if (mFireflyRenderer != null) { |
| 480 | mFireflyRenderer.stop(); |
| 481 | } |
| 482 | |
| 483 | mTextHint.setVisibility(View.GONE); |
| 484 | mTextRetry.setVisibility(View.GONE); |
| 485 | |
| 486 | float currentScale = mScreenshotView.getScaleX(); |
| 487 | float currentAlpha = mScreenshotView.getAlpha(); |
| 488 | |
| 489 | if (finishMode == FINISH_SCALE_UP) { |
| 490 | mBlackLayer.setVisibility(View.GONE); |
| 491 | PropertyValuesHolder scaleUpX = PropertyValuesHolder.ofFloat("scaleX", |
| 492 | new float[] {currentScale, 1.0f}); |
| 493 | PropertyValuesHolder scaleUpY = PropertyValuesHolder.ofFloat("scaleY", |
| 494 | new float[] {currentScale, 1.0f}); |
| 495 | PropertyValuesHolder scaleUpAlpha = PropertyValuesHolder.ofFloat("alpha", |
| 496 | new float[] {currentAlpha, 1.0f}); |
| 497 | mScaleUpAnimator.setValues(scaleUpX, scaleUpY, scaleUpAlpha); |
| 498 | |
| 499 | mScaleUpAnimator.start(); |
| 500 | } else if (finishMode == FINISH_SEND_SUCCESS){ |
| 501 | // Modify the fast send parameters to match the current scale |
| 502 | PropertyValuesHolder postX = PropertyValuesHolder.ofFloat("scaleX", |
| 503 | new float[] {currentScale, 0.0f}); |
| 504 | PropertyValuesHolder postY = PropertyValuesHolder.ofFloat("scaleY", |
| 505 | new float[] {currentScale, 0.0f}); |
| 506 | PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", |
| 507 | new float[] {currentAlpha, 0.0f}); |
| 508 | mFastSendAnimator.setValues(postX, postY, alpha); |
| 509 | |
| 510 | // Reset the fadeIn parameters to start from alpha 1 |
| 511 | PropertyValuesHolder fadeIn = PropertyValuesHolder.ofFloat("alpha", |
| 512 | new float[] {0.0f, 1.0f}); |
| 513 | mFadeInAnimator.setValues(fadeIn); |
| 514 | |
| 515 | mSlowSendAnimator.cancel(); |
| 516 | mSuccessAnimatorSet.start(); |
| 517 | } |
| 518 | mState = STATE_COMPLETE; |
| 519 | } |
| 520 | |
| 521 | void dismiss() { |
| 522 | if (mState < STATE_W4_TOUCH) return; |
| 523 | // Immediately set to IDLE, to prevent .cancel() calls |
| 524 | // below from immediately calling into dismiss() again. |
| 525 | // (They can do so on the same thread). |
| 526 | mState = STATE_IDLE; |
| 527 | mSurface = null; |
| 528 | mFrameCounterAnimator.cancel(); |
| 529 | mPreAnimator.cancel(); |
| 530 | mSlowSendAnimator.cancel(); |
| 531 | mFastSendAnimator.cancel(); |
| 532 | mSuccessAnimatorSet.cancel(); |
| 533 | mScaleUpAnimator.cancel(); |
| 534 | mAlphaUpAnimator.cancel(); |
| 535 | mAlphaDownAnimator.cancel(); |
| 536 | mWindowManager.removeView(mDecor); |
| 537 | mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); |
nxf50051 | 3a018e7 | 2019-04-23 17:11:41 +0530 | [diff] [blame] | 538 | mScreenshotBitmap = null; |
nxpandroid | b781980 | 2017-09-14 11:55:40 +0530 | [diff] [blame] | 539 | mContext.unregisterReceiver(mReceiver); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 540 | if (mToastString != null) { |
nxpandroid | 6fd9cdb | 2017-07-12 18:25:41 +0530 | [diff] [blame] | 541 | Toast toast = Toast.makeText(mContext, mToastString, Toast.LENGTH_LONG); |
| 542 | toast.getWindowParams().privateFlags |= LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; |
| 543 | toast.show(); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 544 | } |
| 545 | mToastString = null; |
| 546 | } |
| 547 | |
| 548 | /** |
| 549 | * @return the current display rotation in degrees |
| 550 | */ |
| 551 | static float getDegreesForRotation(int value) { |
| 552 | switch (value) { |
| 553 | case Surface.ROTATION_90: |
| 554 | return 90f; |
| 555 | case Surface.ROTATION_180: |
| 556 | return 180f; |
| 557 | case Surface.ROTATION_270: |
| 558 | return 270f; |
| 559 | } |
| 560 | return 0f; |
| 561 | } |
| 562 | |
| 563 | final class ScreenshotTask extends AsyncTask<Void, Void, Bitmap> { |
| 564 | @Override |
| 565 | protected Bitmap doInBackground(Void... params) { |
| 566 | return createScreenshot(); |
| 567 | } |
| 568 | |
| 569 | @Override |
| 570 | protected void onPostExecute(Bitmap result) { |
| 571 | if (mState == STATE_W4_SCREENSHOT) { |
| 572 | // Screenshot done, wait for request to start preSend anim |
nxpandroid | 1153eb3 | 2015-11-06 18:46:58 +0530 | [diff] [blame] | 573 | mScreenshotBitmap = result; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 574 | mState = STATE_W4_PRESEND; |
| 575 | } else if (mState == STATE_W4_SCREENSHOT_THEN_STOP) { |
| 576 | // We were asked to finish, move to idle state and exit |
| 577 | mState = STATE_IDLE; |
| 578 | } else if (mState == STATE_W4_SCREENSHOT_PRESEND_REQUESTED || |
| 579 | mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED) { |
| 580 | if (result != null) { |
| 581 | mScreenshotBitmap = result; |
| 582 | boolean requestTap = (mState == STATE_W4_SCREENSHOT_PRESEND_NFC_TAP_REQUESTED); |
| 583 | mState = STATE_W4_PRESEND; |
| 584 | showPreSend(requestTap); |
| 585 | } else { |
| 586 | // Failed to take screenshot; reset state to idle |
| 587 | // and don't do anything |
| 588 | Log.e(TAG, "Failed to create screenshot"); |
| 589 | mState = STATE_IDLE; |
| 590 | } |
| 591 | } else { |
| 592 | Log.e(TAG, "Invalid state on screenshot completion: " + Integer.toString(mState)); |
| 593 | } |
| 594 | } |
| 595 | }; |
| 596 | |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 597 | /** |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 598 | * Returns a screenshot of the current display contents. |
| 599 | */ |
| 600 | Bitmap createScreenshot() { |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 601 | boolean hasNavBar = mContext.getResources().getBoolean( |
| 602 | com.android.internal.R.bool.config_showNavigationBar); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 603 | final int statusBarHeight = mContext.getResources().getDimensionPixelSize( |
| 604 | com.android.internal.R.dimen.status_bar_height); |
| 605 | |
| 606 | // Navbar has different sizes, depending on orientation |
| 607 | final int navBarHeight = hasNavBar ? mContext.getResources().getDimensionPixelSize( |
| 608 | com.android.internal.R.dimen.navigation_bar_height) : 0; |
| 609 | final int navBarHeightLandscape = hasNavBar ? mContext.getResources().getDimensionPixelSize( |
| 610 | com.android.internal.R.dimen.navigation_bar_height_landscape) : 0; |
| 611 | |
| 612 | final int navBarWidth = hasNavBar ? mContext.getResources().getDimensionPixelSize( |
| 613 | com.android.internal.R.dimen.navigation_bar_width) : 0; |
| 614 | |
Ganesh Deva | 0e6fd38 | 2018-08-07 13:13:23 +0530 | [diff] [blame] | 615 | mDisplay.getRealMetrics(mDisplayMetrics); |
| 616 | float smallestWidth = (float)Math.min(mDisplayMetrics.widthPixels, |
| 617 | mDisplayMetrics.heightPixels); |
| 618 | float smallestWidthDp = smallestWidth / (mDisplayMetrics.densityDpi / 160f); |
| 619 | |
| 620 | int rot = mDisplay.getRotation(); |
| 621 | |
| 622 | // TODO this is somewhat device-specific; need generic solution. |
| 623 | // The starting crop for the screenshot is the fullscreen without the status bar, which |
| 624 | // is always on top. The conditional check will determine how to crop the navbar, |
| 625 | // depending on orienation and screen size. |
| 626 | Rect crop = new Rect(0, statusBarHeight, mDisplayMetrics.widthPixels, |
| 627 | mDisplayMetrics.heightPixels); |
| 628 | if (mDisplayMetrics.widthPixels < mDisplayMetrics.heightPixels) { |
| 629 | // Portrait mode: crop the navbar out from the bottom, width unchanged |
| 630 | crop.bottom -= navBarHeight; |
| 631 | } else { |
| 632 | // Landscape mode: |
| 633 | if (smallestWidthDp > 599) { |
| 634 | // Navbar on bottom on >599dp width devices, so crop navbar out from the bottom. |
| 635 | crop.bottom -= navBarHeightLandscape; |
| 636 | } else { |
| 637 | // Navbar on right, so crop navbar out from right of screen. |
| 638 | crop.right -= navBarWidth; |
| 639 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 640 | } |
| 641 | |
Ganesh Deva | 0e6fd38 | 2018-08-07 13:13:23 +0530 | [diff] [blame] | 642 | int width = crop.width(); |
| 643 | int height = crop.height(); |
| 644 | // Take the screenshot. SurfaceControl will generate a hardware bitmap in the correct |
| 645 | // orientation and size. |
| 646 | Bitmap bitmap = SurfaceControl.screenshot(crop, width, height, rot); |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 647 | // Bail if we couldn't take the screenshot |
| 648 | if (bitmap == null) { |
| 649 | return null; |
| 650 | } |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 651 | |
Ganesh Deva | 0e6fd38 | 2018-08-07 13:13:23 +0530 | [diff] [blame] | 652 | // Convert to a software bitmap so it can be set in an ImageView. |
| 653 | Bitmap swBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); |
| 654 | return swBitmap; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 655 | } |
| 656 | |
| 657 | @Override |
| 658 | public void onAnimationStart(Animator animation) { } |
| 659 | |
| 660 | @Override |
| 661 | public void onAnimationEnd(Animator animation) { |
| 662 | if (animation == mScaleUpAnimator || animation == mSuccessAnimatorSet || |
| 663 | animation == mFadeInAnimator) { |
| 664 | // These all indicate the end of the animation |
| 665 | dismiss(); |
| 666 | } else if (animation == mFastSendAnimator) { |
| 667 | // After sending is done and we've faded out, reset the scale to 1 |
| 668 | // so we can fade it back in. |
| 669 | mScreenshotView.setScaleX(1.0f); |
| 670 | mScreenshotView.setScaleY(1.0f); |
| 671 | } else if (animation == mPreAnimator) { |
| 672 | if (mHardwareAccelerated && (mState == STATE_W4_TOUCH || mState == STATE_W4_NFC_TAP)) { |
| 673 | mFireflyRenderer.start(mSurface, mSurfaceWidth, mSurfaceHeight); |
| 674 | } |
| 675 | } |
| 676 | } |
| 677 | |
| 678 | @Override |
| 679 | public void onAnimationCancel(Animator animation) { } |
| 680 | |
| 681 | @Override |
| 682 | public void onAnimationRepeat(Animator animation) { } |
| 683 | |
| 684 | @Override |
| 685 | public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { |
| 686 | // This gets called on animation vsync |
| 687 | if (++mRenderedFrames < 4) { |
| 688 | // For the first 3 frames, call invalidate(); this calls eglSwapBuffers |
| 689 | // on the surface, which will allocate large buffers the first three calls |
| 690 | // as Android uses triple buffering. |
| 691 | mScreenshotLayout.invalidate(); |
| 692 | } else { |
| 693 | // Buffers should be allocated, start the real animation |
| 694 | mFrameCounterAnimator.cancel(); |
| 695 | mPreAnimator.start(); |
| 696 | } |
| 697 | } |
| 698 | |
| 699 | @Override |
| 700 | public boolean onTouch(View v, MotionEvent event) { |
| 701 | if (mState != STATE_W4_TOUCH) { |
| 702 | return false; |
| 703 | } |
| 704 | mState = STATE_SENDING; |
| 705 | // Ignore future touches |
| 706 | mScreenshotView.setOnTouchListener(null); |
| 707 | |
| 708 | // Cancel any ongoing animations |
| 709 | mFrameCounterAnimator.cancel(); |
| 710 | mPreAnimator.cancel(); |
| 711 | |
| 712 | mCallback.onSendConfirmed(); |
| 713 | return true; |
| 714 | } |
| 715 | |
| 716 | @Override |
| 717 | public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { |
| 718 | if (mHardwareAccelerated && mState < STATE_COMPLETE) { |
| 719 | mRenderedFrames = 0; |
| 720 | |
| 721 | mFrameCounterAnimator.start(); |
| 722 | mSurface = surface; |
| 723 | mSurfaceWidth = width; |
| 724 | mSurfaceHeight = height; |
| 725 | } |
| 726 | } |
| 727 | |
| 728 | @Override |
| 729 | public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { |
| 730 | // Since we've disabled orientation changes, we can safely ignore this |
| 731 | } |
| 732 | |
| 733 | @Override |
| 734 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { |
| 735 | mSurface = null; |
| 736 | |
| 737 | return true; |
| 738 | } |
| 739 | |
| 740 | @Override |
| 741 | public void onSurfaceTextureUpdated(SurfaceTexture surface) { } |
| 742 | |
| 743 | public void showSendHint() { |
| 744 | if (mAlphaDownAnimator.isRunning()) { |
| 745 | mAlphaDownAnimator.cancel(); |
| 746 | } |
| 747 | if (mSlowSendAnimator.isRunning()) { |
| 748 | mSlowSendAnimator.cancel(); |
| 749 | } |
| 750 | mBlackLayer.setScaleX(mScreenshotView.getScaleX()); |
| 751 | mBlackLayer.setScaleY(mScreenshotView.getScaleY()); |
| 752 | mBlackLayer.setVisibility(View.VISIBLE); |
| 753 | mTextHint.setVisibility(View.GONE); |
| 754 | |
| 755 | mTextRetry.setText(mContext.getResources().getString(R.string.beam_try_again)); |
| 756 | mTextRetry.setVisibility(View.VISIBLE); |
| 757 | |
| 758 | PropertyValuesHolder alphaUp = PropertyValuesHolder.ofFloat("alpha", |
| 759 | new float[] {mBlackLayer.getAlpha(), 0.9f}); |
| 760 | mAlphaUpAnimator.setValues(alphaUp); |
| 761 | mAlphaUpAnimator.start(); |
| 762 | } |
| 763 | |
| 764 | @Override |
| 765 | public boolean dispatchKeyEvent(KeyEvent event) { |
| 766 | int keyCode = event.getKeyCode(); |
| 767 | if (keyCode == KeyEvent.KEYCODE_BACK) { |
| 768 | mCallback.onCanceled(); |
| 769 | return true; |
| 770 | } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || |
| 771 | keyCode == KeyEvent.KEYCODE_VOLUME_UP) { |
| 772 | // Treat as if it's a touch event |
| 773 | return onTouch(mScreenshotView, null); |
| 774 | } else { |
| 775 | return false; |
| 776 | } |
| 777 | } |
| 778 | |
| 779 | @Override |
| 780 | public boolean dispatchKeyShortcutEvent(KeyEvent event) { |
| 781 | return false; |
| 782 | } |
| 783 | |
| 784 | @Override |
| 785 | public boolean dispatchTouchEvent(MotionEvent event) { |
| 786 | return mScreenshotLayout.dispatchTouchEvent(event); |
| 787 | } |
| 788 | |
| 789 | @Override |
| 790 | public boolean dispatchTrackballEvent(MotionEvent event) { |
| 791 | return false; |
| 792 | } |
| 793 | |
| 794 | @Override |
| 795 | public boolean dispatchGenericMotionEvent(MotionEvent event) { |
| 796 | return false; |
| 797 | } |
| 798 | |
| 799 | @Override |
| 800 | public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { |
| 801 | return false; |
| 802 | } |
| 803 | |
| 804 | @Override |
| 805 | public View onCreatePanelView(int featureId) { |
| 806 | return null; |
| 807 | } |
| 808 | |
| 809 | @Override |
| 810 | public boolean onCreatePanelMenu(int featureId, Menu menu) { |
| 811 | return false; |
| 812 | } |
| 813 | |
| 814 | @Override |
| 815 | public boolean onPreparePanel(int featureId, View view, Menu menu) { |
| 816 | return false; |
| 817 | } |
| 818 | |
| 819 | @Override |
| 820 | public boolean onMenuOpened(int featureId, Menu menu) { |
| 821 | return false; |
| 822 | } |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 823 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 824 | @Override |
| 825 | public boolean onMenuItemSelected(int featureId, MenuItem item) { |
| 826 | return false; |
| 827 | } |
| 828 | |
| 829 | @Override |
| 830 | public void onWindowAttributesChanged(LayoutParams attrs) { |
| 831 | } |
| 832 | |
| 833 | @Override |
| 834 | public void onContentChanged() { |
| 835 | } |
| 836 | |
| 837 | @Override |
| 838 | public void onWindowFocusChanged(boolean hasFocus) { |
| 839 | } |
| 840 | |
| 841 | @Override |
| 842 | public void onAttachedToWindow() { |
| 843 | |
| 844 | } |
| 845 | |
| 846 | @Override |
| 847 | public void onDetachedFromWindow() { |
| 848 | } |
| 849 | |
| 850 | @Override |
| 851 | public void onPanelClosed(int featureId, Menu menu) { |
| 852 | |
| 853 | } |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 854 | |
nxpandroid | 1153eb3 | 2015-11-06 18:46:58 +0530 | [diff] [blame] | 855 | @Override |
| 856 | public boolean onSearchRequested(SearchEvent searchEvent) { |
nxpandroid | 281eb92 | 2016-08-25 20:27:46 +0530 | [diff] [blame] | 857 | return onSearchRequested(); |
nxpandroid | 1153eb3 | 2015-11-06 18:46:58 +0530 | [diff] [blame] | 858 | } |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 859 | |
| 860 | @Override |
| 861 | public boolean onSearchRequested() { |
| 862 | return false; |
| 863 | } |
| 864 | |
| 865 | @Override |
| 866 | public ActionMode onWindowStartingActionMode( |
| 867 | android.view.ActionMode.Callback callback) { |
| 868 | return null; |
| 869 | } |
| 870 | |
nxpandroid | 1153eb3 | 2015-11-06 18:46:58 +0530 | [diff] [blame] | 871 | public ActionMode onWindowStartingActionMode( |
| 872 | android.view.ActionMode.Callback callback, int type) { |
| 873 | return null; |
| 874 | } |
| 875 | |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 876 | @Override |
| 877 | public void onActionModeStarted(ActionMode mode) { |
| 878 | } |
| 879 | |
| 880 | @Override |
| 881 | public void onActionModeFinished(ActionMode mode) { |
| 882 | } |
nxpandroid | b781980 | 2017-09-14 11:55:40 +0530 | [diff] [blame] | 883 | |
| 884 | private final BroadcastReceiver mReceiver = new BroadcastReceiver() { |
| 885 | @Override |
| 886 | public void onReceive(Context context, Intent intent) { |
| 887 | if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { |
| 888 | mCallback.onCanceled(); |
| 889 | } |
| 890 | } |
| 891 | }; |
nxpandroid | 64fd68c | 2015-09-23 16:45:15 +0530 | [diff] [blame] | 892 | } |