Merge "Update split controller to latest extension interface" into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
14c735d9e9
@@ -749,7 +749,8 @@ public class Instrumentation {
|
|||||||
* @see #onStartActivity(Intent)
|
* @see #onStartActivity(Intent)
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public ActivityResult onStartActivity(Context who, Intent intent, Bundle options) {
|
public ActivityResult onStartActivity(@NonNull Context who, @NonNull Intent intent,
|
||||||
|
@NonNull Bundle options) {
|
||||||
return onStartActivity(intent);
|
return onStartActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ package androidx.window.extensions;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
|
||||||
|
import androidx.window.extensions.organizer.EmbeddingExtensionImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provider class that will instantiate the library implementation. It must be included in the
|
* Provider class that will instantiate the library implementation. It must be included in the
|
||||||
* vendor library, and the vendor implementation must match the signature of this class.
|
* vendor library, and the vendor implementation must match the signature of this class.
|
||||||
@@ -31,6 +35,12 @@ public class ExtensionProvider {
|
|||||||
return new SampleExtensionImpl(context);
|
return new SampleExtensionImpl(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Provides a reference implementation of {@link ActivityEmbeddingComponent}. */
|
||||||
|
public static ActivityEmbeddingComponent getActivityEmbeddingExtensionImpl(
|
||||||
|
@NonNull Context context) {
|
||||||
|
return new EmbeddingExtensionImpl();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The support library will use this method to check API version compatibility.
|
* The support library will use this method to check API version compatibility.
|
||||||
* @return API version string in MAJOR.MINOR.PATCH-description format.
|
* @return API version string in MAJOR.MINOR.PATCH-description format.
|
||||||
|
|||||||
@@ -23,19 +23,15 @@ import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.window.common.DeviceStateManagerPostureProducer;
|
import androidx.window.common.DeviceStateManagerPostureProducer;
|
||||||
import androidx.window.common.DisplayFeature;
|
import androidx.window.common.DisplayFeature;
|
||||||
import androidx.window.common.ResourceConfigDisplayFeatureProducer;
|
import androidx.window.common.ResourceConfigDisplayFeatureProducer;
|
||||||
import androidx.window.common.SettingsDevicePostureProducer;
|
import androidx.window.common.SettingsDevicePostureProducer;
|
||||||
import androidx.window.common.SettingsDisplayFeatureProducer;
|
import androidx.window.common.SettingsDisplayFeatureProducer;
|
||||||
import androidx.window.extensions.organizer.SplitController;
|
|
||||||
import androidx.window.util.DataProducer;
|
import androidx.window.util.DataProducer;
|
||||||
import androidx.window.util.PriorityDataProducer;
|
import androidx.window.util.PriorityDataProducer;
|
||||||
|
|
||||||
@@ -60,8 +56,6 @@ class SampleExtensionImpl extends StubExtension {
|
|||||||
private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
|
private final SettingsDisplayFeatureProducer mSettingsDisplayFeatureProducer;
|
||||||
private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
|
private final DataProducer<List<DisplayFeature>> mDisplayFeatureProducer;
|
||||||
|
|
||||||
private final SplitController mSplitController;
|
|
||||||
|
|
||||||
SampleExtensionImpl(Context context) {
|
SampleExtensionImpl(Context context) {
|
||||||
mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
|
mSettingsDevicePostureProducer = new SettingsDevicePostureProducer(context);
|
||||||
mDevicePostureProducer = new PriorityDataProducer<>(List.of(
|
mDevicePostureProducer = new PriorityDataProducer<>(List.of(
|
||||||
@@ -77,8 +71,6 @@ class SampleExtensionImpl extends StubExtension {
|
|||||||
|
|
||||||
mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
mDevicePostureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
||||||
mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
mDisplayFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
|
||||||
|
|
||||||
mSplitController = new SplitController();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getFeatureState(DisplayFeature feature) {
|
private int getFeatureState(DisplayFeature feature) {
|
||||||
@@ -142,28 +134,4 @@ class SampleExtensionImpl extends StubExtension {
|
|||||||
|
|
||||||
onDisplayFeaturesChanged();
|
onDisplayFeaturesChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
|
|
||||||
mSplitController.setSplitRules(splitRules);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NonNull
|
|
||||||
public List<ExtensionSplitRule> getSplitRules() {
|
|
||||||
return new ArrayList<>(mSplitController.getSplitRules());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSplitOrganizerCallback(@Nullable SplitOrganizerCallback callback) {
|
|
||||||
mSplitController.setSplitOrganizerCallback(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
|
|
||||||
@Nullable Bundle options, @NonNull ExtensionSplitPairRule splitPairRule,
|
|
||||||
int startRequestId) {
|
|
||||||
mSplitController.startActivityToSide(launchingActivity, intent, options, splitPairRule,
|
|
||||||
startRequestId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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 androidx.window.extensions.organizer;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
|
||||||
|
import androidx.window.extensions.embedding.EmbeddingRule;
|
||||||
|
import androidx.window.extensions.embedding.SplitInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference implementation of the activity embedding interface defined in WM Jetpack.
|
||||||
|
*/
|
||||||
|
public class EmbeddingExtensionImpl implements ActivityEmbeddingComponent {
|
||||||
|
|
||||||
|
private final SplitController mSplitController;
|
||||||
|
|
||||||
|
public EmbeddingExtensionImpl() {
|
||||||
|
mSplitController = new SplitController();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) {
|
||||||
|
mSplitController.setEmbeddingRules(rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEmbeddingCallback(@NonNull Consumer<List<SplitInfo>> consumer) {
|
||||||
|
mSplitController.setEmbeddingCallback(consumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,9 @@ package androidx.window.extensions.organizer;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
import androidx.window.extensions.ExtensionSplitPairRule;
|
import androidx.window.extensions.embedding.SplitPairRule;
|
||||||
|
import androidx.window.extensions.embedding.SplitPlaceholderRule;
|
||||||
|
import androidx.window.extensions.embedding.SplitRule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client-side descriptor of a split that holds two containers.
|
* Client-side descriptor of a split that holds two containers.
|
||||||
@@ -27,20 +29,26 @@ import androidx.window.extensions.ExtensionSplitPairRule;
|
|||||||
class SplitContainer {
|
class SplitContainer {
|
||||||
private final TaskFragmentContainer mPrimaryContainer;
|
private final TaskFragmentContainer mPrimaryContainer;
|
||||||
private final TaskFragmentContainer mSecondaryContainer;
|
private final TaskFragmentContainer mSecondaryContainer;
|
||||||
private final ExtensionSplitPairRule mSplitPairRule;
|
private final SplitRule mSplitRule;
|
||||||
|
|
||||||
SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
|
SplitContainer(@NonNull TaskFragmentContainer primaryContainer,
|
||||||
@NonNull Activity primaryActivity,
|
@NonNull Activity primaryActivity,
|
||||||
@NonNull TaskFragmentContainer secondaryContainer,
|
@NonNull TaskFragmentContainer secondaryContainer,
|
||||||
@NonNull ExtensionSplitPairRule splitPairRule) {
|
@NonNull SplitRule splitRule) {
|
||||||
mPrimaryContainer = primaryContainer;
|
mPrimaryContainer = primaryContainer;
|
||||||
mSecondaryContainer = secondaryContainer;
|
mSecondaryContainer = secondaryContainer;
|
||||||
mSplitPairRule = splitPairRule;
|
mSplitRule = splitRule;
|
||||||
|
|
||||||
if (mSplitPairRule.finishPrimaryWithSecondary || mSplitPairRule.useAsPlaceholder) {
|
final boolean isPlaceholderContainer = isPlaceholderContainer();
|
||||||
|
final boolean shouldFinishPrimaryWithSecondary = (mSplitRule instanceof SplitPairRule)
|
||||||
|
&& ((SplitPairRule) mSplitRule).shouldFinishPrimaryWithSecondary();
|
||||||
|
final boolean shouldFinishSecondaryWithPrimary = (mSplitRule instanceof SplitPairRule)
|
||||||
|
&& ((SplitPairRule) mSplitRule).shouldFinishSecondaryWithPrimary();
|
||||||
|
|
||||||
|
if (shouldFinishPrimaryWithSecondary || isPlaceholderContainer) {
|
||||||
mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
|
mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
|
||||||
}
|
}
|
||||||
if (mSplitPairRule.finishSecondaryWithPrimary || mSplitPairRule.useAsPlaceholder) {
|
if (shouldFinishSecondaryWithPrimary || isPlaceholderContainer) {
|
||||||
mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
|
mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +64,11 @@ class SplitContainer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
ExtensionSplitPairRule getSplitPairRule() {
|
SplitRule getSplitRule() {
|
||||||
return mSplitPairRule;
|
return mSplitRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isPlaceholderContainer() {
|
||||||
|
return (mSplitRule instanceof SplitPlaceholderRule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import android.app.ActivityOptions;
|
|||||||
import android.app.ActivityThread;
|
import android.app.ActivityThread;
|
||||||
import android.app.Application.ActivityLifecycleCallbacks;
|
import android.app.Application.ActivityLifecycleCallbacks;
|
||||||
import android.app.Instrumentation;
|
import android.app.Instrumentation;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
@@ -32,20 +31,24 @@ import android.os.Bundle;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.util.Pair;
|
||||||
import android.window.TaskFragmentAppearedInfo;
|
import android.window.TaskFragmentAppearedInfo;
|
||||||
import android.window.TaskFragmentInfo;
|
import android.window.TaskFragmentInfo;
|
||||||
import android.window.WindowContainerTransaction;
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
import androidx.window.extensions.ExtensionInterface.SplitOrganizerCallback;
|
import androidx.window.extensions.embedding.ActivityRule;
|
||||||
import androidx.window.extensions.ExtensionSplitActivityRule;
|
import androidx.window.extensions.embedding.EmbeddingRule;
|
||||||
import androidx.window.extensions.ExtensionSplitInfo;
|
import androidx.window.extensions.embedding.SplitInfo;
|
||||||
import androidx.window.extensions.ExtensionSplitPairRule;
|
import androidx.window.extensions.embedding.SplitPairRule;
|
||||||
import androidx.window.extensions.ExtensionSplitRule;
|
import androidx.window.extensions.embedding.SplitPlaceholderRule;
|
||||||
import androidx.window.extensions.ExtensionTaskFragment;
|
import androidx.window.extensions.embedding.SplitRule;
|
||||||
|
import androidx.window.extensions.embedding.TaskFragment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main controller class that manages split states and presentation.
|
* Main controller class that manages split states and presentation.
|
||||||
@@ -55,12 +58,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
private final SplitPresenter mPresenter;
|
private final SplitPresenter mPresenter;
|
||||||
|
|
||||||
// Currently applied split configuration.
|
// Currently applied split configuration.
|
||||||
private final List<ExtensionSplitRule> mSplitRules = new ArrayList<>();
|
private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
|
||||||
private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
|
private final List<TaskFragmentContainer> mContainers = new ArrayList<>();
|
||||||
private final List<SplitContainer> mSplitContainers = new ArrayList<>();
|
private final List<SplitContainer> mSplitContainers = new ArrayList<>();
|
||||||
|
|
||||||
// Callback to Jetpack to notify about changes to split states.
|
// Callback to Jetpack to notify about changes to split states.
|
||||||
private SplitOrganizerCallback mSplitOrganizerCallback;
|
private @NonNull Consumer<List<SplitInfo>> mEmbeddingCallback;
|
||||||
|
|
||||||
public SplitController() {
|
public SplitController() {
|
||||||
mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
|
mPresenter = new SplitPresenter(new MainThreadExecutor(), this);
|
||||||
@@ -73,13 +76,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
instrumentation.addMonitor(new ActivityStartMonitor());
|
instrumentation.addMonitor(new ActivityStartMonitor());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSplitRules(@NonNull List<ExtensionSplitRule> splitRules) {
|
/** Updates the embedding rules applied to future activity launches. */
|
||||||
|
public void setEmbeddingRules(@NonNull Set<EmbeddingRule> rules) {
|
||||||
mSplitRules.clear();
|
mSplitRules.clear();
|
||||||
mSplitRules.addAll(splitRules);
|
mSplitRules.addAll(rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<ExtensionSplitRule> getSplitRules() {
|
public List<EmbeddingRule> getSplitRules() {
|
||||||
return mSplitRules;
|
return mSplitRules;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,22 +91,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* Starts an activity to side of the launchingActivity with the provided split config.
|
* Starts an activity to side of the launchingActivity with the provided split config.
|
||||||
*/
|
*/
|
||||||
public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
|
public void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent intent,
|
||||||
@Nullable Bundle options, @NonNull ExtensionSplitPairRule splitPairRule,
|
@Nullable Bundle options, @NonNull SplitRule sideRule,
|
||||||
int startRequestId) {
|
@NonNull Consumer<Exception> failureCallback) {
|
||||||
try {
|
try {
|
||||||
mPresenter.startActivityToSide(launchingActivity, intent, options, splitPairRule);
|
mPresenter.startActivityToSide(launchingActivity, intent, options, sideRule);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (mSplitOrganizerCallback != null && startRequestId != -1) {
|
failureCallback.accept(e);
|
||||||
mSplitOrganizerCallback.onActivityFailedToStartInContainer(startRequestId, e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the split organizer callback to notify about changes to active splits.
|
* Registers the split organizer callback to notify about changes to active splits.
|
||||||
*/
|
*/
|
||||||
public void setSplitOrganizerCallback(@NonNull SplitOrganizerCallback callback) {
|
public void setEmbeddingCallback(@NonNull Consumer<List<SplitInfo>> callback) {
|
||||||
mSplitOrganizerCallback = callback;
|
mEmbeddingCallback = callback;
|
||||||
updateCallbackIfNecessary();
|
updateCallbackIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,14 +162,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
*/
|
*/
|
||||||
// TODO(b/190433398): Break down into smaller functions.
|
// TODO(b/190433398): Break down into smaller functions.
|
||||||
void onActivityCreated(@NonNull Activity launchedActivity) {
|
void onActivityCreated(@NonNull Activity launchedActivity) {
|
||||||
final ComponentName componentName = launchedActivity.getComponentName();
|
final List<EmbeddingRule> splitRules = getSplitRules();
|
||||||
|
|
||||||
final List<ExtensionSplitRule> splitRules = getSplitRules();
|
|
||||||
final TaskFragmentContainer currentContainer = getContainerWithActivity(
|
final TaskFragmentContainer currentContainer = getContainerWithActivity(
|
||||||
launchedActivity.getActivityToken(), launchedActivity);
|
launchedActivity.getActivityToken(), launchedActivity);
|
||||||
|
|
||||||
// Check if the activity is configured to always be expanded.
|
// Check if the activity is configured to always be expanded.
|
||||||
if (shouldExpand(componentName, splitRules)) {
|
if (shouldExpand(launchedActivity, splitRules)) {
|
||||||
if (shouldContainerBeExpanded(currentContainer)) {
|
if (shouldContainerBeExpanded(currentContainer)) {
|
||||||
// Make sure that the existing container is expanded
|
// Make sure that the existing container is expanded
|
||||||
mPresenter.expandTaskFragment(currentContainer.getTaskFragmentToken());
|
mPresenter.expandTaskFragment(currentContainer.getTaskFragmentToken());
|
||||||
@@ -224,8 +224,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ExtensionSplitPairRule splitPairRule = getSplitRule(
|
final SplitPairRule splitPairRule = getSplitRule(activityBelow, launchedActivity,
|
||||||
activityBelow.getComponentName(), componentName, splitRules);
|
splitRules);
|
||||||
if (splitPairRule == null) {
|
if (splitPairRule == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -302,11 +302,12 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
void registerSplit(@NonNull WindowContainerTransaction wct,
|
void registerSplit(@NonNull WindowContainerTransaction wct,
|
||||||
@NonNull TaskFragmentContainer primaryContainer, @NonNull Activity primaryActivity,
|
@NonNull TaskFragmentContainer primaryContainer, @NonNull Activity primaryActivity,
|
||||||
@NonNull TaskFragmentContainer secondaryContainer,
|
@NonNull TaskFragmentContainer secondaryContainer,
|
||||||
@NonNull ExtensionSplitPairRule splitPairRule) {
|
@NonNull SplitRule splitRule) {
|
||||||
removeExistingSecondaryContainers(wct, primaryContainer);
|
if (splitRule instanceof SplitPairRule && ((SplitPairRule) splitRule).shouldClearTop()) {
|
||||||
|
removeExistingSecondaryContainers(wct, primaryContainer);
|
||||||
|
}
|
||||||
SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
|
SplitContainer splitContainer = new SplitContainer(primaryContainer, primaryActivity,
|
||||||
secondaryContainer, splitPairRule);
|
secondaryContainer, splitRule);
|
||||||
mSplitContainers.add(splitContainer);
|
mSplitContainers.add(splitContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,22 +457,20 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if there is enough space for launch
|
// Check if there is enough space for launch
|
||||||
final ExtensionSplitPairRule placeholderRule = getPlaceholderRule(
|
final SplitPlaceholderRule placeholderRule = getPlaceholderRule(activity);
|
||||||
activity.getComponentName());
|
|
||||||
if (placeholderRule == null || !mPresenter.shouldShowSideBySide(
|
if (placeholderRule == null || !mPresenter.shouldShowSideBySide(
|
||||||
mPresenter.getParentContainerBounds(activity), placeholderRule)) {
|
mPresenter.getParentContainerBounds(activity), placeholderRule)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent placeholderIntent = new Intent();
|
|
||||||
placeholderIntent.setComponent(placeholderRule.secondaryActivityName);
|
|
||||||
// TODO(b/190433398): Handle failed request
|
// TODO(b/190433398): Handle failed request
|
||||||
startActivityToSide(activity, placeholderIntent, null, placeholderRule, -1);
|
startActivityToSide(activity, placeholderRule.getPlaceholderIntent(), null,
|
||||||
|
placeholderRule, null);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) {
|
private boolean dismissPlaceholderIfNecessary(@NonNull SplitContainer splitContainer) {
|
||||||
if (!splitContainer.getSplitPairRule().useAsPlaceholder) {
|
if (!splitContainer.isPlaceholderContainer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,15 +487,14 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* Returns the rule to launch a placeholder for the activity with the provided component name
|
* Returns the rule to launch a placeholder for the activity with the provided component name
|
||||||
* if it is configured in the split config.
|
* if it is configured in the split config.
|
||||||
*/
|
*/
|
||||||
private ExtensionSplitPairRule getPlaceholderRule(@NonNull ComponentName componentName) {
|
private SplitPlaceholderRule getPlaceholderRule(@NonNull Activity activity) {
|
||||||
for (ExtensionSplitRule rule : mSplitRules) {
|
for (EmbeddingRule rule : mSplitRules) {
|
||||||
if (!(rule instanceof ExtensionSplitPairRule)) {
|
if (!(rule instanceof SplitPlaceholderRule)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ExtensionSplitPairRule pairRule = (ExtensionSplitPairRule) rule;
|
SplitPlaceholderRule placeholderRule = (SplitPlaceholderRule) rule;
|
||||||
if (componentName.equals(pairRule.primaryActivityName)
|
if (placeholderRule.getActivityPredicate().test(activity)) {
|
||||||
&& pairRule.useAsPlaceholder) {
|
return placeholderRule;
|
||||||
return pairRule;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -506,27 +504,27 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* Notifies listeners about changes to split states if necessary.
|
* Notifies listeners about changes to split states if necessary.
|
||||||
*/
|
*/
|
||||||
private void updateCallbackIfNecessary() {
|
private void updateCallbackIfNecessary() {
|
||||||
if (mSplitOrganizerCallback == null) {
|
if (mEmbeddingCallback == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO(b/190433398): Check if something actually changed
|
// TODO(b/190433398): Check if something actually changed
|
||||||
mSplitOrganizerCallback.onSplitInfoChanged(getActiveSplitStates());
|
mEmbeddingCallback.accept(getActiveSplitStates());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of descriptors for currently active split states.
|
* Returns a list of descriptors for currently active split states.
|
||||||
*/
|
*/
|
||||||
private List<ExtensionSplitInfo> getActiveSplitStates() {
|
private List<SplitInfo> getActiveSplitStates() {
|
||||||
List<ExtensionSplitInfo> splitStates = new ArrayList<>();
|
List<SplitInfo> splitStates = new ArrayList<>();
|
||||||
for (SplitContainer container : mSplitContainers) {
|
for (SplitContainer container : mSplitContainers) {
|
||||||
ExtensionTaskFragment primaryContainer =
|
TaskFragment primaryContainer =
|
||||||
new ExtensionTaskFragment(
|
new TaskFragment(
|
||||||
container.getPrimaryContainer().collectActivities());
|
container.getPrimaryContainer().collectActivities());
|
||||||
ExtensionTaskFragment secondaryContainer =
|
TaskFragment secondaryContainer =
|
||||||
new ExtensionTaskFragment(
|
new TaskFragment(
|
||||||
container.getSecondaryContainer().collectActivities());
|
container.getSecondaryContainer().collectActivities());
|
||||||
ExtensionSplitInfo splitState = new ExtensionSplitInfo(primaryContainer,
|
SplitInfo splitState = new SplitInfo(primaryContainer,
|
||||||
secondaryContainer, container.getSplitPairRule().splitRatio);
|
secondaryContainer, container.getSplitRule().getSplitRatio());
|
||||||
splitStates.add(splitState);
|
splitStates.add(splitState);
|
||||||
}
|
}
|
||||||
return splitStates;
|
return splitStates;
|
||||||
@@ -550,23 +548,41 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a split rule for the provided pair of component names if available.
|
* Returns a split rule for the provided pair of primary activity and secondary activity intent
|
||||||
|
* if available.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private static ExtensionSplitPairRule getSplitRule(@NonNull ComponentName primaryActivityName,
|
private static SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
|
||||||
@NonNull ComponentName secondaryActivityName,
|
@NonNull Intent secondaryActivityIntent, @NonNull List<EmbeddingRule> splitRules) {
|
||||||
@NonNull List<ExtensionSplitRule> splitRules) {
|
for (EmbeddingRule rule : splitRules) {
|
||||||
if (splitRules == null || primaryActivityName == null || secondaryActivityName == null) {
|
if (!(rule instanceof SplitPairRule)) {
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ExtensionSplitRule rule : splitRules) {
|
|
||||||
if (!(rule instanceof ExtensionSplitPairRule)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ExtensionSplitPairRule pairRule = (ExtensionSplitPairRule) rule;
|
SplitPairRule pairRule = (SplitPairRule) rule;
|
||||||
if (match(secondaryActivityName, pairRule.secondaryActivityName)
|
if (pairRule.getActivityIntentPredicate().test(
|
||||||
&& match(primaryActivityName, pairRule.primaryActivityName)) {
|
new Pair(primaryActivity, secondaryActivityIntent))) {
|
||||||
|
return pairRule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a split rule for the provided pair of primary and secondary activities if available.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static SplitPairRule getSplitRule(@NonNull Activity primaryActivity,
|
||||||
|
@NonNull Activity secondaryActivity, @NonNull List<EmbeddingRule> splitRules) {
|
||||||
|
for (EmbeddingRule rule : splitRules) {
|
||||||
|
if (!(rule instanceof SplitPairRule)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SplitPairRule pairRule = (SplitPairRule) rule;
|
||||||
|
final Intent intent = secondaryActivity.getIntent();
|
||||||
|
if (pairRule.getActivityPairPredicate().test(
|
||||||
|
new Pair(primaryActivity, secondaryActivity))
|
||||||
|
&& (intent == null || pairRule.getActivityIntentPredicate().test(
|
||||||
|
new Pair(primaryActivity, intent)))) {
|
||||||
return pairRule;
|
return pairRule;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -587,55 +603,26 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
* Returns {@code true} if an Activity with the provided component name should always be
|
* Returns {@code true} if an Activity with the provided component name should always be
|
||||||
* expanded to occupy full task bounds. Such activity must not be put in a split.
|
* expanded to occupy full task bounds. Such activity must not be put in a split.
|
||||||
*/
|
*/
|
||||||
private static boolean shouldExpand(@NonNull ComponentName componentName,
|
private static boolean shouldExpand(@NonNull Activity activity,
|
||||||
List<ExtensionSplitRule> splitRules) {
|
List<EmbeddingRule> splitRules) {
|
||||||
if (splitRules == null) {
|
if (splitRules == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (ExtensionSplitRule rule : splitRules) {
|
for (EmbeddingRule rule : splitRules) {
|
||||||
if (!(rule instanceof ExtensionSplitActivityRule)) {
|
if (!(rule instanceof ActivityRule)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ExtensionSplitActivityRule activityRule = (ExtensionSplitActivityRule) rule;
|
ActivityRule activityRule = (ActivityRule) rule;
|
||||||
if (match(componentName, activityRule.activityName)
|
if (!activityRule.shouldAlwaysExpand()) {
|
||||||
&& activityRule.alwaysExpand) {
|
continue;
|
||||||
|
}
|
||||||
|
if (activityRule.getActivityPredicate().test(activity)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Match check allowing wildcards for activity class name but not package name. */
|
|
||||||
private static boolean match(@NonNull ComponentName activityComponent,
|
|
||||||
@NonNull ComponentName ruleComponent) {
|
|
||||||
if (activityComponent.toString().contains("*")) {
|
|
||||||
throw new IllegalArgumentException("Wildcard can only be part of the rule.");
|
|
||||||
}
|
|
||||||
final boolean packagesMatch =
|
|
||||||
activityComponent.getPackageName().equals(ruleComponent.getPackageName());
|
|
||||||
final boolean classesMatch =
|
|
||||||
activityComponent.getClassName().equals(ruleComponent.getClassName());
|
|
||||||
return packagesMatch && (classesMatch
|
|
||||||
|| wildcardMatch(activityComponent.getClassName(), ruleComponent.getClassName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the provided name matches the pattern.
|
|
||||||
*/
|
|
||||||
private static boolean wildcardMatch(@NonNull String name, @NonNull String pattern) {
|
|
||||||
if (!pattern.contains("*")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (pattern.equals("*")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (pattern.indexOf("*") != pattern.lastIndexOf("*") || !pattern.endsWith("*")) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Name pattern with a wildcard must only contain a single * in the end");
|
|
||||||
}
|
|
||||||
return name.startsWith(pattern.substring(0, pattern.length() - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class LifecycleCallbacks implements ActivityLifecycleCallbacks {
|
private final class LifecycleCallbacks implements ActivityLifecycleCallbacks {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -698,8 +685,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
private class ActivityStartMonitor extends Instrumentation.ActivityMonitor {
|
private class ActivityStartMonitor extends Instrumentation.ActivityMonitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Instrumentation.ActivityResult onStartActivity(Context who, Intent intent,
|
public Instrumentation.ActivityResult onStartActivity(@NonNull Context who,
|
||||||
Bundle options) {
|
@NonNull Intent intent, @NonNull Bundle options) {
|
||||||
// TODO(b/190433398): Check if the activity is configured to always be expanded.
|
// TODO(b/190433398): Check if the activity is configured to always be expanded.
|
||||||
|
|
||||||
// Check if activity should be put in a split with the activity that launched it.
|
// Check if activity should be put in a split with the activity that launched it.
|
||||||
@@ -722,8 +709,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
*/
|
*/
|
||||||
private boolean setLaunchingToSideContainer(Activity launchingActivity, Intent intent,
|
private boolean setLaunchingToSideContainer(Activity launchingActivity, Intent intent,
|
||||||
Bundle options) {
|
Bundle options) {
|
||||||
final ExtensionSplitPairRule splitPairRule = getSplitRule(
|
final SplitPairRule splitPairRule = getSplitRule(launchingActivity, intent,
|
||||||
launchingActivity.getComponentName(), intent.getComponent(), getSplitRules());
|
getSplitRules());
|
||||||
if (splitPairRule == null) {
|
if (splitPairRule == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -770,8 +757,8 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ExtensionSplitPairRule splitPairRule = getSplitRule(
|
final SplitPairRule splitPairRule = getSplitRule(primaryActivity, intent,
|
||||||
primaryActivity.getComponentName(), intent.getComponent(), getSplitRules());
|
getSplitRules());
|
||||||
if (splitPairRule == null) {
|
if (splitPairRule == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,16 @@ import android.content.res.Configuration;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.view.WindowInsets;
|
||||||
|
import android.view.WindowMetrics;
|
||||||
import android.window.TaskFragmentCreationParams;
|
import android.window.TaskFragmentCreationParams;
|
||||||
import android.window.WindowContainerTransaction;
|
import android.window.WindowContainerTransaction;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.window.extensions.ExtensionSplitPairRule;
|
import androidx.window.extensions.embedding.SplitPairRule;
|
||||||
|
import androidx.window.extensions.embedding.SplitRule;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@@ -89,7 +92,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
* @return The newly created secondary container.
|
* @return The newly created secondary container.
|
||||||
*/
|
*/
|
||||||
TaskFragmentContainer createNewSplitWithEmptySideContainer(@NonNull Activity primaryActivity,
|
TaskFragmentContainer createNewSplitWithEmptySideContainer(@NonNull Activity primaryActivity,
|
||||||
@NonNull ExtensionSplitPairRule rule) {
|
@NonNull SplitPairRule rule) {
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
|
||||||
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
||||||
@@ -128,7 +131,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
* @param rule The split rule to be applied to the container.
|
* @param rule The split rule to be applied to the container.
|
||||||
*/
|
*/
|
||||||
void createNewSplitContainer(@NonNull Activity primaryActivity,
|
void createNewSplitContainer(@NonNull Activity primaryActivity,
|
||||||
@NonNull Activity secondaryActivity, @NonNull ExtensionSplitPairRule rule) {
|
@NonNull Activity secondaryActivity, @NonNull SplitPairRule rule) {
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
|
|
||||||
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
final Rect parentBounds = getParentContainerBounds(primaryActivity);
|
||||||
@@ -192,7 +195,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
* @param rule The split rule to be applied to the container.
|
* @param rule The split rule to be applied to the container.
|
||||||
*/
|
*/
|
||||||
void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
|
void startActivityToSide(@NonNull Activity launchingActivity, @NonNull Intent activityIntent,
|
||||||
@Nullable Bundle activityOptions, @NonNull ExtensionSplitPairRule rule) {
|
@Nullable Bundle activityOptions, @NonNull SplitRule rule) {
|
||||||
final Rect parentBounds = getParentContainerBounds(launchingActivity);
|
final Rect parentBounds = getParentContainerBounds(launchingActivity);
|
||||||
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
|
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
|
||||||
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
|
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
|
||||||
@@ -227,7 +230,7 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
@NonNull WindowContainerTransaction wct) {
|
@NonNull WindowContainerTransaction wct) {
|
||||||
// Getting the parent bounds using the updated container - it will have the recent value.
|
// Getting the parent bounds using the updated container - it will have the recent value.
|
||||||
final Rect parentBounds = getParentContainerBounds(updatedContainer);
|
final Rect parentBounds = getParentContainerBounds(updatedContainer);
|
||||||
final ExtensionSplitPairRule rule = splitContainer.getSplitPairRule();
|
final SplitRule rule = splitContainer.getSplitRule();
|
||||||
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
|
final Rect primaryRectBounds = getBoundsForPosition(POSITION_LEFT, parentBounds, rule);
|
||||||
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
|
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_RIGHT, parentBounds, rule);
|
||||||
|
|
||||||
@@ -273,24 +276,24 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer {
|
|||||||
|
|
||||||
boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
|
boolean shouldShowSideBySide(@NonNull SplitContainer splitContainer) {
|
||||||
final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
|
final Rect parentBounds = getParentContainerBounds(splitContainer.getPrimaryContainer());
|
||||||
return shouldShowSideBySide(parentBounds, splitContainer.getSplitPairRule());
|
return shouldShowSideBySide(parentBounds, splitContainer.getSplitRule());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean shouldShowSideBySide(@Nullable Rect parentBounds,
|
boolean shouldShowSideBySide(@Nullable Rect parentBounds, @NonNull SplitRule rule) {
|
||||||
@NonNull ExtensionSplitPairRule rule) {
|
// TODO(b/190433398): Supply correct insets.
|
||||||
return parentBounds != null && parentBounds.width() >= rule.minWidth
|
final WindowMetrics parentMetrics = new WindowMetrics(parentBounds,
|
||||||
// TODO(b/190433398): Consider proper smallest width computation.
|
new WindowInsets(new Rect()));
|
||||||
&& Math.min(parentBounds.width(), parentBounds.height()) >= rule.minSmallestWidth;
|
return rule.getParentWindowMetricsPredicate().test(parentMetrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
|
private Rect getBoundsForPosition(@Position int position, @NonNull Rect parentBounds,
|
||||||
@NonNull ExtensionSplitPairRule rule) {
|
@NonNull SplitRule rule) {
|
||||||
if (!shouldShowSideBySide(parentBounds, rule)) {
|
if (!shouldShowSideBySide(parentBounds, rule)) {
|
||||||
return new Rect();
|
return new Rect();
|
||||||
}
|
}
|
||||||
|
|
||||||
float splitRatio = rule.splitRatio;
|
float splitRatio = rule.getSplitRatio();
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case POSITION_LEFT:
|
case POSITION_LEFT:
|
||||||
return new Rect(
|
return new Rect(
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user