// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.chrome.browser.media.router; import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v7.app.MediaRouteChooserDialogFragment; import android.support.v7.media.MediaRouter; import android.view.View; import android.widget.FrameLayout; import org.chromium.base.ApplicationStatus; import org.chromium.chrome.browser.media.router.cast.MediaSource; import javax.annotation.Nullable; /** * Shared code for {@link MediaRouteDialogManager} implementations. */ public abstract class BaseMediaRouteDialogManager implements MediaRouteDialogManager { /** * A helper class to handle the system visibility change caused by the dialog showing up. * Call saveSystemVisibility() in onCreateDialog() of the DialogFragment and later * restoreSystemVisibility() in onStop(). * TODO(avayvod): refactor this to avoid a redundant copy in ChromeMediaRouteDialogFactory. */ protected static class SystemVisibilitySaver { private int mSystemVisibilityToRestore; private boolean mWasFullscreenBeforeShowing; void saveSystemVisibility(Activity activity) { // If we are in fullscreen we may have also have hidden the system UI. This // is overridden when we display the dialog. Save the system UI visibility // state so we can restore it. FrameLayout decor = (FrameLayout) activity.getWindow().getDecorView(); mSystemVisibilityToRestore = decor.getSystemUiVisibility(); mWasFullscreenBeforeShowing = ( (mSystemVisibilityToRestore & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0); } void restoreSystemVisibility(Activity activity) { if (!mWasFullscreenBeforeShowing) return; FrameLayout decor = (FrameLayout) activity.getWindow().getDecorView(); // In some cases we come out of fullscreen before closing this dialog. In these // cases we don't want to restore the system UI visibility state. boolean isStillFullscreen = (decor.getSystemUiVisibility() & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) == 0; if (!isStillFullscreen) return; decor.setSystemUiVisibility(mSystemVisibilityToRestore); } } private final MediaSource mMediaSource; private final MediaRouter mAndroidMediaRouter; private final MediaRouteDialogDelegate mDelegate; protected DialogFragment mDialogFragment; @Override public void openDialog() { if (mAndroidMediaRouter == null) { mDelegate.onDialogCancelled(); return; } FragmentActivity currentActivity = (FragmentActivity) ApplicationStatus.getLastTrackedFocusedActivity(); if (currentActivity == null) { mDelegate.onDialogCancelled(); return; } FragmentManager fm = currentActivity.getSupportFragmentManager(); if (fm == null) { mDelegate.onDialogCancelled(); return; } mDialogFragment = openDialogInternal(fm); if (mDialogFragment == null) { mDelegate.onDialogCancelled(); return; } } @Override public void closeDialog() { if (mDialogFragment == null) return; mDialogFragment.dismiss(); mDialogFragment = null; } @Override public boolean isShowingDialog() { return mDialogFragment != null && mDialogFragment.isVisible(); } protected BaseMediaRouteDialogManager(MediaSource source, Context applicationContext, MediaRouteDialogDelegate delegate) { mMediaSource = source; mAndroidMediaRouter = ChromeMediaRouter.getAndroidMediaRouter(applicationContext); mDelegate = delegate; } /** * Base class for media router dialog fragment. Classes inheriting from * BaseMediaRouteDialogManager may extend the implementation but must redirect the empty * constructor to this implementation to handle the case of the Fragment being created via * this method. */ public static class Fragment extends MediaRouteChooserDialogFragment { private final Handler mHandler = new Handler(); private final SystemVisibilitySaver mVisibilitySaver = new SystemVisibilitySaver(); protected BaseMediaRouteDialogManager mManager = null; public Fragment() { mHandler.post(new Runnable() { @Override public void run() { Fragment.this.dismiss(); } }); } public Fragment(BaseMediaRouteDialogManager manager) { mManager = manager; } @Override public void onStart() { mVisibilitySaver.saveSystemVisibility(getActivity()); super.onStart(); } @Override public void onStop() { super.onStop(); mVisibilitySaver.restoreSystemVisibility(getActivity()); } @Override public void onDismiss(DialogInterface dialog) { super.onDismiss(dialog); if (mManager == null) return; mManager.mDialogFragment = null; } } /** * Initializes and shows the {@link DialogFragment} instance corresponding to the dialog type * needed. * * @param fm {@link FragmentManager} to use to show the dialog. * @return null if the initialization fails, otherwise the initialized dialog fragment. */ @Nullable protected abstract DialogFragment openDialogInternal(FragmentManager fm); protected MediaRouteDialogDelegate delegate() { return mDelegate; } protected MediaRouter androidMediaRouter() { return mAndroidMediaRouter; } protected MediaSource mediaSource() { return mMediaSource; } }