Merge "Initial check-in of picture-in-picture system-ui"
This commit is contained in:
committed by
Android (Google) Code Review
commit
d7358f5463
@@ -23,4 +23,12 @@
|
||||
|
||||
<!-- Flags enabling default window features. See Window.java -->
|
||||
<bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
|
||||
|
||||
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
|
||||
<string translatable="false" name="config_defaultPictureInPictureBounds">"1420 100 1820 325"</string>
|
||||
|
||||
<!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
|
||||
is located in center. -->
|
||||
<string translatable="false" name="config_centeredPictureInPictureBounds">"600 331 1320 749"</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -2419,6 +2419,10 @@
|
||||
<!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
|
||||
<string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
|
||||
|
||||
<!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP
|
||||
is located in center. -->
|
||||
<string translatable="false" name="config_centeredPictureInPictureBounds">"0 0 300 300"</string>
|
||||
|
||||
<!-- Controls the snap mode for the docked stack divider
|
||||
0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
|
||||
1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
|
||||
|
||||
@@ -305,6 +305,7 @@
|
||||
<java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
|
||||
<java-symbol type="bool" name="config_freeformWindowManagement" />
|
||||
<java-symbol type="string" name="config_defaultPictureInPictureBounds" />
|
||||
<java-symbol type="string" name="config_centeredPictureInPictureBounds" />
|
||||
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
|
||||
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
|
||||
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
|
||||
|
||||
@@ -309,6 +309,27 @@
|
||||
android:launchMode="singleTop"
|
||||
android:excludeFromRecents="true" />
|
||||
|
||||
<!-- started from PipUI -->
|
||||
<activity
|
||||
android:name="com.android.systemui.tv.pip.PipMenuActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/PipTheme"
|
||||
android:launchMode="singleTop"
|
||||
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|layoutDirection"
|
||||
android:resizeable="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
androidprv:alwaysFocusable="true"
|
||||
android:excludeFromRecents="true" />
|
||||
<activity
|
||||
android:name="com.android.systemui.tv.pip.PipOverlayActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/PipTheme"
|
||||
android:launchMode="singleTop"
|
||||
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|layoutDirection"
|
||||
android:resizeable="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:excludeFromRecents="true" />
|
||||
|
||||
<!-- platform logo easter egg activity -->
|
||||
<activity
|
||||
android:name=".DessertCase"
|
||||
|
||||
61
packages/SystemUI/res/layout/tv_pip_menu.xml
Normal file
61
packages/SystemUI/res/layout/tv_pip_menu.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2016, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:background="#88FFFFFF">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<Button android:id="@+id/full"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/pip_fullscreen"
|
||||
android:textSize="10sp"
|
||||
android:focusable="true" />
|
||||
|
||||
<Button android:id="@+id/exit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/pip_exit"
|
||||
android:textSize="10sp"
|
||||
android:focusable="true" />
|
||||
|
||||
<Button android:id="@+id/cancel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/pip_cancel"
|
||||
android:textSize="10sp"
|
||||
android:focusable="true" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</RelativeLayout>
|
||||
33
packages/SystemUI/res/layout/tv_pip_overlay.xml
Normal file
33
packages/SystemUI/res/layout/tv_pip_overlay.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2016, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<TextView
|
||||
android:id="@+id/guide_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:padding="3dp"
|
||||
android:textSize="13sp"
|
||||
android:textColor="#111111"
|
||||
android:background="#99EEEEEE"
|
||||
android:text="@string/pip_hold_home" />
|
||||
</FrameLayout>
|
||||
32
packages/SystemUI/res/values/strings_tv.xml
Normal file
32
packages/SystemUI/res/values/strings_tv.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/**
|
||||
* Copyright (c) 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<!-- Button to close PIP on PIP UI -->
|
||||
<string name="pip_exit">Close PIP</string>
|
||||
<!-- Button to move PIP screen to the fullscreen on PIP UI -->
|
||||
<string name="pip_fullscreen">Full screen</string>
|
||||
<!-- Button to play the current media on PIP UI -->
|
||||
<string name="pip_play">Play</string>
|
||||
<!-- Button to pause the current media on PIP UI -->
|
||||
<string name="pip_pause">Pause</string>
|
||||
<!-- Button to close PIP overlay menu on PIP UI -->
|
||||
<string name="pip_cancel">Cancel</string>
|
||||
<!-- Overlay text on PIP -->
|
||||
<string name="pip_hold_home">Hold HOME to control PIP</string>
|
||||
</resources>
|
||||
25
packages/SystemUI/res/values/styles_tv.xml
Normal file
25
packages/SystemUI/res/values/styles_tv.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/**
|
||||
* Copyright (c) 2016, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
-->
|
||||
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<style name="PipTheme" parent="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:backgroundDimEnabled">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -54,6 +54,7 @@ public class SystemUIApplication extends Application {
|
||||
com.android.systemui.power.PowerUI.class,
|
||||
com.android.systemui.media.RingtonePlayer.class,
|
||||
com.android.systemui.keyboard.KeyboardUI.class,
|
||||
com.android.systemui.tv.pip.PipUI.class
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.tv.pip;
|
||||
|
||||
import android.app.ActivityManager.StackInfo;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.ITaskStackListener;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
|
||||
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
|
||||
|
||||
/**
|
||||
* Manages the picture-in-picture (PIP) UI and states.
|
||||
*/
|
||||
public class PipManager {
|
||||
private static final String TAG = "PipManager";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static PipManager sPipManager;
|
||||
|
||||
private static final int STATE_NO_PIP = 0;
|
||||
private static final int STATE_PIP_OVERLAY = 1;
|
||||
private static final int STATE_PIP_MENU = 2;
|
||||
|
||||
private Context mContext;
|
||||
private IActivityManager mActivityManager;
|
||||
private int mState = STATE_NO_PIP;
|
||||
private final Handler mHandler = new Handler();
|
||||
private List<Listener> mListeners = new ArrayList<>();
|
||||
private Rect mPipBound;
|
||||
private Rect mMenuModePipBound;
|
||||
private boolean mInitialized;
|
||||
private final Runnable mOnActivityPinnedRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
StackInfo stackInfo = null;
|
||||
try {
|
||||
stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
|
||||
if (stackInfo == null) {
|
||||
Log.w(TAG, "There is no pinned stack");
|
||||
return;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "getStackInfo failed", e);
|
||||
return;
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo);
|
||||
mState = STATE_PIP_OVERLAY;
|
||||
launchPipOverlayActivity();
|
||||
}
|
||||
};
|
||||
private final Runnable mOnTaskStackChanged = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mState != STATE_NO_PIP) {
|
||||
// TODO: check whether PIP task is closed.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final BroadcastReceiver mPipButtonReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (DEBUG) Log.d(TAG, "PIP button pressed");
|
||||
if (!hasPipTasks()) {
|
||||
startPip();
|
||||
} else if (mState == STATE_PIP_OVERLAY) {
|
||||
showPipMenu();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private PipManager() { }
|
||||
|
||||
/**
|
||||
* Initializes {@link PipManager}.
|
||||
*/
|
||||
public void initialize(Context context) {
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
mInitialized = true;
|
||||
mContext = context;
|
||||
Resources res = context.getResources();
|
||||
mPipBound = Rect.unflattenFromString(res.getString(
|
||||
com.android.internal.R.string.config_defaultPictureInPictureBounds));
|
||||
mMenuModePipBound = Rect.unflattenFromString(res.getString(
|
||||
com.android.internal.R.string.config_centeredPictureInPictureBounds));
|
||||
|
||||
mActivityManager = ActivityManagerNative.getDefault();
|
||||
TaskStackListener taskStackListener = new TaskStackListener();
|
||||
IActivityManager iam = ActivityManagerNative.getDefault();
|
||||
try {
|
||||
iam.registerTaskStackListener(taskStackListener);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "registerTaskStackListener failed", e);
|
||||
}
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_PICTURE_IN_PICTURE_BUTTON);
|
||||
mContext.registerReceiver(mPipButtonReceiver, intentFilter);
|
||||
}
|
||||
|
||||
private void startPip() {
|
||||
try {
|
||||
mActivityManager.moveTopActivityToPinnedStack(FULLSCREEN_WORKSPACE_STACK_ID, mPipBound);
|
||||
} catch (RemoteException|IllegalArgumentException e) {
|
||||
Log.e(TAG, "moveTopActivityToPinnedStack failed", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes PIP (PIPped activity and PIP system UI).
|
||||
*/
|
||||
public void closePip() {
|
||||
mState = STATE_NO_PIP;
|
||||
StackInfo stackInfo = null;
|
||||
try {
|
||||
stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID);
|
||||
if (stackInfo == null) {
|
||||
return;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "getStackInfo failed", e);
|
||||
return;
|
||||
}
|
||||
for (int taskId : stackInfo.taskIds) {
|
||||
try {
|
||||
mActivityManager.removeTask(taskId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "removeTask failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the PIPped activity to the fullscreen and closes PIP system UI.
|
||||
*/
|
||||
public void movePipToFullscreen() {
|
||||
mState = STATE_NO_PIP;
|
||||
for (int i = mListeners.size() - 1; i >= 0; --i) {
|
||||
mListeners.get(i).onMoveToFullscreen();
|
||||
}
|
||||
try {
|
||||
mActivityManager.moveTasksToFullscreenStack(PINNED_STACK_ID, true);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "moveTasksToFullscreenStack failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows PIP overlay UI by launching {@link PipOverlayActivity}. It also locates the pinned
|
||||
* stack to the default PIP bound {@link com.android.internal.R.string
|
||||
* .config_defaultPictureInPictureBounds}.
|
||||
*/
|
||||
public void showPipOverlay() {
|
||||
if (DEBUG) Log.d(TAG, "showPipOverlay()");
|
||||
try {
|
||||
mActivityManager.resizeStack(PINNED_STACK_ID, mPipBound, false);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "resizeStack failed", e);
|
||||
closePip();
|
||||
return;
|
||||
}
|
||||
mState = STATE_PIP_OVERLAY;
|
||||
launchPipOverlayActivity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows PIP menu UI by launching {@link PipMenuActivity}. It also locates the pinned
|
||||
* stack to the centered PIP bound {@link com.android.internal.R.string
|
||||
* .config_centeredPictureInPictureBounds}.
|
||||
*/
|
||||
public void showPipMenu() {
|
||||
if (DEBUG) Log.d(TAG, "showPipMenu()");
|
||||
try {
|
||||
mActivityManager.resizeStack(PINNED_STACK_ID, mMenuModePipBound, false);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "resizeStack failed", e);
|
||||
closePip();
|
||||
return;
|
||||
}
|
||||
mState = STATE_PIP_MENU;
|
||||
for (int i = mListeners.size() - 1; i >= 0; --i) {
|
||||
mListeners.get(i).onShowPipMenu();
|
||||
}
|
||||
Intent intent = new Intent(mContext, PipMenuActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final ActivityOptions options = ActivityOptions.makeBasic();
|
||||
options.setLaunchStackId(PINNED_STACK_ID);
|
||||
mContext.startActivity(intent, options.toBundle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds {@link Listener}.
|
||||
*/
|
||||
public void addListener(Listener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes {@link Listener}.
|
||||
*/
|
||||
public void removeListener(Listener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
private void launchPipOverlayActivity() {
|
||||
Intent intent = new Intent(mContext, PipOverlayActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final ActivityOptions options = ActivityOptions.makeBasic();
|
||||
options.setLaunchStackId(PINNED_STACK_ID);
|
||||
mContext.startActivity(intent, options.toBundle());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private class TaskStackListener extends ITaskStackListener.Stub {
|
||||
@Override
|
||||
public void onTaskStackChanged() throws RemoteException {
|
||||
// Post the message back to the UI thread.
|
||||
mHandler.post(mOnTaskStackChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPinned() throws RemoteException {
|
||||
// Post the message back to the UI thread.
|
||||
mHandler.post(mOnActivityPinnedRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener interface to receive notification on changes in PIP.
|
||||
*/
|
||||
public interface Listener {
|
||||
/**
|
||||
* Invoked when a PIPped activity is closed.
|
||||
*/
|
||||
void onPipActivityClosed();
|
||||
/**
|
||||
* Invoked when the PIP menu gets shown.
|
||||
*/
|
||||
void onShowPipMenu();
|
||||
/**
|
||||
* Invoked when the PIPped activity is returned back to the fullscreen.
|
||||
*/
|
||||
void onMoveToFullscreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of {@link PipManager}.
|
||||
*/
|
||||
public static PipManager getInstance() {
|
||||
if (sPipManager == null) {
|
||||
sPipManager = new PipManager();
|
||||
}
|
||||
return sPipManager;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.tv.pip;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.media.session.MediaController;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
/**
|
||||
* Activity to show the PIP menu to control PIP.
|
||||
*/
|
||||
public class PipMenuActivity extends Activity implements PipManager.Listener {
|
||||
private static final String TAG = "PipMenuActivity";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final PipManager mPipManager = PipManager.getInstance();
|
||||
private MediaController mMediaController;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
setContentView(R.layout.tv_pip_menu);
|
||||
mPipManager.addListener(this);
|
||||
findViewById(R.id.full).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mPipManager.movePipToFullscreen();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mPipManager.closePip();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mPipManager.showPipOverlay();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
mPipManager.removeListener(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
mPipManager.showPipOverlay();
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipActivityClosed() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPipMenu() { }
|
||||
|
||||
@Override
|
||||
public void onMoveToFullscreen() {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.tv.pip;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
/**
|
||||
* Activity to show an overlay on top of PIP activity to show how to pop up PIP menu.
|
||||
*/
|
||||
public class PipOverlayActivity extends Activity implements PipManager.Listener {
|
||||
private static final String TAG = "PipOverlayActivity";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final long SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS = 2000;
|
||||
|
||||
private final PipManager mPipManager = PipManager.getInstance();
|
||||
private final Handler mHandler = new Handler();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
setContentView(R.layout.tv_pip_overlay);
|
||||
mPipManager.addListener(this);
|
||||
final View overlayView = findViewById(R.id.guide_overlay);
|
||||
// TODO: apply animation
|
||||
overlayView.setVisibility(View.VISIBLE);
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
overlayView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}, SHOW_GUIDE_OVERLAY_VIEW_DURATION_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
mPipManager.removeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipActivityClosed() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPipMenu() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoveToFullscreen() {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
53
packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
Normal file
53
packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.tv.pip;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import com.android.systemui.SystemUI;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
|
||||
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
|
||||
|
||||
/**
|
||||
* Controls the picture-in-picture window for TV devices.
|
||||
*/
|
||||
public class PipUI extends SystemUI {
|
||||
private boolean mSupportPip;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
mSupportPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)
|
||||
&& pm.hasSystemFeature(FEATURE_LEANBACK);
|
||||
if (!mSupportPip) {
|
||||
return;
|
||||
}
|
||||
PipManager pipManager = PipManager.getInstance();
|
||||
pipManager.initialize(mContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
if (!mSupportPip) {
|
||||
return;
|
||||
}
|
||||
// TODO: handle configuration change.
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user