blob: 5aa7f58f0968e28da42ce63f5cee107ff0f02685 [file] [log] [blame]
/*
* Copyright (C) 2017 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.am;
import android.annotation.IntDef;
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo.WindowLayout;
import android.graphics.Rect;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_CONTINUE;
import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_DONE;
import static com.android.server.am.LaunchingBoundsController.LaunchingBoundsPositioner.RESULT_SKIP;
/**
* {@link LaunchingBoundsController} calculates the launch bounds by coordinating between registered
* {@link LaunchingBoundsPositioner}.
*/
class LaunchingBoundsController {
private final List<LaunchingBoundsPositioner> mPositioners = new ArrayList<>();
// Temporary {@link Rect} for calculations. This is kept separate from {@code mTmpCurrent} and
// {@code mTmpResult} to prevent clobbering values.
private final Rect mTmpRect = new Rect();
private final Rect mTmpCurrent = new Rect();
private final Rect mTmpResult = new Rect();
/**
* Creates a {@link LaunchingBoundsController} with default registered
* {@link LaunchingBoundsPositioner}s.
*/
void registerDefaultPositioners(ActivityStackSupervisor supervisor) {
// {@link LaunchingTaskPositioner} handles window layout preferences.
registerPositioner(new LaunchingTaskPositioner());
// {@link LaunchingActivityPositioner} is the most specific positioner and thus should be
// registered last (applied first) out of the defaults.
registerPositioner(new LaunchingActivityPositioner(supervisor));
}
/**
* Returns the position calculated by the registered positioners
* @param task The {@link TaskRecord} currently being positioned.
* @param layout The specified {@link WindowLayout}.
* @param activity The {@link ActivityRecord} currently being positioned.
* @param source The {@link ActivityRecord} from which activity was started from.
* @param options The {@link ActivityOptions} specified for the activity.
* @param result The resulting bounds. If no bounds are set, {@link Rect#isEmpty()} will be
* {@code true}.
*/
void calculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options, Rect result) {
result.setEmpty();
// We start at the last registered {@link LaunchingBoundsPositioner} as this represents
// The positioner closest to the product level. Moving back through the list moves closer to
// the platform logic.
for (int i = mPositioners.size() - 1; i >= 0; --i) {
mTmpResult.setEmpty();
mTmpCurrent.set(result);
final LaunchingBoundsPositioner positioner = mPositioners.get(i);
switch(positioner.onCalculateBounds(task, layout, activity, source, options,
mTmpCurrent, mTmpResult)) {
case RESULT_SKIP:
// Do not apply any results when we are told to skip
continue;
case RESULT_DONE:
// Set result and return immediately.
result.set(mTmpResult);
return;
case RESULT_CONTINUE:
// Set result and continue
result.set(mTmpResult);
break;
}
}
}
/**
* A convenience method for laying out a task.
* @return {@code true} if bounds were set on the task. {@code false} otherwise.
*/
boolean layoutTask(TaskRecord task, WindowLayout layout) {
return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
}
boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options) {
calculateBounds(task, layout, activity, source, options, mTmpRect);
if (mTmpRect.isEmpty()) {
return false;
}
task.updateOverrideConfiguration(mTmpRect);
return true;
}
/**
* Adds a positioner to participate in future bounds calculation. Note that the last registered
* {@link LaunchingBoundsPositioner} will be the first to calculate the bounds.
*/
void registerPositioner(LaunchingBoundsPositioner positioner) {
if (mPositioners.contains(positioner)) {
return;
}
mPositioners.add(positioner);
}
/**
* An interface implemented by those wanting to participate in bounds calculation.
*/
interface LaunchingBoundsPositioner {
@Retention(RetentionPolicy.SOURCE)
@IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
@interface Result {}
// Returned when the positioner does not want to influence the bounds calculation
int RESULT_SKIP = 0;
// Returned when the positioner has changed the bounds and would like its results to be the
// final bounds applied.
int RESULT_DONE = 1;
// Returned when the positioner has changed the bounds but is okay with other positioners
// influencing the bounds.
int RESULT_CONTINUE = 2;
/**
* Called when asked to calculate bounds.
* @param task The {@link TaskRecord} currently being positioned.
* @param layout The specified {@link WindowLayout}.
* @param activity The {@link ActivityRecord} currently being positioned.
* @param source The {@link ActivityRecord} activity was started from.
* @param options The {@link ActivityOptions} specified for the activity.
* @param current The current bounds. This can differ from the initial bounds as it
* represents the modified bounds up to this point.
* @param result The {@link Rect} which the positioner should return its modified bounds.
* Any merging of the current bounds should be already applied to this
* value as well before returning.
* @return A {@link Result} representing the result of the bounds calculation.
*/
@Result
int onCalculateBounds(TaskRecord task, WindowLayout layout, ActivityRecord activity,
ActivityRecord source, ActivityOptions options, Rect current, Rect result);
}
}