From 82ac50d607ac252905bf8a095d6e6061f023664e Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 21 Mar 2016 17:34:28 +0900 Subject: [PATCH] PIP: Fix NPE when an activity is PIPed again immediately More proper fix would be not showing Recents after an activity is PIPed, but NPE shouldn't be happen so let me propose the CL as the first step. Bug: 27634771 Change-Id: Ie98293b7dd2d206567ded08d54134164aa78ca9c --- .../SystemUI/res/layout/recents_on_tv.xml | 7 +- .../recents/tv/RecentsTvActivity.java | 79 +++++++++++-------- .../android/systemui/tv/pip/PipManager.java | 29 ++++--- .../systemui/tv/pip/PipMenuActivity.java | 3 + .../tv/pip/PipOnboardingActivity.java | 3 + .../systemui/tv/pip/PipOverlayActivity.java | 6 +- 6 files changed, 78 insertions(+), 49 deletions(-) diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml index 567e009d07eec..97640743514f7 100644 --- a/packages/SystemUI/res/layout/recents_on_tv.xml +++ b/packages/SystemUI/res/layout/recents_on_tv.xml @@ -38,16 +38,15 @@ android:id="@+id/pip_shade" android:layout_width="match_parent" android:layout_height="match_parent" - android:visibility="invisible" + android:visibility="gone" android:background="#76000000"/> + Size and positions will be adjusted to comply with the PIP bounds --> diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java index dae522f2c072d..960bd8c4af856 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java @@ -84,10 +84,14 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { private PipManager mPipManager; private PipManager.Listener mPipListener = new PipManager.Listener() { + @Override + public void onPipEntered() { + updatePipUI(); + } + @Override public void onPipActivityClosed() { - mPipView.setVisibility(View.GONE); - mPipShadeView.setVisibility(View.GONE); + updatePipUI(); } @Override @@ -102,6 +106,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { @Override public void onMediaControllerChanged() { } }; + private boolean mHasPip; /** * A common Runnable to finish Recents by launching Home with an animation depending on the @@ -266,6 +271,10 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent); + + mHasPip = false; + updatePipUI(); + mPipManager.addListener(mPipListener); } @Override @@ -296,34 +305,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { SystemServicesProxy ssp = Recents.getSystemServices(); EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true)); - if (mPipManager.isPipShown()) { - // Place mPipView at the PIP bounds for fine tuned focus handling. - Rect pipBounds = mPipManager.getPipBounds(); - LayoutParams lp = (LayoutParams) mPipView.getLayoutParams(); - lp.width = pipBounds.width(); - lp.height = pipBounds.height(); - lp.leftMargin = pipBounds.left; - lp.topMargin = pipBounds.top; - mPipView.setLayoutParams(lp); - - mPipView.setVisibility(View.VISIBLE); - mPipView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mPipManager.resizePinnedStack(PipManager.STATE_PIP_MENU); - } - }); - mPipView.setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - mPipManager.onPipViewFocusChangedInRecents(hasFocus); - mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE); - } - }); - mPipManager.addListener(mPipListener); - } else { - mPipView.setVisibility(View.GONE); - } mPipManager.onRecentsStarted(); // Give focus to the recents row whenever its visible to an user. mRecentsView.requestFocus(); @@ -340,7 +321,6 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { super.onStop(); mPipManager.onRecentsStopped(); - mPipManager.removeListener(mPipListener); mIgnoreAltTabRelease = false; // Notify that recents is now hidden EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false)); @@ -357,6 +337,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { protected void onDestroy() { super.onDestroy(); + mPipManager.removeListener(mPipListener); // In the case that the activity finished on startup, just skip the unregistration below if (mFinishedOnStartup) { return; @@ -480,4 +461,40 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener { }); return true; } + + private void updatePipUI() { + if (mHasPip == mPipManager.isPipShown()) { + return; + } + mHasPip = mPipManager.isPipShown(); + if (mHasPip) { + // Place mPipView at the PIP bounds for fine tuned focus handling. + Rect pipBounds = mPipManager.getPipBounds(); + LayoutParams lp = (LayoutParams) mPipView.getLayoutParams(); + lp.width = pipBounds.width(); + lp.height = pipBounds.height(); + lp.leftMargin = pipBounds.left; + lp.topMargin = pipBounds.top; + mPipView.setLayoutParams(lp); + + mPipView.setVisibility(View.VISIBLE); + mPipView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mPipManager.resizePinnedStack(PipManager.STATE_PIP_MENU); + } + }); + mPipView.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + mPipManager.onPipViewFocusChangedInRecents(hasFocus); + mPipShadeView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE); + } + }); + mPipShadeView.setVisibility(View.GONE); + } else { + mPipView.setVisibility(View.GONE); + mPipShadeView.setVisibility(View.GONE); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java index 451203dd513ac..95cee4c0438e4 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java @@ -120,6 +120,14 @@ public class PipManager { mMediaSessionManager.addOnActiveSessionsChangedListener( mActiveMediaSessionListener, null); updateMediaController(mMediaSessionManager.getActiveSessions(null)); + if (mIsRecentsShown) { + // If an activity becomes PIPed again after the fullscreen, the Recents is shown + // behind so we need to resize the pinned stack and show the correct overlay. + resizePinnedStack(STATE_PIP_OVERLAY); + } + for (int i = mListeners.size() - 1; i >= 0; i--) { + mListeners.get(i).onPipEntered(); + } } }; private final Runnable mOnTaskStackChanged = new Runnable() { @@ -384,7 +392,7 @@ public class PipManager { try { mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds, true, true, true, -1); } catch (RemoteException e) { - Log.e(TAG, "showPipMenu failed", e); + Log.e(TAG, "resizeStack failed", e); } } @@ -482,17 +490,7 @@ public class PipManager { * Returns {@code true} if PIP is shown. */ public boolean isPipShown() { - return hasPipTasks(); - } - - private boolean hasPipTasks() { - try { - StackInfo stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); - return stackInfo != null; - } catch (RemoteException e) { - Log.e(TAG, "getStackInfo failed", e); - return false; - } + return mState != STATE_NO_PIP; } private void handleMediaResourceGranted(String[] packageNames) { @@ -600,6 +598,13 @@ public class PipManager { * A listener interface to receive notification on changes in PIP. */ public interface Listener { + /** + * Invoked when an activity is pinned and PIP manager is set corresponding information. + * Classes must use this instead of {@link android.app.ITaskStackListener.onActivityPinned} + * because there's no guarantee for the PIP manager be return relavent information + * correctly. (e.g. {@link isPipShown}, {@link getPipBounds}) + */ + void onPipEntered(); /** Invoked when a PIPed activity is closed. */ void onPipActivityClosed(); /** Invoked when the PIP menu gets shown. */ diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java index 285dfd1f9318b..b8b837a0cb845 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java @@ -197,6 +197,9 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { restorePipAndFinish(); } + @Override + public void onPipEntered() { } + @Override public void onPipActivityClosed() { finish(); diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java index ad45625b0f9cf..79daf3d510563 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java @@ -66,6 +66,9 @@ public class PipOnboardingActivity extends Activity implements PipManager.Listen mPipManager.removeListener(this); } + @Override + public void onPipEntered() { } + @Override public void onPipActivityClosed() { finish(); diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java index 4bd3f49e1fc8e..1de321dd10045 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java @@ -108,6 +108,9 @@ public class PipOverlayActivity extends Activity implements PipManager.Listener PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_OVERLAY_ACTIVITY_FINISH); } + @Override + public void onPipEntered() { } + @Override public void onPipActivityClosed() { finish(); @@ -131,8 +134,7 @@ public class PipOverlayActivity extends Activity implements PipManager.Listener } @Override - public void onMediaControllerChanged() { - } + public void onMediaControllerChanged() { } @Override public void finish() {