1 /* 2 * Copyright (C) 2015 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 */ 16 17 package android.server.wm.app; 18 19 import static android.server.wm.app.Components.PipActivity.ACTION_CHANGE_ASPECT_RATIO; 20 import static android.server.wm.app.Components.PipActivity.ACTION_ENTER_PIP; 21 import static android.server.wm.app.Components.PipActivity.ACTION_ENTER_PIP_AND_WAIT_FOR_UI_STATE; 22 import static android.server.wm.app.Components.PipActivity.ACTION_EXPAND_PIP; 23 import static android.server.wm.app.Components.PipActivity.ACTION_FINISH; 24 import static android.server.wm.app.Components.PipActivity.ACTION_LAUNCH_TRANSLUCENT_ACTIVITY; 25 import static android.server.wm.app.Components.PipActivity.ACTION_MOVE_TO_BACK; 26 import static android.server.wm.app.Components.PipActivity.ACTION_ON_PIP_REQUESTED; 27 import static android.server.wm.app.Components.PipActivity.ACTION_SET_ON_PAUSE_REMOTE_CALLBACK; 28 import static android.server.wm.app.Components.PipActivity.ACTION_SET_REQUESTED_ORIENTATION; 29 import static android.server.wm.app.Components.PipActivity.ACTION_UPDATE_PIP_STATE; 30 import static android.server.wm.app.Components.PipActivity.EXTRA_ALLOW_AUTO_PIP; 31 import static android.server.wm.app.Components.PipActivity.EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP; 32 import static android.server.wm.app.Components.PipActivity.EXTRA_CLOSE_ACTION; 33 import static android.server.wm.app.Components.PipActivity.EXTRA_DISMISS_KEYGUARD; 34 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP; 35 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR; 36 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR; 37 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_BACK_PRESSED; 38 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PAUSE; 39 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_PIP_REQUESTED; 40 import static android.server.wm.app.Components.PipActivity.EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT; 41 import static android.server.wm.app.Components.PipActivity.EXTRA_EXPANDED_PIP_ASPECT_RATIO_DENOMINATOR; 42 import static android.server.wm.app.Components.PipActivity.EXTRA_EXPANDED_PIP_ASPECT_RATIO_NUMERATOR; 43 import static android.server.wm.app.Components.PipActivity.EXTRA_FINISH_SELF_ON_RESUME; 44 import static android.server.wm.app.Components.PipActivity.EXTRA_IS_SEAMLESS_RESIZE_ENABLED; 45 import static android.server.wm.app.Components.PipActivity.EXTRA_NUMBER_OF_CUSTOM_ACTIONS; 46 import static android.server.wm.app.Components.PipActivity.EXTRA_ON_PAUSE_DELAY; 47 import static android.server.wm.app.Components.PipActivity.EXTRA_PIP_ON_PAUSE_CALLBACK; 48 import static android.server.wm.app.Components.PipActivity.EXTRA_PIP_ORIENTATION; 49 import static android.server.wm.app.Components.PipActivity.EXTRA_SET_ASPECT_RATIO_DENOMINATOR; 50 import static android.server.wm.app.Components.PipActivity.EXTRA_SET_ASPECT_RATIO_NUMERATOR; 51 import static android.server.wm.app.Components.PipActivity.EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR; 52 import static android.server.wm.app.Components.PipActivity.EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR; 53 import static android.server.wm.app.Components.PipActivity.EXTRA_SET_PIP_CALLBACK; 54 import static android.server.wm.app.Components.PipActivity.EXTRA_SET_PIP_STASHED; 55 import static android.server.wm.app.Components.PipActivity.EXTRA_SHOW_OVER_KEYGUARD; 56 import static android.server.wm.app.Components.PipActivity.EXTRA_START_ACTIVITY; 57 import static android.server.wm.app.Components.PipActivity.EXTRA_SUBTITLE; 58 import static android.server.wm.app.Components.PipActivity.EXTRA_TAP_TO_FINISH; 59 import static android.server.wm.app.Components.PipActivity.EXTRA_TITLE; 60 import static android.server.wm.app.Components.PipActivity.IS_IN_PIP_MODE_RESULT; 61 import static android.server.wm.app.Components.PipActivity.UI_STATE_ENTERING_PIP_RESULT; 62 import static android.server.wm.app.Components.PipActivity.UI_STATE_STASHED_RESULT; 63 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 64 65 import android.app.Activity; 66 import android.app.PendingIntent; 67 import android.app.PictureInPictureParams; 68 import android.app.PictureInPictureUiState; 69 import android.app.RemoteAction; 70 import android.content.BroadcastReceiver; 71 import android.content.ComponentName; 72 import android.content.Context; 73 import android.content.Intent; 74 import android.content.IntentFilter; 75 import android.content.res.Configuration; 76 import android.graphics.drawable.Icon; 77 import android.os.Bundle; 78 import android.os.Handler; 79 import android.os.RemoteCallback; 80 import android.os.SystemClock; 81 import android.server.wm.CommandSession; 82 import android.util.Log; 83 import android.util.Rational; 84 import android.window.OnBackInvokedDispatcher; 85 86 import androidx.annotation.Nullable; 87 88 import java.util.ArrayList; 89 import java.util.List; 90 91 public class PipActivity extends AbstractLifecycleLogActivity { 92 93 private boolean mEnteredPictureInPicture; 94 private boolean mEnterPipOnBackPressed; 95 private RemoteCallback mCb; 96 private RemoteCallback mOnPauseCallback; 97 98 private Handler mHandler = new Handler(); 99 private BroadcastReceiver mReceiver = new BroadcastReceiver() { 100 @Override 101 public void onReceive(Context context, Intent intent) { 102 if (intent != null) { 103 switch (intent.getAction()) { 104 case ACTION_ENTER_PIP: 105 enterPictureInPictureMode(new PictureInPictureParams.Builder().build()); 106 if (intent.getExtras() != null) { 107 mCb = (RemoteCallback) intent.getExtras().get(EXTRA_SET_PIP_CALLBACK); 108 if (mCb != null) { 109 mCb.sendResult(new Bundle()); 110 } 111 } 112 break; 113 case ACTION_ENTER_PIP_AND_WAIT_FOR_UI_STATE: 114 // mCb will be callback-ed in onPictureInPictureUiStateChanged. 115 mCb = (RemoteCallback) intent.getExtras().get(EXTRA_SET_PIP_CALLBACK); 116 enterPictureInPictureMode(new PictureInPictureParams.Builder().build()); 117 break; 118 case ACTION_MOVE_TO_BACK: 119 moveTaskToBack(false /* nonRoot */); 120 break; 121 case ACTION_UPDATE_PIP_STATE: 122 mCb = (RemoteCallback) intent.getExtras().get(EXTRA_SET_PIP_CALLBACK); 123 boolean stashed = intent.getBooleanExtra(EXTRA_SET_PIP_STASHED, false); 124 onPictureInPictureUiStateChanged(new PictureInPictureUiState(stashed)); 125 break; 126 case ACTION_EXPAND_PIP: 127 // Trigger the activity to expand 128 Intent startIntent = new Intent(PipActivity.this, PipActivity.class); 129 startIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); 130 startActivity(startIntent); 131 132 if (intent.hasExtra(EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR) 133 && intent.hasExtra(EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR)) { 134 // Ugly, but required to wait for the startActivity to actually start 135 // the activity... 136 mHandler.postDelayed(() -> { 137 final PictureInPictureParams.Builder builder = 138 new PictureInPictureParams.Builder(); 139 builder.setAspectRatio(getAspectRatio(intent, 140 EXTRA_SET_ASPECT_RATIO_WITH_DELAY_NUMERATOR, 141 EXTRA_SET_ASPECT_RATIO_WITH_DELAY_DENOMINATOR)); 142 setPictureInPictureParams(builder.build()); 143 }, 100); 144 } 145 break; 146 case ACTION_SET_REQUESTED_ORIENTATION: 147 setRequestedOrientation(Integer.parseInt(intent.getStringExtra( 148 EXTRA_PIP_ORIENTATION))); 149 break; 150 case ACTION_FINISH: 151 finish(); 152 break; 153 case ACTION_ON_PIP_REQUESTED: 154 onPictureInPictureRequested(); 155 break; 156 case ACTION_CHANGE_ASPECT_RATIO: 157 setPictureInPictureParams(new PictureInPictureParams.Builder() 158 .setAspectRatio(getAspectRatio(intent, 159 EXTRA_SET_ASPECT_RATIO_NUMERATOR, 160 EXTRA_SET_ASPECT_RATIO_DENOMINATOR)) 161 .build()); 162 break; 163 case ACTION_LAUNCH_TRANSLUCENT_ACTIVITY: 164 startActivity(new Intent(PipActivity.this, TranslucentTestActivity.class)); 165 break; 166 case ACTION_SET_ON_PAUSE_REMOTE_CALLBACK: 167 mOnPauseCallback = intent.getParcelableExtra( 168 EXTRA_PIP_ON_PAUSE_CALLBACK, RemoteCallback.class); 169 // Signals the caller that we have received the mOnPauseCallback 170 final RemoteCallback setCallback = intent.getParcelableExtra( 171 EXTRA_SET_PIP_CALLBACK, RemoteCallback.class); 172 setCallback.sendResult(Bundle.EMPTY); 173 break; 174 } 175 } 176 } 177 }; 178 179 @Override onCreate(Bundle savedInstanceState)180 protected void onCreate(Bundle savedInstanceState) { 181 super.onCreate(savedInstanceState); 182 183 // Set the fixed orientation if requested 184 if (getIntent().hasExtra(EXTRA_PIP_ORIENTATION)) { 185 final int ori = Integer.parseInt(getIntent().getStringExtra(EXTRA_PIP_ORIENTATION)); 186 setRequestedOrientation(ori); 187 } 188 189 // Set the window flag to show over the keyguard 190 setShowWhenLocked(parseBooleanExtra(EXTRA_SHOW_OVER_KEYGUARD)); 191 192 // Set the window flag to dismiss the keyguard 193 if (parseBooleanExtra(EXTRA_DISMISS_KEYGUARD)) { 194 getWindow().addFlags(FLAG_DISMISS_KEYGUARD); 195 } 196 197 boolean enteringPip = false; 198 // Enter picture in picture with the given aspect ratio if provided 199 if (parseBooleanExtra(EXTRA_ENTER_PIP)) { 200 if (getIntent().hasExtra(EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR) 201 && getIntent().hasExtra(EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR)) { 202 try { 203 final PictureInPictureParams.Builder builder = 204 new PictureInPictureParams.Builder(); 205 builder.setAspectRatio(getAspectRatio(getIntent(), 206 EXTRA_ENTER_PIP_ASPECT_RATIO_NUMERATOR, 207 EXTRA_ENTER_PIP_ASPECT_RATIO_DENOMINATOR)); 208 if (shouldAddExpandedPipAspectRatios()) { 209 builder.setExpandedAspectRatio(getAspectRatio(getIntent(), 210 EXTRA_EXPANDED_PIP_ASPECT_RATIO_NUMERATOR, 211 EXTRA_EXPANDED_PIP_ASPECT_RATIO_DENOMINATOR)); 212 } 213 enteringPip = enterPictureInPictureMode(builder.build()); 214 } catch (Exception e) { 215 // This call can fail intentionally if the aspect ratio is too extreme 216 } 217 } else { 218 enteringPip = enterPictureInPictureMode( 219 new PictureInPictureParams.Builder().build()); 220 } 221 } 222 223 // We need to wait for either enterPictureInPicture() or requestAutoEnterPictureInPicture() 224 // to be called before setting the aspect ratio 225 if (getIntent().hasExtra(EXTRA_SET_ASPECT_RATIO_NUMERATOR) 226 && getIntent().hasExtra(EXTRA_SET_ASPECT_RATIO_DENOMINATOR)) { 227 final PictureInPictureParams.Builder builder = 228 new PictureInPictureParams.Builder(); 229 builder.setAspectRatio(getAspectRatio(getIntent(), 230 EXTRA_SET_ASPECT_RATIO_NUMERATOR, EXTRA_SET_ASPECT_RATIO_DENOMINATOR)); 231 try { 232 setPictureInPictureParams(builder.build()); 233 } catch (Exception e) { 234 // This call can fail intentionally if the aspect ratio is too extreme 235 } 236 } 237 238 final PictureInPictureParams.Builder sharedBuilder = new PictureInPictureParams.Builder(); 239 boolean sharedBuilderChanged = false; 240 241 if (parseBooleanExtra(EXTRA_ALLOW_AUTO_PIP)) { 242 sharedBuilder.setAutoEnterEnabled(true); 243 sharedBuilderChanged = true; 244 } 245 246 if (getIntent().hasExtra(EXTRA_IS_SEAMLESS_RESIZE_ENABLED)) { 247 sharedBuilder.setSeamlessResizeEnabled( 248 getIntent().getBooleanExtra(EXTRA_IS_SEAMLESS_RESIZE_ENABLED, true)); 249 sharedBuilderChanged = true; 250 } 251 252 if (getIntent().hasExtra(EXTRA_TITLE)) { 253 sharedBuilder.setTitle(getIntent().getStringExtra(EXTRA_TITLE)); 254 sharedBuilderChanged = true; 255 } 256 257 if (getIntent().hasExtra(EXTRA_SUBTITLE)) { 258 sharedBuilder.setSubtitle(getIntent().getStringExtra(EXTRA_SUBTITLE)); 259 sharedBuilderChanged = true; 260 } 261 262 if (getIntent().hasExtra(EXTRA_CLOSE_ACTION)) { 263 if (getIntent().getBooleanExtra(EXTRA_CLOSE_ACTION, false)) { 264 sharedBuilder.setCloseAction(createRemoteAction(0)); 265 } else { 266 sharedBuilder.setCloseAction(null); 267 } 268 sharedBuilderChanged = true; 269 } 270 271 // Enable tap to finish if necessary 272 if (parseBooleanExtra(EXTRA_TAP_TO_FINISH)) { 273 setContentView(R.layout.tap_to_finish_pip_layout); 274 findViewById(R.id.content).setOnClickListener(v -> { 275 finish(); 276 }); 277 } 278 279 // Launch a new activity if requested 280 String launchActivityComponent = getIntent().getStringExtra(EXTRA_START_ACTIVITY); 281 if (launchActivityComponent != null) { 282 Intent launchIntent = new Intent(); 283 launchIntent.setComponent(ComponentName.unflattenFromString(launchActivityComponent)); 284 startActivity(launchIntent); 285 } 286 287 // Set custom actions if requested 288 if (getIntent().hasExtra(EXTRA_NUMBER_OF_CUSTOM_ACTIONS)) { 289 final int numberOfCustomActions = Integer.valueOf( 290 getIntent().getStringExtra(EXTRA_NUMBER_OF_CUSTOM_ACTIONS)); 291 final List<RemoteAction> actions = new ArrayList<>(numberOfCustomActions); 292 for (int i = 0; i< numberOfCustomActions; i++) { 293 actions.add(createRemoteAction(i)); 294 } 295 sharedBuilder.setActions(actions); 296 sharedBuilderChanged = true; 297 } 298 299 if (sharedBuilderChanged) { 300 setPictureInPictureParams(sharedBuilder.build()); 301 } 302 303 // Register the broadcast receiver 304 IntentFilter filter = new IntentFilter(); 305 filter.addAction(ACTION_ENTER_PIP); 306 filter.addAction(ACTION_MOVE_TO_BACK); 307 filter.addAction(ACTION_EXPAND_PIP); 308 filter.addAction(ACTION_UPDATE_PIP_STATE); 309 filter.addAction(ACTION_ENTER_PIP_AND_WAIT_FOR_UI_STATE); 310 filter.addAction(ACTION_SET_REQUESTED_ORIENTATION); 311 filter.addAction(ACTION_FINISH); 312 filter.addAction(ACTION_ON_PIP_REQUESTED); 313 filter.addAction(ACTION_CHANGE_ASPECT_RATIO); 314 filter.addAction(ACTION_LAUNCH_TRANSLUCENT_ACTIVITY); 315 filter.addAction(ACTION_SET_ON_PAUSE_REMOTE_CALLBACK); 316 registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED); 317 318 // Don't dump configuration when entering PIP to avoid the verifier getting the intermediate 319 // state. In this case it is expected that the verifier will check the changed configuration 320 // after onConfigurationChanged. 321 if (!enteringPip) { 322 // Dump applied display metrics. 323 dumpConfiguration(getResources().getConfiguration()); 324 dumpConfigInfo(); 325 } 326 327 mEnterPipOnBackPressed = parseBooleanExtra(EXTRA_ENTER_PIP_ON_BACK_PRESSED); 328 getOnBackInvokedDispatcher().registerOnBackInvokedCallback( 329 OnBackInvokedDispatcher.PRIORITY_DEFAULT, this::onBackInvoked); 330 } 331 332 @Override onResume()333 protected void onResume() { 334 super.onResume(); 335 336 // Finish self if requested 337 if (parseBooleanExtra(EXTRA_FINISH_SELF_ON_RESUME)) { 338 finish(); 339 } 340 } 341 342 @Override onPause()343 protected void onPause() { 344 super.onPause(); 345 346 // Pause if requested 347 if (getIntent().hasExtra(EXTRA_ON_PAUSE_DELAY)) { 348 SystemClock.sleep(Long.valueOf(getIntent().getStringExtra(EXTRA_ON_PAUSE_DELAY))); 349 } 350 351 // Enter PIP on move to background 352 if (parseBooleanExtra(EXTRA_ENTER_PIP_ON_PAUSE)) { 353 enterPictureInPictureMode(new PictureInPictureParams.Builder().build()); 354 } 355 356 if (mOnPauseCallback != null) { 357 Bundle res = new Bundle(1); 358 res.putBoolean(IS_IN_PIP_MODE_RESULT, isInPictureInPictureMode()); 359 mOnPauseCallback.sendResult(res); 360 } 361 } 362 363 @Override onStop()364 protected void onStop() { 365 super.onStop(); 366 367 if (parseBooleanExtra(EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP) && !mEnteredPictureInPicture) { 368 Log.w(getTag(), "Unexpected onStop() called before entering picture-in-picture"); 369 finish(); 370 } 371 } 372 373 @Override onDestroy()374 protected void onDestroy() { 375 super.onDestroy(); 376 377 unregisterReceiver(mReceiver); 378 } 379 380 @Override onUserLeaveHint()381 protected void onUserLeaveHint() { 382 super.onUserLeaveHint(); 383 if (parseBooleanExtra(EXTRA_ENTER_PIP_ON_USER_LEAVE_HINT)) { 384 enterPictureInPictureMode(new PictureInPictureParams.Builder().build()); 385 } 386 } 387 388 @Override onPictureInPictureRequested()389 public boolean onPictureInPictureRequested() { 390 onCallback(CommandSession.ActivityCallback.ON_PICTURE_IN_PICTURE_REQUESTED); 391 if (parseBooleanExtra(EXTRA_ENTER_PIP_ON_PIP_REQUESTED)) { 392 enterPictureInPictureMode(new PictureInPictureParams.Builder().build()); 393 return true; 394 } 395 return super.onPictureInPictureRequested(); 396 } 397 398 @Override onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig)399 public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, 400 Configuration newConfig) { 401 super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); 402 403 // Fail early if the activity state does not match the dispatched state 404 if (isInPictureInPictureMode() != isInPictureInPictureMode) { 405 Log.w(getTag(), "Received onPictureInPictureModeChanged mode=" 406 + isInPictureInPictureMode + " activityState=" + isInPictureInPictureMode()); 407 finish(); 408 } 409 410 // Mark that we've entered picture-in-picture so that we can stop checking for 411 // EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP 412 if (isInPictureInPictureMode) { 413 mEnteredPictureInPicture = true; 414 } 415 } 416 417 @Override onPictureInPictureUiStateChanged(PictureInPictureUiState pipState)418 public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) { 419 Bundle res = new Bundle(); 420 res.putBoolean(UI_STATE_STASHED_RESULT, pipState.isStashed()); 421 res.putBoolean(UI_STATE_ENTERING_PIP_RESULT, pipState.isTransitioningToPip()); 422 if (mCb != null) { 423 mCb.sendResult(res); 424 } 425 } 426 427 @Override onConfigurationChanged(Configuration newConfig)428 public void onConfigurationChanged(Configuration newConfig) { 429 super.onConfigurationChanged(newConfig); 430 dumpConfiguration(newConfig); 431 dumpConfigInfo(); 432 } 433 onBackInvoked()434 private void onBackInvoked() { 435 if (mEnterPipOnBackPressed) { 436 enterPictureInPictureMode(new PictureInPictureParams.Builder().build()); 437 } else { 438 finish(); 439 } 440 } 441 442 /** 443 * Launches a new instance of the PipActivity in the same task that will automatically enter 444 * PiP. 445 */ launchEnterPipActivity(Activity caller, @Nullable Bundle overrides)446 static void launchEnterPipActivity(Activity caller, @Nullable Bundle overrides) { 447 final Intent intent = new Intent(caller, PipActivity.class); 448 intent.putExtra(EXTRA_ENTER_PIP, "true"); 449 intent.putExtra(EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP, "true"); 450 if (overrides != null) { 451 intent.putExtras(overrides); 452 } 453 caller.startActivity(intent); 454 } 455 parseBooleanExtra(String key)456 private boolean parseBooleanExtra(String key) { 457 return getIntent().hasExtra(key) && Boolean.parseBoolean(getIntent().getStringExtra(key)); 458 } 459 460 /** 461 * @return a {@link Rational} aspect ratio from the given intent and extras. 462 */ getAspectRatio(Intent intent, String extraNum, String extraDenom)463 private Rational getAspectRatio(Intent intent, String extraNum, String extraDenom) { 464 return new Rational( 465 Integer.valueOf(intent.getStringExtra(extraNum)), 466 Integer.valueOf(intent.getStringExtra(extraDenom))); 467 } 468 469 /** @return {@link RemoteAction} instance titled after a given index */ createRemoteAction(int index)470 private RemoteAction createRemoteAction(int index) { 471 return new RemoteAction(Icon.createWithResource(this, R.drawable.red), 472 "action " + index, 473 "contentDescription " + index, 474 PendingIntent.getBroadcast(this, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)); 475 } 476 shouldAddExpandedPipAspectRatios()477 private boolean shouldAddExpandedPipAspectRatios() { 478 return getIntent().hasExtra(EXTRA_EXPANDED_PIP_ASPECT_RATIO_NUMERATOR) 479 && getIntent().hasExtra(EXTRA_EXPANDED_PIP_ASPECT_RATIO_DENOMINATOR); 480 } 481 } 482