Here is another solution which uses fragments to show a scaled UI. Unlike my previous solution, this solution has the advantage to be able to show a UI which is optimized for the PIP mode. (E.g. some views can be hidden in the PIP mode.)
Following code uses onPictureInPictureModeChanged() to listen for a mode change and changes the UI at the next restart. (Because the toolbar is not needed in PIP mode, it is hidden before the PIP mode is entered.)
public class Activity extends AppCompatActivity {
private static final String FRAGMENT_TAG_FULL = "fragment_full";
private static final String FRAGMENT_TAG_PIP = "fragment_pip";
private MyApplication mApplication;
private Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApplication = (MyApplication) getApplicationContext();
setContentView(R.layout.activity);
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
if (!mApplication.inPipMode) {
showFullFragment();
} else {
showPipFragment();
}
}
@Override
protected void onUserLeaveHint() {
mToolbar.setVisibility(View.GONE);
PictureInPictureParams params = new PictureInPictureParams.Builder().build();
enterPictureInPictureMode(params);
}
@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
if (isInPictureInPictureMode) {
mApplication.inPipMode = true;
} else {
mApplication.inPipMode = false;
}
}
private void showFullFragment() {
Fragment fragment = new FragmentFull();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container_content, fragment, FRAGMENT_TAG_FULL)
.commit();
mToolbar.setVisibility(View.VISIBLE);
}
private void showPipFragment() {
Fragment fragment = new FragmentPip();
getSupportFragmentManager().beginTransaction()
.replace(R.id.container_content, fragment, FRAGMENT_TAG_PIP)
.commit();
mToolbar.setVisibility(View.GONE);
}
}
Because onUserLeaveHint() - which starts the PIP mode - is called after onSaveInstanceState() the current mode can't be stored in a field of the activity class. It must be stored somewhere else where it survives a configuration change. A field in the application class is used here.
public class MyApplication extends Application {
public boolean inPipMode = false;
}
Fragment layout for full screen mode:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Hello World!"
android:textSize="36sp" />
<TextView
android:id="@+id/text_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text"
android:layout_centerHorizontal="true"
android:text="🙂"
android:textSize="28sp" />
</RelativeLayout>
Fragment layout for PIP mode:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Hello World!"
android:textSize="10sp"/>
</RelativeLayout>
Result: