Merge "Consolidate PiP demos in ApiDemos app"
This commit is contained in:
@@ -290,45 +290,9 @@
|
||||
android:label="@string/activity_picture_in_picture"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:configChanges=
|
||||
"screenSize|smallestScreenSize|screenLayout|orientation">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".app.PictureInPictureAutoEnter"
|
||||
android:label="@string/activity_picture_in_picture_auto_enter"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:theme="@style/Theme.NoActionBar"
|
||||
android:configChanges=
|
||||
"screenSize|smallestScreenSize|screenLayout|orientation">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".app.PictureInPictureSeamlessResize"
|
||||
android:label="@string/activity_picture_in_picture_seamless_resize"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:configChanges=
|
||||
"screenSize|smallestScreenSize|screenLayout|orientation">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".app.PictureInPictureSourceRectHint"
|
||||
android:label="@string/activity_picture_in_picture_source_rect_hint"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:configChanges=
|
||||
"screenSize|smallestScreenSize|screenLayout|orientation">
|
||||
"screenSize|smallestScreenSize|screenLayout|orientation">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||
|
||||
@@ -15,18 +15,106 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- Demonstrates implementation of picture-in-picture. -->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:padding="4dp"
|
||||
android:gravity="center_horizontal"
|
||||
<!--
|
||||
Demonstrates Picture-In-Picture with various configurations.
|
||||
- Enter PiP with on-screen button
|
||||
- Enter PiP by swiping up to home or tap on home button
|
||||
- Toggle the auto enter PiP flag on and off
|
||||
- Toggle the source rect hint on and off
|
||||
- Toggle the seamless resize flag on and off
|
||||
- Change the position of current and next source rect hint
|
||||
- Tablet layout on foldables
|
||||
- Enter content PiP
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button android:layout_width="wrap_content"
|
||||
<!-- layout params would be changed programmatically -->
|
||||
<com.example.android.apis.view.FixedAspectRatioImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/enter_pip"
|
||||
android:text="@string/enter_picture_in_picture">
|
||||
</Button>
|
||||
</LinearLayout>
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/sample_1"
|
||||
app:aspectRatio="16/9" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/control_group"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Switch
|
||||
android:id="@+id/auto_pip_toggle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/activity_picture_in_picture_auto_pip_toggle" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/source_rect_hint_toggle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/activity_picture_in_picture_source_rect_hint_toggle" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/seamless_resize_toggle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/activity_picture_in_picture_seamless_resize_toggle" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/current_position"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_current_position" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radio_current_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_position_start" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radio_current_end"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/label_position_end" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<Button
|
||||
android:id="@+id/enter_pip_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_picture_in_picture" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/enter_content_pip_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_content_pip" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<!-- Demonstrates Picture-In-Picture with auto enter enabled. -->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- layout params would be changed programmatically -->
|
||||
<com.example.android.apis.view.FixedAspectRatioImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/sample_1"
|
||||
app:aspectRatio="16/9" />
|
||||
|
||||
<Switch android:id="@+id/source_rect_hint_toggle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/activity_picture_in_picture_source_rect_hint_toggle" />
|
||||
|
||||
<Button android:id="@+id/change_orientation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/activity_picture_in_picture_change_orientation" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<!-- Demonstrates Picture-In-Picture's Seamless Resize. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:text="@string/activity_picture_in_picture_seamless_resize_demo_text"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
<Switch
|
||||
android:id="@+id/seamless_resize_switch"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/activity_picture_in_picture_seamless_resize_switch"
|
||||
android:checked="false"
|
||||
android:background="@android:color/white"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,56 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<!-- Demonstrates Picture-In-Picture's Source Rect Hint usage. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/frame_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/entry_source_btn">
|
||||
|
||||
<VideoView
|
||||
android:id="@+id/video_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/entry_source_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/exit_source_btn"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/exit_source_btn"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -63,21 +63,19 @@
|
||||
<string name="screen_orientation">Screen Orientation</string>
|
||||
|
||||
<string name="activity_picture_in_picture">App/Activity/Picture in Picture</string>
|
||||
<string name="activity_picture_in_picture_auto_enter">App/Activity/Picture in Picture Auto Enter</string>
|
||||
<string name="activity_picture_in_picture_source_rect_hint_toggle">Toggle source rect hint</string>
|
||||
<string name="activity_picture_in_picture_seamless_resize">App/Activity/Picture in Picture Seamless Resize</string>
|
||||
<string name="activity_picture_in_picture_source_rect_hint">App/Activity/Picture in Picture Source Rect Hint</string>
|
||||
<string name="activity_picture_in_picture_source_rect_hint_current_position">Current position: %1$s</string>
|
||||
<string name="activity_picture_in_picture_source_rect_hint_position_on_exit">Position on exit: %1$s</string>
|
||||
<string name="activity_picture_in_picture_change_orientation">Change orientation</string>
|
||||
<string name="activity_picture_in_picture_seamless_resize_switch">Turn on Seamless Resize (recommend off)</string>
|
||||
<string name="activity_picture_in_picture_seamless_resize_demo_text">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</string>
|
||||
<string name="activity_picture_in_picture_auto_pip_toggle">Enable auto PiP</string>
|
||||
<string name="activity_picture_in_picture_source_rect_hint_toggle">Enable source rect hint</string>
|
||||
<string name="activity_picture_in_picture_seamless_resize_toggle">Enable seamless resize</string>
|
||||
<string name="enter_content_pip">Enter content PiP</string>
|
||||
<string name="enter_picture_in_picture">Manually enter PiP</string>
|
||||
<string name="label_current_position">Current position</string>
|
||||
<string name="label_exit_position">Exit position</string>
|
||||
<string name="label_position_start">Start</string>
|
||||
<string name="label_position_end">End</string>
|
||||
|
||||
<string name="activity_max_aspect_ratio_square">App/Activity/Max Aspect Ratio/1:1</string>
|
||||
<string name="activity_max_aspect_ratio_16to9">App/Activity/Max Aspect Ratio/16:9</string>
|
||||
<string name="activity_max_aspect_ratio_any">App/Activity/Max Aspect Ratio/Any</string>
|
||||
<string name="enter_picture_in_picture">Enter picture-in-picture mode</string>
|
||||
|
||||
<string name="activity_translucent">App/Activity/Translucent</string>
|
||||
<string name="translucent_background">Example of how you can make an
|
||||
|
||||
@@ -17,26 +17,251 @@
|
||||
package com.example.android.apis.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
import android.util.Rational;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Switch;
|
||||
|
||||
import com.example.android.apis.R;
|
||||
|
||||
public class PictureInPicture extends Activity {
|
||||
private static final String EXTRA_ENABLE_AUTO_PIP = "auto_pip";
|
||||
private static final String EXTRA_ENABLE_SOURCE_RECT_HINT = "source_rect_hint";
|
||||
private static final String EXTRA_ENABLE_SEAMLESS_RESIZE = "seamless_resize";
|
||||
private static final String EXTRA_CURRENT_POSITION = "current_position";
|
||||
|
||||
private Button mEnterPip;
|
||||
private final View.OnLayoutChangeListener mOnLayoutChangeListener =
|
||||
(v, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight, newBottom) -> {
|
||||
updatePictureInPictureParams();
|
||||
};
|
||||
|
||||
private final CompoundButton.OnCheckedChangeListener mOnToggleChangedListener =
|
||||
(v, isChecked) -> updatePictureInPictureParams();
|
||||
|
||||
private final RadioGroup.OnCheckedChangeListener mOnPositionChangedListener =
|
||||
(v, id) -> updateContentPosition(id);
|
||||
|
||||
private LinearLayout mContainer;
|
||||
private View mImageView;
|
||||
private View mControlGroup;
|
||||
private Switch mAutoPipToggle;
|
||||
private Switch mSourceRectHintToggle;
|
||||
private Switch mSeamlessResizeToggle;
|
||||
private RadioGroup mCurrentPositionGroup;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.picture_in_picture);
|
||||
|
||||
mEnterPip = (Button)findViewById(R.id.enter_pip);
|
||||
mEnterPip.setOnClickListener((v) -> enterPictureInPictureMode());
|
||||
// Find views
|
||||
mContainer = findViewById(R.id.container);
|
||||
mImageView = findViewById(R.id.image);
|
||||
mControlGroup = findViewById(R.id.control_group);
|
||||
mAutoPipToggle = findViewById(R.id.auto_pip_toggle);
|
||||
mSourceRectHintToggle = findViewById(R.id.source_rect_hint_toggle);
|
||||
mSeamlessResizeToggle = findViewById(R.id.seamless_resize_toggle);
|
||||
mCurrentPositionGroup = findViewById(R.id.current_position);
|
||||
|
||||
// Attach listeners
|
||||
mImageView.addOnLayoutChangeListener(mOnLayoutChangeListener);
|
||||
mAutoPipToggle.setOnCheckedChangeListener(mOnToggleChangedListener);
|
||||
mSourceRectHintToggle.setOnCheckedChangeListener(mOnToggleChangedListener);
|
||||
mSeamlessResizeToggle.setOnCheckedChangeListener(mOnToggleChangedListener);
|
||||
mCurrentPositionGroup.setOnCheckedChangeListener(mOnPositionChangedListener);
|
||||
findViewById(R.id.enter_pip_button).setOnClickListener(v -> enterPictureInPictureMode());
|
||||
findViewById(R.id.enter_content_pip_button).setOnClickListener(v -> enterContentPip());
|
||||
|
||||
// Set defaults
|
||||
final Intent intent = getIntent();
|
||||
mAutoPipToggle.setChecked(intent.getBooleanExtra(EXTRA_ENABLE_AUTO_PIP, false));
|
||||
mSourceRectHintToggle.setChecked(
|
||||
intent.getBooleanExtra(EXTRA_ENABLE_SOURCE_RECT_HINT, false));
|
||||
mSeamlessResizeToggle.setChecked(
|
||||
intent.getBooleanExtra(EXTRA_ENABLE_SEAMLESS_RESIZE, false));
|
||||
final int positionId = "end".equalsIgnoreCase(
|
||||
intent.getStringExtra(EXTRA_CURRENT_POSITION))
|
||||
? R.id.radio_current_end
|
||||
: R.id.radio_current_start;
|
||||
mCurrentPositionGroup.check(positionId);
|
||||
|
||||
updateLayout(getResources().getConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUserLeaveHint() {
|
||||
enterPictureInPictureMode();
|
||||
// Only used when auto PiP is disabled. This is to simulate the behavior that an app
|
||||
// supports regular PiP but not auto PiP.
|
||||
if (!mAutoPipToggle.isChecked()) {
|
||||
enterPictureInPictureMode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfiguration) {
|
||||
super.onConfigurationChanged(newConfiguration);
|
||||
updateLayout(newConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
|
||||
Configuration newConfig) {
|
||||
if (!isInPictureInPictureMode) {
|
||||
// When it's about to exit PiP mode, always reset the mImageView position to start.
|
||||
// If position is previously set to end, this should demonstrate the exit
|
||||
// source rect hint behavior introduced in S.
|
||||
mCurrentPositionGroup.check(R.id.radio_current_start);
|
||||
}
|
||||
}
|
||||
|
||||
private void enterContentPip() {
|
||||
// TBD
|
||||
}
|
||||
|
||||
private void updateLayout(Configuration configuration) {
|
||||
mImageView.addOnLayoutChangeListener(mOnLayoutChangeListener);
|
||||
final boolean isTablet = configuration.screenWidthDp >= 800;
|
||||
final boolean isLandscape =
|
||||
(configuration.orientation == Configuration.ORIENTATION_LANDSCAPE);
|
||||
final boolean isPictureInPicture = isInPictureInPictureMode();
|
||||
if (isPictureInPicture) {
|
||||
setupPictureInPictureLayout();
|
||||
} else if (isTablet && isLandscape) {
|
||||
setupTabletLandscapeLayout();
|
||||
} else if (isLandscape) {
|
||||
setupFullScreenLayout();
|
||||
} else {
|
||||
setupRegularLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPictureInPictureLayout() {
|
||||
mControlGroup.setVisibility(View.GONE);
|
||||
final LinearLayout.LayoutParams imageLp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
imageLp.gravity = Gravity.NO_GRAVITY;
|
||||
mImageView.setLayoutParams(imageLp);
|
||||
}
|
||||
|
||||
private void setupTabletLandscapeLayout() {
|
||||
mControlGroup.setVisibility(View.VISIBLE);
|
||||
exitFullScreenMode();
|
||||
|
||||
final LinearLayout.LayoutParams imageLp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
imageLp.gravity = Gravity.NO_GRAVITY;
|
||||
enterTwoPaneMode(imageLp);
|
||||
}
|
||||
|
||||
private void setupFullScreenLayout() {
|
||||
mControlGroup.setVisibility(View.GONE);
|
||||
enterFullScreenMode();
|
||||
|
||||
final LinearLayout.LayoutParams imageLp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
imageLp.gravity = Gravity.CENTER_HORIZONTAL;
|
||||
enterOnePaneMode(imageLp);
|
||||
}
|
||||
|
||||
private void setupRegularLayout() {
|
||||
mControlGroup.setVisibility(View.VISIBLE);
|
||||
exitFullScreenMode();
|
||||
|
||||
final LinearLayout.LayoutParams imageLp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
imageLp.gravity = Gravity.NO_GRAVITY;
|
||||
enterOnePaneMode(imageLp);
|
||||
}
|
||||
|
||||
private void enterOnePaneMode(LinearLayout.LayoutParams imageLp) {
|
||||
mContainer.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
final LinearLayout.LayoutParams controlLp =
|
||||
(LinearLayout.LayoutParams) mControlGroup.getLayoutParams();
|
||||
controlLp.width = LinearLayout.LayoutParams.MATCH_PARENT;
|
||||
controlLp.height = 0;
|
||||
controlLp.weight = 1;
|
||||
mControlGroup.setLayoutParams(controlLp);
|
||||
|
||||
imageLp.weight = 0;
|
||||
mImageView.setLayoutParams(imageLp);
|
||||
}
|
||||
|
||||
private void enterTwoPaneMode(LinearLayout.LayoutParams imageLp) {
|
||||
mContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
final LinearLayout.LayoutParams controlLp =
|
||||
(LinearLayout.LayoutParams) mControlGroup.getLayoutParams();
|
||||
controlLp.width = 0;
|
||||
controlLp.height = LinearLayout.LayoutParams.MATCH_PARENT;
|
||||
controlLp.weight = 1;
|
||||
mControlGroup.setLayoutParams(controlLp);
|
||||
|
||||
imageLp.width = 0;
|
||||
imageLp.height = LinearLayout.LayoutParams.WRAP_CONTENT;
|
||||
imageLp.weight = 1;
|
||||
mImageView.setLayoutParams(imageLp);
|
||||
}
|
||||
|
||||
private void enterFullScreenMode() {
|
||||
// TODO(b/188001699) switch to use insets controller once the bug is fixed.
|
||||
final View decorView = getWindow().getDecorView();
|
||||
final int systemUiNavigationBarFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
decorView.setSystemUiVisibility(decorView.getSystemUiVisibility()
|
||||
| systemUiNavigationBarFlags);
|
||||
}
|
||||
|
||||
private void exitFullScreenMode() {
|
||||
final View decorView = getWindow().getDecorView();
|
||||
final int systemUiNavigationBarFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
decorView.setSystemUiVisibility(decorView.getSystemUiVisibility()
|
||||
& ~systemUiNavigationBarFlags);
|
||||
}
|
||||
|
||||
private void updatePictureInPictureParams() {
|
||||
mImageView.removeOnLayoutChangeListener(mOnLayoutChangeListener);
|
||||
// do not bother PictureInPictureParams update when it's already in pip mode.
|
||||
if (isInPictureInPictureMode()) return;
|
||||
final Rect imageViewRect = new Rect();
|
||||
mImageView.getGlobalVisibleRect(imageViewRect);
|
||||
// bail early if mImageView has not been measured yet
|
||||
if (imageViewRect.isEmpty()) return;
|
||||
final PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder()
|
||||
.setAutoEnterEnabled(mAutoPipToggle.isChecked())
|
||||
.setSourceRectHint(mSourceRectHintToggle.isChecked()
|
||||
? new Rect(imageViewRect) : null)
|
||||
.setSeamlessResizeEnabled(mSeamlessResizeToggle.isChecked())
|
||||
.setAspectRatio(new Rational(imageViewRect.width(), imageViewRect.height()));
|
||||
setPictureInPictureParams(builder.build());
|
||||
}
|
||||
|
||||
private void updateContentPosition(int checkedId) {
|
||||
mContainer.removeAllViews();
|
||||
mImageView.addOnLayoutChangeListener(mOnLayoutChangeListener);
|
||||
if (checkedId == R.id.radio_current_start) {
|
||||
mContainer.addView(mImageView, 0);
|
||||
mContainer.addView(mControlGroup, 1);
|
||||
} else {
|
||||
mContainer.addView(mControlGroup, 0);
|
||||
mContainer.addView(mImageView, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.example.android.apis.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.util.Rational;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Switch;
|
||||
|
||||
import com.example.android.apis.R;
|
||||
|
||||
public class PictureInPictureAutoEnter extends Activity {
|
||||
private final View.OnLayoutChangeListener mOnLayoutChangeListener =
|
||||
(v, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight, newBottom) -> {
|
||||
updatePictureInPictureParams();
|
||||
};
|
||||
|
||||
private final CompoundButton.OnCheckedChangeListener mOnCheckedChangeListener =
|
||||
(v, isChecked) -> updatePictureInPictureParams();
|
||||
|
||||
private View mImageView;
|
||||
private View mButtonView;
|
||||
private Switch mSwitchView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.picture_in_picture_auto_enter);
|
||||
|
||||
mImageView = findViewById(R.id.image);
|
||||
mImageView.addOnLayoutChangeListener(mOnLayoutChangeListener);
|
||||
mButtonView = findViewById(R.id.change_orientation);
|
||||
mButtonView.setOnClickListener((v) -> {
|
||||
final int orientation = getResources().getConfiguration().orientation;
|
||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
} else {
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
});
|
||||
mSwitchView = findViewById(R.id.source_rect_hint_toggle);
|
||||
mSwitchView.setOnCheckedChangeListener(mOnCheckedChangeListener);
|
||||
|
||||
// there is a bug that setSourceRectHint(null) does not clear the source rect hint
|
||||
// once there is a non-null source rect hint ever been set. set this to false by default
|
||||
// therefore this demo activity can be used for testing autoEnterPip behavior without
|
||||
// source rect hint when launched for the first time.
|
||||
mSwitchView.setChecked(false);
|
||||
|
||||
updateLayout(getResources().getConfiguration());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfiguration) {
|
||||
super.onConfigurationChanged(newConfiguration);
|
||||
updateLayout(newConfiguration);
|
||||
}
|
||||
|
||||
private void updateLayout(Configuration configuration) {
|
||||
final boolean isLandscape =
|
||||
(configuration.orientation == Configuration.ORIENTATION_LANDSCAPE);
|
||||
final boolean isPictureInPicture = isInPictureInPictureMode();
|
||||
mButtonView.setVisibility((isPictureInPicture || isLandscape) ? View.GONE : View.VISIBLE);
|
||||
mSwitchView.setVisibility((isPictureInPicture || isLandscape) ? View.GONE: View.VISIBLE);
|
||||
final LinearLayout.LayoutParams layoutParams;
|
||||
if (isPictureInPicture) {
|
||||
layoutParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
layoutParams.gravity = Gravity.NO_GRAVITY;
|
||||
} else {
|
||||
// Toggle the fullscreen mode as well.
|
||||
// TODO(b/188001699) switch to use insets controller once the bug is fixed.
|
||||
final View decorView = getWindow().getDecorView();
|
||||
final int systemUiNavigationBarFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
|
||||
if (isLandscape) {
|
||||
layoutParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
layoutParams.gravity = Gravity.CENTER_HORIZONTAL;
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
decorView.setSystemUiVisibility(decorView.getSystemUiVisibility()
|
||||
| systemUiNavigationBarFlags);
|
||||
} else {
|
||||
layoutParams = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.gravity = Gravity.NO_GRAVITY;
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
decorView.setSystemUiVisibility(decorView.getSystemUiVisibility()
|
||||
& ~systemUiNavigationBarFlags);
|
||||
}
|
||||
}
|
||||
mImageView.addOnLayoutChangeListener(mOnLayoutChangeListener);
|
||||
mImageView.setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
private void updatePictureInPictureParams() {
|
||||
mImageView.removeOnLayoutChangeListener(mOnLayoutChangeListener);
|
||||
// do not bother PictureInPictureParams update when it's already in pip mode.
|
||||
if (isInPictureInPictureMode()) return;
|
||||
final Rect imageViewRect = new Rect();
|
||||
mImageView.getGlobalVisibleRect(imageViewRect);
|
||||
// bail early if mImageView has not been measured yet
|
||||
if (imageViewRect.isEmpty()) return;
|
||||
final Rect sourceRectHint = mSwitchView.isChecked() ? new Rect(imageViewRect) : null;
|
||||
final PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder()
|
||||
.setAutoEnterEnabled(true)
|
||||
.setAspectRatio(new Rational(imageViewRect.width(), imageViewRect.height()))
|
||||
.setSourceRectHint(sourceRectHint);
|
||||
setPictureInPictureParams(builder.build());
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.example.android.apis.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Switch;
|
||||
|
||||
import com.example.android.apis.R;
|
||||
|
||||
public class PictureInPictureSeamlessResize extends Activity {
|
||||
|
||||
private Switch mSwitchView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getActionBar().hide();
|
||||
setContentView(R.layout.picture_in_picture_seamless_resize);
|
||||
|
||||
mSwitchView = findViewById(R.id.seamless_resize_switch);
|
||||
mSwitchView.setOnCheckedChangeListener((v, isChecked) -> {
|
||||
onSeamlessResizeCheckedChanged(isChecked);
|
||||
});
|
||||
onSeamlessResizeCheckedChanged(mSwitchView.isChecked());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
|
||||
Configuration newConfig) {
|
||||
mSwitchView.setVisibility(isInPictureInPictureMode ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPictureInPictureRequested() {
|
||||
enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onSeamlessResizeCheckedChanged(boolean checked) {
|
||||
final PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder()
|
||||
.setSeamlessResizeEnabled(checked);
|
||||
setPictureInPictureParams(builder.build());
|
||||
}
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.example.android.apis.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Rational;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.VideoView;
|
||||
|
||||
import com.example.android.apis.R;
|
||||
|
||||
public class PictureInPictureSourceRectHint extends Activity {
|
||||
|
||||
private FrameLayout mFrameLayout;
|
||||
private VideoView mVideoView;
|
||||
private Button mEntryButton;
|
||||
private Button mExitButton;
|
||||
|
||||
private int mPositionOnEntry;
|
||||
private int mPositionOnExit;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getActionBar().hide();
|
||||
setContentView(R.layout.picture_in_picture_source_rect_hint);
|
||||
|
||||
mFrameLayout = findViewById(R.id.frame_layout);
|
||||
mVideoView = findViewById(R.id.video_view);
|
||||
mEntryButton = findViewById(R.id.entry_source_btn);
|
||||
mExitButton = findViewById(R.id.exit_source_btn);
|
||||
|
||||
initPlayer(Uri.parse("android.resource://" + getPackageName() +
|
||||
"/" + R.raw.videoviewdemo));
|
||||
|
||||
|
||||
setEntryState(Gravity.TOP);
|
||||
setExitState(Gravity.TOP);
|
||||
|
||||
mEntryButton.setOnClickListener(v -> {
|
||||
// Toggle the position and update the views.
|
||||
setEntryState(mPositionOnEntry == Gravity.TOP ? Gravity.BOTTOM : Gravity.TOP);
|
||||
});
|
||||
mExitButton.setOnClickListener(v -> {
|
||||
// Toggle the position and update the views.
|
||||
setExitState(mPositionOnExit == Gravity.TOP ? Gravity.BOTTOM : Gravity.TOP);
|
||||
});
|
||||
|
||||
mVideoView.addOnLayoutChangeListener(
|
||||
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
||||
if (left == oldLeft && right == oldRight && top == oldTop
|
||||
&& bottom == oldBottom) return;
|
||||
|
||||
setPictureInPictureParams(new PictureInPictureParams.Builder()
|
||||
.setSourceRectHint(getVideoRectHint())
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mVideoView.stopPlayback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,
|
||||
Configuration newConfig) {
|
||||
mEntryButton.setVisibility(isInPictureInPictureMode ? View.GONE : View.VISIBLE);
|
||||
mExitButton.setVisibility(isInPictureInPictureMode ? View.GONE : View.VISIBLE);
|
||||
|
||||
final FrameLayout.LayoutParams params;
|
||||
if (isInPictureInPictureMode) {
|
||||
// In PIP mode the video should take up the full width and height.
|
||||
params = new FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
|
||||
} else {
|
||||
// Exiting PIP, return the video to its original size and place it to the preferred
|
||||
// gravity selected before entering PIP mode.
|
||||
params = new FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||
params.gravity = mPositionOnExit;
|
||||
// The "exit" gravity becomes the current "entry" gravity, update it and its views.
|
||||
setEntryState(mPositionOnExit);
|
||||
}
|
||||
mVideoView.setLayoutParams(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPictureInPictureRequested() {
|
||||
final Rect hint = getVideoRectHint();
|
||||
enterPictureInPictureMode(new PictureInPictureParams.Builder()
|
||||
.setSourceRectHint(hint)
|
||||
.setAspectRatio(new Rational(hint.width(), hint.height()))
|
||||
.build());
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initPlayer(Uri uri) {
|
||||
mVideoView.setVideoURI(uri);
|
||||
mVideoView.requestFocus();
|
||||
mVideoView.setOnPreparedListener(mp -> {
|
||||
mp.setLooping(true);
|
||||
mVideoView.start();
|
||||
});
|
||||
}
|
||||
|
||||
private Rect getVideoRectHint() {
|
||||
final Rect hint = new Rect();
|
||||
mVideoView.getGlobalVisibleRect(hint);
|
||||
return hint;
|
||||
}
|
||||
|
||||
private void setEntryState(int gravity) {
|
||||
mPositionOnEntry = gravity;
|
||||
mEntryButton.setText(getString(
|
||||
R.string.activity_picture_in_picture_source_rect_hint_current_position,
|
||||
getGravityName(mPositionOnEntry)));
|
||||
final FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) mVideoView.getLayoutParams();
|
||||
p.gravity = mPositionOnEntry;
|
||||
mVideoView.setLayoutParams(p);
|
||||
}
|
||||
|
||||
private void setExitState(int gravity) {
|
||||
mPositionOnExit = gravity;
|
||||
mExitButton.setText(getString(
|
||||
R.string.activity_picture_in_picture_source_rect_hint_position_on_exit,
|
||||
getGravityName(mPositionOnExit)));
|
||||
}
|
||||
|
||||
private String getGravityName(int gravity) {
|
||||
return gravity == Gravity.TOP ? "TOP" : "BOTTOM";
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,6 @@ public class FixedAspectRatioImageView extends ImageView {
|
||||
height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
width = (int) (height * mAspectRatio.floatValue());
|
||||
}
|
||||
android.util.Log.d("DebugMe", "onMeasure w=" + width + " h=" + height);
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user