blob: 5feb93c4ac054e5490ebacbc8bd6dddb26f4b305 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wm;
import static com.android.server.wm.ActivityStarter.Request;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.Looper;
import android.util.Pair;
import android.view.Display;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import java.util.ArrayList;
import java.util.List;
/**
* Class to control the assignment of a display for Car while launching a Activity.
*
* <p>This one controls which displays users are allowed to launch.
* The policy should be passed from car service through
* {@link com.android.internal.car.ICarServiceHelper} binder interfaces. If no policy is set,
* this module will not change anything for launch process.</p>
*
* <p> The policy can only affect which display passenger users can use. Current user, assumed
* to be a driver user, is allowed to launch any display always.</p>
*
* @hide
*/
public final class CarLaunchParamsModifier implements LaunchParamsController.LaunchParamsModifier {
private final Context mContext;
private DisplayManager mDisplayManager; // set only from init()
private ActivityTaskManagerService mAtm; // set only from init()
private CarLaunchParamsModifierUpdatable mUpdatable;
// getFallbackDisplayAreasForActivity() can return the most 3 {@link TaskDisplayAreaWrapper}.
private final ArrayList<TaskDisplayAreaWrapper> mFallBackDisplayAreaList = new ArrayList<>(3);
/** Constructor. Can be constructed any time. */
public CarLaunchParamsModifier(Context context) {
// This can be very early stage. So postpone interaction with other system until init.
mContext = context;
}
public void setUpdatable(CarLaunchParamsModifierUpdatable updatable) {
mUpdatable = updatable;
}
public CarLaunchParamsModifierInterface getBuiltinInterface() {
return mBuiltinInterface;
}
/**
* Initializes all internal stuffs. This should be called only after ATMS, DisplayManagerService
* are ready.
*/
public void init() {
mAtm = (ActivityTaskManagerService) ActivityTaskManager.getService();
LaunchParamsController controller = mAtm.mTaskSupervisor.getLaunchParamsController();
controller.registerModifier(this);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
mDisplayManager.registerDisplayListener(mUpdatable.getDisplayListener(),
new Handler(Looper.getMainLooper()));
}
/** Notifies user visibility changed. */
public void handleUserVisibilityChanged(int userId, boolean visible) {
mUpdatable.handleUserVisibilityChanged(userId, visible);
}
/** Notifies user switching. */
public void handleUserStarting(@UserIdInt int startingUserId) {
mUpdatable.handleUserStarting(startingUserId);
}
/** Notifies user switching. */
public void handleCurrentUserSwitching(@UserIdInt int newUserId) {
mUpdatable.handleCurrentUserSwitching(newUserId);
}
/** Notifies user stopped. */
public void handleUserStopped(@UserIdInt int stoppedUser) {
mUpdatable.handleUserStopped(stoppedUser);
}
/**
* Decides display to assign while an Activity is launched.
*
* <p>For current user (=driver), launching to any display is allowed as long as system
* allows it.</p>
*
* <p>For private display, do not change anything as private display has its own logic.</p>
*
* <p>For passenger displays, only run in allowed displays. If requested display is not
* allowed, change to the 1st allowed display.</p>
*/
@Override
@Result
public int onCalculate(@Nullable Task task, @Nullable ActivityInfo.WindowLayout layout,
@Nullable ActivityRecord activity, @Nullable ActivityRecord source,
ActivityOptions options, @Nullable Request request, int phase,
LaunchParamsController.LaunchParams currentParams,
LaunchParamsController.LaunchParams outParams) {
CalculateParams params = CalculateParams.create(task, layout, activity, source,
options, request, phase, currentParams, outParams, mAtm.mSupportsMultiDisplay);
return mUpdatable.calculate(params);
}
@Nullable
private TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int displayId) {
if (displayId == Display.INVALID_DISPLAY) {
return null;
}
DisplayContent dc = mAtm.mRootWindowContainer.getDisplayContentOrCreate(displayId);
if (dc == null) {
return null;
}
return TaskDisplayAreaWrapper.create(dc.getDefaultTaskDisplayArea());
}
/**
* Calculates the default {@link TaskDisplayAreaWrapper} for a task. We attempt to put
* the activity within the same display area if possible. The strategy is to find the display
* in the following order:
*
* <ol>
* <li>The display area of the top activity from the launching process will be used</li>
* <li>The display area of the top activity from the real launching process will be used
* </li>
* <li>Default display area from the associated root window container.</li>
* </ol>
* @param activityRecordWrapper the activity being started
* @param requestWrapper optional {@link RequestWrapper} made to start the activity record
* @return the list of {@link TaskDisplayAreaWrapper} to house the task
*/
private List<TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(
@NonNull ActivityRecordWrapper activityRecordWrapper,
@Nullable RequestWrapper requestWrapper) {
ActivityRecord activityRecord = activityRecordWrapper.getActivityRecord();
Request request = requestWrapper != null ? requestWrapper.getRequest() : null;
mFallBackDisplayAreaList.clear();
WindowProcessController controllerFromLaunchingRecord = mAtm.getProcessController(
activityRecord.getLaunchedFromPid(), activityRecord.getLaunchedFromUid());
TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null
? null : controllerFromLaunchingRecord.getTopActivityDisplayArea();
if (displayAreaForLaunchingRecord != null) {
mFallBackDisplayAreaList.add(
TaskDisplayAreaWrapper.create(displayAreaForLaunchingRecord));
}
WindowProcessController controllerFromProcess = mAtm.getProcessController(
activityRecord.getProcessName(), activityRecord.getUid());
TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null
: controllerFromProcess.getTopActivityDisplayArea();
if (displayAreaForRecord != null) {
mFallBackDisplayAreaList.add(TaskDisplayAreaWrapper.create(displayAreaForRecord));
}
WindowProcessController controllerFromRequest =
request == null ? null : mAtm.getProcessController(request.realCallingPid,
request.realCallingUid);
TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null
: controllerFromRequest.getTopActivityDisplayArea();
if (displayAreaFromSourceProcess != null) {
mFallBackDisplayAreaList.add(
TaskDisplayAreaWrapper.create(displayAreaFromSourceProcess));
}
return mFallBackDisplayAreaList;
}
@Nullable
private TaskDisplayAreaWrapper findTaskDisplayArea(int displayId, int featureId) {
DisplayContent display = mAtm.mRootWindowContainer.getDisplayContent(displayId);
if (display == null) {
return null;
}
TaskDisplayArea tda = display.getItemFromTaskDisplayAreas(
displayArea -> displayArea.mFeatureId == featureId ? displayArea : null);
return TaskDisplayAreaWrapper.create(tda);
}
private final CarLaunchParamsModifierInterface mBuiltinInterface =
new CarLaunchParamsModifierInterface() {
@Nullable
@Override
public TaskDisplayAreaWrapper findTaskDisplayArea(int displayId, int featureId) {
return CarLaunchParamsModifier.this.findTaskDisplayArea(displayId, featureId);
}
@Nullable
@Override
public TaskDisplayAreaWrapper getDefaultTaskDisplayAreaOnDisplay(int displayId) {
return CarLaunchParamsModifier.this.getDefaultTaskDisplayAreaOnDisplay(displayId);
}
@NonNull
@Override
public List<TaskDisplayAreaWrapper> getFallbackDisplayAreasForActivity(
@NonNull ActivityRecordWrapper activityRecord, @Nullable RequestWrapper request) {
return CarLaunchParamsModifier.this.getFallbackDisplayAreasForActivity(
activityRecord, request);
}
@NonNull
@Override
public Pair<Integer, Integer> getCurrentAndTargetUserIds() {
return mAtm.mAmInternal.getCurrentAndTargetUserIds();
}
@Override
public int getUserAssignedToDisplay(int displayId) {
UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
int userId = umi.getUserAssignedToDisplay(displayId);
return userId;
}
@Override
public int getMainDisplayAssignedToUser(int userId) {
UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
int displayId = umi.getMainDisplayAssignedToUser(userId);
return displayId;
}
};
}