diff options
19 files changed, 444 insertions, 134 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index fcab4005652a..9bff793ea0e6 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -11807,7 +11807,7 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult setIccLockEnabled(boolean, @NonNull String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabledStatus(int, boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMobileDataPolicyEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean); method public int setNrDualConnectivityState(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean); diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 790773fd83c5..b22921233f05 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -65,7 +65,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true"); DEFAULT_FLAGS.put("settings_tether_all_in_one", "false"); - DEFAULT_FLAGS.put("settings_silky_home", "true"); + DEFAULT_FLAGS.put("settings_silky_home", "false"); DEFAULT_FLAGS.put("settings_contextual_home", "false"); DEFAULT_FLAGS.put(SETTINGS_PROVIDER_MODEL, "false"); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java index 52648d915f2c..fe97e24fac41 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java @@ -16,7 +16,7 @@ package com.android.wm.shell; -import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT; import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.common.ShellExecutor; @@ -155,7 +155,7 @@ public final class ShellCommandHandlerImpl { } final int taskId = new Integer(args[2]); final int sideStagePosition = args.length > 3 - ? new Integer(args[3]) : SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; + ? new Integer(args[3]) : STAGE_POSITION_BOTTOM_OR_RIGHT; mSplitScreenOptional.ifPresent(split -> split.moveToSideStage(taskId, sideStagePosition)); return true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index 800150c0a93c..35dcdd5923a8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -34,8 +34,11 @@ import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPL import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP; -import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; -import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_TOP_OR_LEFT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import android.app.ActivityManager; import android.app.ActivityTaskManager; @@ -84,8 +87,7 @@ public class DragAndDropPolicy { private DragSession mSession; public DragAndDropPolicy(Context context, SplitScreen splitScreen) { - this(context, ActivityTaskManager.getInstance(), splitScreen, - new DefaultStarter(context, splitScreen)); + this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context)); } @VisibleForTesting @@ -94,7 +96,7 @@ public class DragAndDropPolicy { mContext = context; mActivityTaskManager = activityTaskManager; mSplitScreen = splitScreen; - mStarter = starter; + mStarter = mSplitScreen != null ? mSplitScreen : starter; } /** @@ -195,39 +197,23 @@ public class DragAndDropPolicy { return; } - final ClipDescription description = data.getDescription(); - final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); - final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); - final Intent dragData = mSession.dragData; final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible(); final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT; - final Bundle opts = dragData.hasExtra(EXTRA_ACTIVITY_OPTIONS) - ? dragData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) - : new Bundle(); - - if (target.type == TYPE_FULLSCREEN) { - // Exit split stages if needed - mStarter.exitSplitScreen(); - } else if (mSplitScreen != null) { + + @SplitScreen.StageType int stage = STAGE_TYPE_UNDEFINED; + @SplitScreen.StagePosition int position = STAGE_POSITION_UNDEFINED; + if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) { // Update launch options for the split side we are targeting. - final int position = leftOrTop - ? SIDE_STAGE_POSITION_TOP_OR_LEFT : SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; + position = leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT; if (!inSplitScreen) { - // Update the side stage position to match where we want to launch. - mSplitScreen.setSideStagePosition(position); + // Launch in the side stage if we are not in split-screen already. + stage = STAGE_TYPE_SIDE; } - mSplitScreen.updateActivityOptions(opts, position); } - if (isTask) { - mStarter.startTask(dragData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID), opts); - } else if (isShortcut) { - mStarter.startShortcut(dragData.getStringExtra(EXTRA_PACKAGE_NAME), - dragData.getStringExtra(EXTRA_SHORTCUT_ID), - opts, dragData.getParcelableExtra(EXTRA_USER)); - } else { - mStarter.startIntent(dragData.getParcelableExtra(EXTRA_PENDING_INTENT), opts); - } + final ClipDescription description = data.getDescription(); + final Intent dragData = mSession.dragData; + mStarter.startClipDescription(description, dragData, stage, position); } /** @@ -247,7 +233,6 @@ public class DragAndDropPolicy { int runningTaskActType = ACTIVITY_TYPE_STANDARD; boolean runningTaskIsResizeable; boolean dragItemSupportsSplitscreen; - boolean isPhone; DragSession(Context context, ActivityTaskManager activityTaskManager, DisplayLayout dispLayout, ClipData data) { @@ -275,7 +260,6 @@ public class DragAndDropPolicy { final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo(); dragItemSupportsSplitscreen = info == null || ActivityInfo.isResizeableMode(info.resizeMode); - isPhone = mContext.getResources().getConfiguration().smallestScreenWidthDp < 600; dragData = mInitialDragData.getItemAt(0).getIntent(); } } @@ -284,11 +268,33 @@ public class DragAndDropPolicy { * Interface for actually committing the task launches. */ @VisibleForTesting - interface Starter { - void startTask(int taskId, Bundle activityOptions); - void startShortcut(String packageName, String shortcutId, Bundle activityOptions, - UserHandle user); - void startIntent(PendingIntent intent, Bundle activityOptions); + public interface Starter { + default void startClipDescription(ClipDescription description, Intent intent, + @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position) { + final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); + final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); + final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS) + ? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle(); + + if (isTask) { + final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); + startTask(taskId, stage, position, opts); + } else if (isShortcut) { + final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); + final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID); + final UserHandle user = intent.getParcelableExtra(EXTRA_USER); + startShortcut(packageName, id, stage, position, opts, user); + } else { + startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position, opts); + } + } + void startTask(int taskId, @SplitScreen.StageType int stage, + @SplitScreen.StagePosition int position, @Nullable Bundle options); + void startShortcut(String packageName, String shortcutId, + @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position, + @Nullable Bundle options, UserHandle user); + void startIntent(PendingIntent intent, @SplitScreen.StageType int stage, + @SplitScreen.StagePosition int position, @Nullable Bundle options); void enterSplitScreen(int taskId, boolean leftOrTop); void exitSplitScreen(); } @@ -299,39 +305,39 @@ public class DragAndDropPolicy { */ private static class DefaultStarter implements Starter { private final Context mContext; - private final SplitScreen mSplitScreen; - public DefaultStarter(Context context, SplitScreen splitScreen) { + public DefaultStarter(Context context) { mContext = context; - mSplitScreen = splitScreen; } @Override - public void startTask(int taskId, Bundle activityOptions) { + public void startTask(int taskId, int stage, int position, + @Nullable Bundle options) { try { - ActivityTaskManager.getService().startActivityFromRecents(taskId, activityOptions); + ActivityTaskManager.getService().startActivityFromRecents(taskId, options); } catch (RemoteException e) { Slog.e(TAG, "Failed to launch task", e); } } @Override - public void startShortcut(String packageName, String shortcutId, Bundle activityOptions, - UserHandle user) { + public void startShortcut(String packageName, String shortcutId, int stage, int position, + @Nullable Bundle options, UserHandle user) { try { LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class); launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */, - activityOptions, user); + options, user); } catch (ActivityNotFoundException e) { Slog.e(TAG, "Failed to launch shortcut", e); } } @Override - public void startIntent(PendingIntent intent, Bundle activityOptions) { + public void startIntent(PendingIntent intent, int stage, int position, + @Nullable Bundle options) { try { - intent.send(null, 0, null, null, null, null, activityOptions); + intent.send(null, 0, null, null, null, null, options); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "Failed to launch activity", e); } @@ -339,14 +345,12 @@ public class DragAndDropPolicy { @Override public void enterSplitScreen(int taskId, boolean leftOrTop) { - mSplitScreen.moveToSideStage(taskId, - leftOrTop ? SIDE_STAGE_POSITION_TOP_OR_LEFT - : SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT); + throw new UnsupportedOperationException("enterSplitScreen not implemented by starter"); } @Override public void exitSplitScreen() { - mSplitScreen.exitSplitScreen(); + throw new UnsupportedOperationException("exitSplitScreen not implemented by starter"); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java index 7c1b9d813851..2c6809259459 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java @@ -18,12 +18,16 @@ package com.android.wm.shell.splitscreen; import android.annotation.IntDef; import android.app.ActivityManager; +import android.app.PendingIntent; import android.graphics.Rect; import android.os.Bundle; +import android.os.UserHandle; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.wm.shell.common.annotations.ExternalThread; +import com.android.wm.shell.draganddrop.DragAndDropPolicy; import java.io.PrintWriter; @@ -31,46 +35,93 @@ import java.io.PrintWriter; * Interface to engage split-screen feature. */ @ExternalThread -public interface SplitScreen { +public interface SplitScreen extends DragAndDropPolicy.Starter { /** - * Specifies that the side-stage is positioned at the top half of the screen if + * Stage position isn't specified normally meaning to use what ever it is currently set to. + */ + int STAGE_POSITION_UNDEFINED = -1; + /** + * Specifies that a stage is positioned at the top half of the screen if * in portrait mode or at the left half of the screen if in landscape mode. */ - int SIDE_STAGE_POSITION_TOP_OR_LEFT = 0; + int STAGE_POSITION_TOP_OR_LEFT = 0; /** - * Specifies that the side-stage is positioned at the bottom half of the screen if + * Specifies that a stage is positioned at the bottom half of the screen if * in portrait mode or at the right half of the screen if in landscape mode. */ - int SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT = 1; + int STAGE_POSITION_BOTTOM_OR_RIGHT = 1; - @IntDef(prefix = { "SIDE_STAGE_POSITION_" }, value = { - SIDE_STAGE_POSITION_TOP_OR_LEFT, - SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT + @IntDef(prefix = { "STAGE_POSITION_" }, value = { + STAGE_POSITION_UNDEFINED, + STAGE_POSITION_TOP_OR_LEFT, + STAGE_POSITION_BOTTOM_OR_RIGHT }) - @interface SideStagePosition {} + @interface StagePosition {} + + /** + * Stage type isn't specified normally meaning to use what ever the default is. + * E.g. exit split-screen and launch the app in fullscreen. + */ + int STAGE_TYPE_UNDEFINED = -1; + /** + * The main stage type. + * @see MainStage + */ + int STAGE_TYPE_MAIN = 0; + + /** + * The side stage type. + * @see SideStage + */ + int STAGE_TYPE_SIDE = 1; + + @IntDef(prefix = { "STAGE_TYPE_" }, value = { + STAGE_TYPE_UNDEFINED, + STAGE_TYPE_MAIN, + STAGE_TYPE_SIDE + }) + @interface StageType {} + + /** Callback interface for listening to changes in a split-screen stage. */ + interface SplitScreenListener { + void onStagePositionChanged(@StageType int stage, @StagePosition int position); + void onTaskStageChanged(int taskId, @StageType int stage); + } /** @return {@code true} if split-screen is currently visible. */ boolean isSplitScreenVisible(); /** Moves a task in the side-stage of split-screen. */ - boolean moveToSideStage(int taskId, @SideStagePosition int sideStagePosition); + boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition); /** Moves a task in the side-stage of split-screen. */ boolean moveToSideStage(ActivityManager.RunningTaskInfo task, - @SideStagePosition int sideStagePosition); + @StagePosition int sideStagePosition); /** Removes a task from the side-stage of split-screen. */ boolean removeFromSideStage(int taskId); /** Sets the position of the side-stage. */ - void setSideStagePosition(@SideStagePosition int sideStagePosition); + void setSideStagePosition(@StagePosition int sideStagePosition); /** Hides the side-stage if it is currently visible. */ void setSideStageVisibility(boolean visible); + default void enterSplitScreen(int taskId, boolean leftOrTop) { + moveToSideStage(taskId, + leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT); + } /** Removes the split-screen stages. */ void exitSplitScreen(); /** Gets the stage bounds. */ void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds); - /** Updates the launch activity options for the split position we want to launch it in. */ - void updateActivityOptions(Bundle opts, @SideStagePosition int position); /** Dumps current status of split-screen. */ void dump(@NonNull PrintWriter pw, String prefix); /** Called when the shell organizer has been registered. */ void onOrganizerRegistered(); + + void registerSplitScreenListener(SplitScreenListener listener); + void unregisterSplitScreenListener(SplitScreenListener listener); + + void startTask(int taskId, + @StageType int stage, @StagePosition int position, @Nullable Bundle options); + void startShortcut(String packageName, String shortcutId, @StageType int stage, + @StagePosition int position, @Nullable Bundle options, UserHandle user); + void startIntent(PendingIntent intent, + @StageType int stage, @StagePosition int position, @Nullable Bundle options); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 27d3b81d41b5..18dd53b90ff4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -19,11 +19,19 @@ package com.android.wm.shell.splitscreen; import static android.view.Display.DEFAULT_DISPLAY; import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.app.PendingIntent; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.pm.LauncherApps; import android.graphics.Rect; import android.os.Bundle; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -69,7 +77,7 @@ public class SplitScreenController implements SplitScreen { } @Override - public boolean moveToSideStage(int taskId, @SideStagePosition int sideStagePosition) { + public boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition) { final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId); if (task == null) { throw new IllegalArgumentException("Unknown taskId" + taskId); @@ -79,7 +87,7 @@ public class SplitScreenController implements SplitScreen { @Override public boolean moveToSideStage(ActivityManager.RunningTaskInfo task, - @SideStagePosition int sideStagePosition) { + @StagePosition int sideStagePosition) { return mStageCoordinator.moveToSideStage(task, sideStagePosition); } @@ -89,7 +97,7 @@ public class SplitScreenController implements SplitScreen { } @Override - public void setSideStagePosition(@SideStagePosition int sideStagePosition) { + public void setSideStagePosition(@StagePosition int sideStagePosition) { mStageCoordinator.setSideStagePosition(sideStagePosition); } @@ -109,8 +117,103 @@ public class SplitScreenController implements SplitScreen { } @Override - public void updateActivityOptions(Bundle opts, @SideStagePosition int position) { - mStageCoordinator.updateActivityOptions(opts, position); + public void registerSplitScreenListener(SplitScreenListener listener) { + mStageCoordinator.registerSplitScreenListener(listener); + } + + @Override + public void unregisterSplitScreenListener(SplitScreenListener listener) { + mStageCoordinator.unregisterSplitScreenListener(listener); + } + + @Override + public void startTask(int taskId, + @StageType int stage, @StagePosition int position, @Nullable Bundle options) { + options = resolveStartStage(stage, position, options); + + try { + ActivityTaskManager.getService().startActivityFromRecents(taskId, options); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to launch task", e); + } + } + + @Override + public void startShortcut(String packageName, String shortcutId, @StageType int stage, + @StagePosition int position, @Nullable Bundle options, UserHandle user) { + options = resolveStartStage(stage, position, options); + + try { + LauncherApps launcherApps = + mContext.getSystemService(LauncherApps.class); + launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */, + options, user); + } catch (ActivityNotFoundException e) { + Slog.e(TAG, "Failed to launch shortcut", e); + } + } + + @Override + public void startIntent(PendingIntent intent, + @StageType int stage, @StagePosition int position, @Nullable Bundle options) { + options = resolveStartStage(stage, position, options); + + try { + intent.send(null, 0, null, null, null, null, options); + } catch (PendingIntent.CanceledException e) { + Slog.e(TAG, "Failed to launch activity", e); + } + } + + private Bundle resolveStartStage(@StageType int stage, @StagePosition int position, + @Nullable Bundle options) { + switch (stage) { + case STAGE_TYPE_UNDEFINED: { + // Use the stage of the specified position is valid. + if (position != STAGE_POSITION_UNDEFINED) { + if (position == mStageCoordinator.getSideStagePosition()) { + options = resolveStartStage(STAGE_TYPE_SIDE, position, options); + } else { + options = resolveStartStage(STAGE_TYPE_MAIN, position, options); + } + } else { + // Exit split-screen and launch fullscreen since stage wasn't specified. + mStageCoordinator.exitSplitScreen(); + } + break; + } + case STAGE_TYPE_SIDE: { + if (position != STAGE_POSITION_UNDEFINED) { + mStageCoordinator.setSideStagePosition(position); + } else { + position = mStageCoordinator.getSideStagePosition(); + } + if (options == null) { + options = new Bundle(); + } + mStageCoordinator.updateActivityOptions(options, position); + break; + } + case STAGE_TYPE_MAIN: { + if (position != STAGE_POSITION_UNDEFINED) { + // Set the side stage opposite of what we want to the main stage. + final int sideStagePosition = position == STAGE_POSITION_TOP_OR_LEFT + ? STAGE_POSITION_BOTTOM_OR_RIGHT : STAGE_POSITION_TOP_OR_LEFT; + mStageCoordinator.setSideStagePosition(sideStagePosition); + } else { + position = mStageCoordinator.getMainStagePosition(); + } + if (options == null) { + options = new Bundle(); + } + mStageCoordinator.updateActivityOptions(options, position); + break; + } + default: + throw new IllegalArgumentException("Unknown stage=" + stage); + } + + return options; } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index d571e7514542..176852b148fa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -17,12 +17,14 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityOptions.KEY_LAUNCH_ROOT_TASK_TOKEN; -import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; -import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; -import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_TOP_OR_LEFT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import android.app.ActivityManager; import android.content.Context; @@ -41,6 +43,8 @@ import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.split.SplitLayout; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; /** * Coordinates the staging (visibility, sizing, ...) of the split-screen {@link MainStage} and @@ -64,8 +68,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, private final StageListenerImpl mMainStageListener = new StageListenerImpl(); private final SideStage mSideStage; private final StageListenerImpl mSideStageListener = new StageListenerImpl(); - private @SplitScreen.SideStagePosition int mSideStagePosition = - SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; + private @SplitScreen.StagePosition int mSideStagePosition = STAGE_POSITION_BOTTOM_OR_RIGHT; private final int mDisplayId; private SplitLayout mSplitLayout; @@ -75,6 +78,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, private final ShellTaskOrganizer mTaskOrganizer; private DisplayAreaInfo mDisplayAreaInfo; private final Context mContext; + private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>(); StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer) { @@ -107,7 +111,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } boolean moveToSideStage(ActivityManager.RunningTaskInfo task, - @SplitScreen.SideStagePosition int sideStagePosition) { + @SplitScreen.StagePosition int sideStagePosition) { final WindowContainerTransaction wct = new WindowContainerTransaction(); mSideStagePosition = sideStagePosition; mMainStage.activate(getMainStageBounds(), wct); @@ -130,7 +134,16 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, return result; } - void setSideStagePosition(@SplitScreen.SideStagePosition int sideStagePosition) { + @SplitScreen.StagePosition int getSideStagePosition() { + return mSideStagePosition; + } + + @SplitScreen.StagePosition int getMainStagePosition() { + return mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT + ? STAGE_POSITION_BOTTOM_OR_RIGHT : STAGE_POSITION_TOP_OR_LEFT; + } + + void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) { mSideStagePosition = sideStagePosition; if (mSideStageListener.mVisible) { onStageVisibilityChanged(mSideStageListener); @@ -163,7 +176,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, outBottomOrRightBounds.set(mSplitLayout.getBounds2()); } - void updateActivityOptions(Bundle opts, @SplitScreen.SideStagePosition int position) { + void updateActivityOptions(Bundle opts, @SplitScreen.StagePosition int position) { final StageTaskListener stage = position == mSideStagePosition ? mSideStage : mMainStage; opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token); @@ -176,6 +189,35 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } } + void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) { + if (mListeners.contains(listener)) return; + mListeners.add(listener); + listener.onStagePositionChanged(STAGE_TYPE_MAIN, getMainStagePosition()); + listener.onStagePositionChanged(STAGE_TYPE_SIDE, getSideStagePosition()); + mSideStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_SIDE); + mMainStage.onSplitScreenListenerRegistered(listener, STAGE_TYPE_MAIN); + } + + void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) { + mListeners.remove(listener); + } + + private void onStageChildTaskStatusChanged( + StageListenerImpl stageListener, int taskId, boolean present) { + + int stage; + if (present) { + stage = stageListener == mSideStageListener ? STAGE_TYPE_SIDE : STAGE_TYPE_MAIN; + } else { + // No longer on any stage + stage = STAGE_TYPE_UNDEFINED; + } + + for (int i = mListeners.size() - 1; i >= 0; --i) { + mListeners.get(i).onTaskStageChanged(taskId, stage); + } + } + private void onStageRootTaskAppeared(StageListenerImpl stageListener) { if (mMainStageListener.mHasRootTask && mSideStageListener.mHasRootTask) { final WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -299,7 +341,7 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, @Override public void onSnappedToDismiss(boolean bottomOrRight) { final boolean mainStageToTop = bottomOrRight - && mSideStagePosition == SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; + && mSideStagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT; exitSplitScreen(mainStageToTop ? mMainStage : mSideStage); } @@ -326,8 +368,8 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, @Override public void onDoubleTappedDivider() { - setSideStagePosition(mSideStagePosition == SIDE_STAGE_POSITION_TOP_OR_LEFT - ? SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT : SIDE_STAGE_POSITION_TOP_OR_LEFT); + setSideStagePosition(mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT + ? STAGE_POSITION_BOTTOM_OR_RIGHT : STAGE_POSITION_TOP_OR_LEFT); } @Override @@ -380,12 +422,12 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } private Rect getSideStageBounds() { - return mSideStagePosition == SIDE_STAGE_POSITION_TOP_OR_LEFT + return mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT ? mSplitLayout.getBounds1() : mSplitLayout.getBounds2(); } private Rect getMainStageBounds() { - return mSideStagePosition == SIDE_STAGE_POSITION_TOP_OR_LEFT + return mSideStagePosition == STAGE_POSITION_TOP_OR_LEFT ? mSplitLayout.getBounds2() : mSplitLayout.getBounds1(); } @@ -429,6 +471,11 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } @Override + public void onChildTaskStatusChanged(int taskId, boolean present) { + StageCoordinator.this.onStageChildTaskStatusChanged(this, taskId, present); + } + + @Override public void onRootTaskVanished() { reset(); StageCoordinator.this.onStageRootTaskVanished(this); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 1aa7552c01eb..653299326cd0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -58,6 +58,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { public interface StageListenerCallbacks { void onRootTaskAppeared(); void onStatusChanged(boolean visible, boolean hasChildren); + void onChildTaskStatusChanged(int taskId, boolean present); void onRootTaskVanished(); } private final StageListenerCallbacks mCallbacks; @@ -83,9 +84,11 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { mRootTaskInfo = taskInfo; mCallbacks.onRootTaskAppeared(); } else if (taskInfo.parentTaskId == mRootTaskInfo.taskId) { - mChildrenLeashes.put(taskInfo.taskId, leash); - mChildrenTaskInfo.put(taskInfo.taskId, taskInfo); + final int taskId = taskInfo.taskId; + mChildrenLeashes.put(taskId, leash); + mChildrenTaskInfo.put(taskId, taskInfo); updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */); + mCallbacks.onChildTaskStatusChanged(taskId, true /* present */); } else { throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo + "\n mRootTaskInfo: " + mRootTaskInfo); @@ -120,6 +123,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { mChildrenTaskInfo.remove(taskId); mChildrenLeashes.remove(taskId); sendStatusChanged(); + mCallbacks.onChildTaskStatusChanged(taskId, false /* present */); } else { throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo + "\n mRootTaskInfo: " + mRootTaskInfo); @@ -134,6 +138,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { wct.reorder(mRootTaskInfo.token, visible /* onTop */); } + void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener, + @SplitScreen.StageType int stage) { + for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { + listener.onTaskStageChanged(mChildrenTaskInfo.keyAt(i), stage); + } + } + private void updateChildTaskSurface(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, boolean firstAppeared) { final Point taskPositionInParent = taskInfo.positionInParent; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java index 79bdaf43f171..25721066b713 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java @@ -29,6 +29,10 @@ import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPL import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_LEFT; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT; import static com.android.wm.shell.draganddrop.DragAndDropPolicy.Target.TYPE_SPLIT_TOP; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; @@ -86,11 +90,9 @@ public class DragAndDropPolicyTest { @Mock private ActivityTaskManager mActivityTaskManager; + // Both the split-screen and start interface. @Mock - private SplitScreen mSplitScreen; - - @Mock - private DragAndDropPolicy.Starter mStarter; + private SplitScreen mSplitScreenStarter; private DisplayLayout mLandscapeDisplayLayout; private DisplayLayout mPortraitDisplayLayout; @@ -126,7 +128,7 @@ public class DragAndDropPolicyTest { mInsets = Insets.of(0, 0, 0, 0); mPolicy = new DragAndDropPolicy( - mContext, mActivityTaskManager, mSplitScreen, mStarter); + mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter); mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); setClipDataResizeable(mNonResizeableActivityClipData, false); @@ -191,7 +193,7 @@ public class DragAndDropPolicyTest { } private void setInSplitScreen(boolean inSplitscreen) { - doReturn(inSplitscreen).when(mSplitScreen).isSplitScreenVisible(); + doReturn(inSplitscreen).when(mSplitScreenStarter).isSplitScreenVisible(); } @Test @@ -202,7 +204,8 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mStarter).startIntent(any(), any()); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); } @Test @@ -213,12 +216,13 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mStarter).exitSplitScreen(); - verify(mStarter).startIntent(any(), any()); - reset(mStarter); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + reset(mSplitScreenStarter); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); - verify(mStarter).startIntent(any(), any()); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); } @Test @@ -229,12 +233,13 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mStarter).exitSplitScreen(); - verify(mStarter).startIntent(any(), any()); - reset(mStarter); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + reset(mSplitScreenStarter); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); - verify(mStarter).startIntent(any(), any()); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); } @Test @@ -245,7 +250,8 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mStarter).startIntent(any(), any()); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); } @Test @@ -256,7 +262,8 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mStarter).startIntent(any(), any()); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); } @Test @@ -268,12 +275,14 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mStarter).startIntent(any(), any()); - reset(mStarter); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + reset(mSplitScreenStarter); // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); - verify(mStarter).startIntent(any(), any()); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); } @Test @@ -285,12 +294,14 @@ public class DragAndDropPolicyTest { mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); - verify(mStarter).startIntent(any(), any()); - reset(mStarter); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); + reset(mSplitScreenStarter); // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); - verify(mStarter).startIntent(any(), any()); + verify(mSplitScreenStarter).startClipDescription(any(), any(), + eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java index 168e0df35fe1..d2d18129d071 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java @@ -19,7 +19,7 @@ package com.android.wm.shell.splitscreen; import static android.view.Display.DEFAULT_DISPLAY; import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; -import static com.android.wm.shell.splitscreen.SplitScreen.SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; +import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -71,7 +71,7 @@ public class StageCoordinatorTests extends ShellTestCase { public void testMoveToSideStage() { final ActivityManager.RunningTaskInfo task = new TestRunningTaskInfoBuilder().build(); - mStageCoordinator.moveToSideStage(task, SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT); + mStageCoordinator.moveToSideStage(task, STAGE_POSITION_BOTTOM_OR_RIGHT); verify(mMainStage).activate(any(Rect.class), any(WindowContainerTransaction.class)); verify(mSideStage).addTask(eq(task), any(Rect.class), diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 55630039683a..7556ace466f2 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1484,5 +1484,5 @@ <!-- Content description of the Ethernet connection when disconnected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_ethernet_disconnected">Ethernet disconnected.</string> <!-- Content description of the Ethernet connection when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> - <string name="accessibility_ethernet_connected">Ethernet connected.</string> + <string name="accessibility_ethernet_connected">Ethernet.</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 1b2ad4c8b5bb..191b85bd1f21 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -54,6 +54,9 @@ import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import com.android.systemui.statusbar.policy.WifiIcons; +import java.io.FileDescriptor; +import java.io.PrintWriter; + import javax.inject.Inject; /** Quick settings tile: Internet **/ @@ -65,7 +68,7 @@ public class InternetTile extends QSTileImpl<SignalState> { protected final NetworkController mController; private final DataUsageController mDataController; private final QSTile.SignalState mStateBeforeClick = newTileState(); - // The last updated tile state, 0: mobile, 1: wifi + // The last updated tile state, 0: mobile, 1: wifi, 2: ethernet. private int mLastTileState = -1; protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback(); @@ -140,6 +143,21 @@ public class InternetTile extends QSTileImpl<SignalState> { return string; } + private static final class EthernetCallbackInfo { + boolean mConnected; + int mEthernetSignalIconId; + String mEthernetContentDescription; + + @Override + public String toString() { + return new StringBuilder("EthernetCallbackInfo[") + .append("mConnected=").append(mConnected) + .append(",mEthernetSignalIconId=").append(mEthernetSignalIconId) + .append(",mEthernetContentDescription=").append(mEthernetContentDescription) + .append(']').toString(); + } + } + private static final class WifiCallbackInfo { boolean mAirplaneModeEnabled; boolean mEnabled; @@ -212,6 +230,8 @@ public class InternetTile extends QSTileImpl<SignalState> { protected final class InternetSignalCallback implements SignalCallback { final WifiCallbackInfo mWifiInfo = new WifiCallbackInfo(); final CellularCallbackInfo mCellularInfo = new CellularCallbackInfo(); + final EthernetCallbackInfo mEthernetInfo = new EthernetCallbackInfo(); + @Override public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon, @@ -230,14 +250,12 @@ public class InternetTile extends QSTileImpl<SignalState> { } // When airplane mode is enabled, we need to refresh the Internet Tile even if the WiFi // is not the default network. - if (qsIcon == null && !mWifiInfo.mAirplaneModeEnabled) { + if (qsIcon == null) { return; } - if (qsIcon != null) { - mWifiInfo.mConnected = qsIcon.visible; - mWifiInfo.mWifiSignalIconId = qsIcon.icon; - mWifiInfo.mWifiSignalContentDescription = qsIcon.contentDescription; - } + mWifiInfo.mConnected = qsIcon.visible; + mWifiInfo.mWifiSignalIconId = qsIcon.icon; + mWifiInfo.mWifiSignalContentDescription = qsIcon.contentDescription; mWifiInfo.mEnabled = enabled; mWifiInfo.mSsid = description; mWifiInfo.mActivityIn = activityIn; @@ -287,6 +305,20 @@ public class InternetTile extends QSTileImpl<SignalState> { } @Override + public void setEthernetIndicators(IconState icon) { + if (DEBUG) { + Log.d(TAG, "setEthernetIndicators: " + + "icon = " + (icon == null ? "" : icon.toString())); + } + mEthernetInfo.mConnected = icon.visible; + mEthernetInfo.mEthernetSignalIconId = icon.icon; + mEthernetInfo.mEthernetContentDescription = icon.contentDescription; + if (icon.visible) { + refreshState(mEthernetInfo); + } + } + + @Override public void setNoSims(boolean show, boolean simDetected) { if (DEBUG) { Log.d(TAG, "setNoSims: " @@ -299,7 +331,6 @@ public class InternetTile extends QSTileImpl<SignalState> { mCellularInfo.mMobileSignalIconId = 0; mCellularInfo.mQsTypeIcon = 0; } - refreshState(mCellularInfo); } @Override @@ -310,7 +341,9 @@ public class InternetTile extends QSTileImpl<SignalState> { } mCellularInfo.mAirplaneModeEnabled = icon.visible; mWifiInfo.mAirplaneModeEnabled = icon.visible; - refreshState(mCellularInfo); + if (!mSignalCallback.mEthernetInfo.mConnected) { + refreshState(mCellularInfo); + } } @Override @@ -330,6 +363,15 @@ public class InternetTile extends QSTileImpl<SignalState> { mWifiInfo.mNoNetworksAvailable = noNetworksAvailable; refreshState(mWifiInfo); } + + @Override + public String toString() { + return new StringBuilder("InternetSignalCallback[") + .append("mWifiInfo=").append(mWifiInfo) + .append(",mCellularInfo=").append(mCellularInfo) + .append(",mEthernetInfo=").append(mEthernetInfo) + .append(']').toString(); + } } @Override @@ -340,6 +382,9 @@ public class InternetTile extends QSTileImpl<SignalState> { } else if (arg instanceof WifiCallbackInfo) { mLastTileState = 1; handleUpdateWifiState(state, arg); + } else if (arg instanceof EthernetCallbackInfo) { + mLastTileState = 2; + handleUpdateEthernetState(state, arg); } else { // handleUpdateState will be triggered when user expands the QuickSetting panel with // arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo @@ -348,6 +393,8 @@ public class InternetTile extends QSTileImpl<SignalState> { handleUpdateCellularState(state, mSignalCallback.mCellularInfo); } else if (mLastTileState == 1) { handleUpdateWifiState(state, mSignalCallback.mWifiInfo); + } else if (mLastTileState == 2) { + handleUpdateEthernetState(state, mSignalCallback.mEthernetInfo); } } } @@ -440,7 +487,6 @@ public class InternetTile extends QSTileImpl<SignalState> { Log.d(TAG, "handleUpdateCellularState: " + "CellularCallbackInfo = " + cb.toString()); } final Resources r = mContext.getResources(); - // TODO(b/174753536): Use the new "Internet" string as state.label once available. state.label = r.getString(R.string.quick_settings_internet_label); state.state = Tile.STATE_ACTIVE; boolean mobileDataEnabled = mDataController.isMobileDataSupported() @@ -478,6 +524,18 @@ public class InternetTile extends QSTileImpl<SignalState> { } } + private void handleUpdateEthernetState(SignalState state, Object arg) { + EthernetCallbackInfo cb = (EthernetCallbackInfo) arg; + if (DEBUG) { + Log.d(TAG, "handleUpdateEthernetState: " + "EthernetCallbackInfo = " + cb.toString()); + } + final Resources r = mContext.getResources(); + state.label = r.getString(R.string.quick_settings_internet_label); + state.state = Tile.STATE_ACTIVE; + state.icon = ResourceIcon.get(cb.mEthernetSignalIconId); + state.secondaryLabel = cb.mEthernetContentDescription; + } + private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) { if (TextUtils.isEmpty(dataType)) { return Html.fromHtml((current == null ? "" : current.toString()), 0); @@ -519,4 +577,15 @@ public class InternetTile extends QSTileImpl<SignalState> { return d; } } + + /** + * Dumps the state of this tile along with its name. + */ + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println(this.getClass().getSimpleName() + ":"); + pw.print(" "); pw.println(getState().toString()); + pw.print(" "); pw.println("mLastTileState=" + mLastTileState); + pw.print(" "); pw.println("mSignalCallback=" + mSignalCallback.toString()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java index 2eff04eb66f6..80b75a740965 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java @@ -53,13 +53,21 @@ public class EthernetSignalController extends public void notifyListeners(SignalCallback callback) { boolean ethernetVisible = mCurrentState.connected; String contentDescription = getTextIfExists(getContentDescription()).toString(); - // TODO: wire up data transfer using WifiSignalPoller. callback.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(), contentDescription)); } @Override + public int getContentDescription() { + if (mCurrentState.connected) { + return getIcons().contentDesc[1]; + } else { + return getIcons().discContentDesc; + } + } + + @Override public State cleanState() { return new State(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index f9450ae4d524..e13e30b74c3c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -524,6 +524,10 @@ public class NetworkControllerImpl extends BroadcastReceiver return mWifiSignalController.isCarrierMergedWifi(subId); } + boolean isEthernetDefault() { + return mConnectedTransports.get(NetworkCapabilities.TRANSPORT_ETHERNET); + } + String getNonDefaultMobileDataNetworkName(int subId) { MobileSignalController controller = getControllerWithSubId(subId); return controller != null ? controller.getNonDefaultCarrierName() : ""; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 9669522675ac..b2120d47ab5d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -106,7 +106,8 @@ public class WifiSignalController extends IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription); if (mProviderModel) { IconState qsIcon = null; - if (mCurrentState.isDefault) { + if (mCurrentState.isDefault || (!mNetworkController.isRadioOn() + && !mNetworkController.isEthernetDefault())) { qsIcon = new IconState(mCurrentState.connected, mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected : getQsCurrentIconId(), contentDescription); diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 38ae51fc2c1b..83085ccb7d8c 100755 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -977,7 +977,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { AudioPortConfig sourceConfig = mAudioSource.activeConfig(); List<AudioPortConfig> sinkConfigs = new ArrayList<>(); AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch }; - boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated; + boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated || mAudioPatch == null; for (AudioDevicePort audioSink : mAudioSink) { AudioPortConfig sinkConfig = audioSink.activeConfig(); diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index 8507d8512a5c..706e3cb93a0f 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -344,6 +344,7 @@ public final class NetworkRegistrationInfo implements Parcelable { // TODO: Instead of doing this, we should create a formal way for cloning cell identity. // Cell identity is not an immutable object so we have to deep copy it. mCellIdentity = CellIdentity.CREATOR.createFromParcel(p); + p.recycle(); } if (nri.mVoiceSpecificInfo != null) { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index e4386e750d14..65b8de2b2216 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -14242,7 +14242,7 @@ public class TelephonyManager { * If this policy is enabled, data will be temporarily enabled on the non-default data SIM * during any voice calls. * - * This policy can be enabled and disabled via {@link #setMobileDataPolicyEnabledStatus}. + * This policy can be enabled and disabled via {@link #setMobileDataPolicyEnabled}. * @hide */ @SystemApi @@ -14256,7 +14256,7 @@ public class TelephonyManager { * will also return true for {@link ApnSetting#TYPE_MMS}. * When disabled, the MMS APN will be governed by the same rules as all other APNs. * - * This policy can be enabled and disabled via {@link #setMobileDataPolicyEnabledStatus}. + * This policy can be enabled and disabled via {@link #setMobileDataPolicyEnabled}. * @hide */ @SystemApi @@ -14284,11 +14284,11 @@ public class TelephonyManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - public void setMobileDataPolicyEnabledStatus(@MobileDataPolicy int policy, boolean enabled) { + public void setMobileDataPolicyEnabled(@MobileDataPolicy int policy, boolean enabled) { try { ITelephony service = getITelephony(); if (service != null) { - service.setMobileDataPolicyEnabledStatus(getSubId(), policy, enabled); + service.setMobileDataPolicyEnabled(getSubId(), policy, enabled); } } catch (RemoteException ex) { // This could happen if binder process crashes. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index d17415a7354a..0cd17da3c0c5 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2172,7 +2172,7 @@ interface ITelephony { */ String getMmsUAProfUrl(int subId); - void setMobileDataPolicyEnabledStatus(int subscriptionId, int policy, boolean enabled); + void setMobileDataPolicyEnabled(int subscriptionId, int policy, boolean enabled); boolean isMobileDataPolicyEnabled(int subscriptionId, int policy); |