Merge "Letterbox Reacheability Multiplier Persistence" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
a8117a579f
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package com.android.server.wm;
|
|
||||||
|
|
||||||
option java_package = "com.android.server.wm";
|
|
||||||
option java_outer_classname = "WindowManagerProtos";
|
|
||||||
|
|
||||||
message TaskSnapshotProto {
|
|
||||||
int32 orientation = 1;
|
|
||||||
int32 inset_left = 2;
|
|
||||||
int32 inset_top = 3;
|
|
||||||
int32 inset_right = 4;
|
|
||||||
int32 inset_bottom = 5;
|
|
||||||
bool is_real_snapshot = 6;
|
|
||||||
int32 windowing_mode = 7;
|
|
||||||
int32 system_ui_visibility = 8 [deprecated=true];
|
|
||||||
bool is_translucent = 9;
|
|
||||||
string top_activity_component = 10;
|
|
||||||
// deprecated because original width and height are stored now instead of the scale.
|
|
||||||
float legacy_scale = 11 [deprecated=true];
|
|
||||||
int64 id = 12;
|
|
||||||
int32 rotation = 13;
|
|
||||||
// The task width when the snapshot was taken
|
|
||||||
int32 task_width = 14;
|
|
||||||
// The task height when the snapshot was taken
|
|
||||||
int32 task_height = 15;
|
|
||||||
int32 appearance = 16;
|
|
||||||
int32 letterbox_inset_left = 17;
|
|
||||||
int32 letterbox_inset_top = 18;
|
|
||||||
int32 letterbox_inset_right = 19;
|
|
||||||
int32 letterbox_inset_bottom = 20;
|
|
||||||
}
|
|
||||||
71
proto/src/windowmanager.proto
Normal file
71
proto/src/windowmanager.proto
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package com.android.server.wm;
|
||||||
|
|
||||||
|
option java_package = "com.android.server.wm";
|
||||||
|
option java_outer_classname = "WindowManagerProtos";
|
||||||
|
|
||||||
|
message TaskSnapshotProto {
|
||||||
|
int32 orientation = 1;
|
||||||
|
int32 inset_left = 2;
|
||||||
|
int32 inset_top = 3;
|
||||||
|
int32 inset_right = 4;
|
||||||
|
int32 inset_bottom = 5;
|
||||||
|
bool is_real_snapshot = 6;
|
||||||
|
int32 windowing_mode = 7;
|
||||||
|
int32 system_ui_visibility = 8 [deprecated=true];
|
||||||
|
bool is_translucent = 9;
|
||||||
|
string top_activity_component = 10;
|
||||||
|
// deprecated because original width and height are stored now instead of the scale.
|
||||||
|
float legacy_scale = 11 [deprecated=true];
|
||||||
|
int64 id = 12;
|
||||||
|
int32 rotation = 13;
|
||||||
|
// The task width when the snapshot was taken
|
||||||
|
int32 task_width = 14;
|
||||||
|
// The task height when the snapshot was taken
|
||||||
|
int32 task_height = 15;
|
||||||
|
int32 appearance = 16;
|
||||||
|
int32 letterbox_inset_left = 17;
|
||||||
|
int32 letterbox_inset_top = 18;
|
||||||
|
int32 letterbox_inset_right = 19;
|
||||||
|
int32 letterbox_inset_bottom = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persistent letterboxing configurations
|
||||||
|
message LetterboxProto {
|
||||||
|
|
||||||
|
// Possible values for the letterbox horizontal reachability
|
||||||
|
enum LetterboxHorizontalReachability {
|
||||||
|
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT = 0;
|
||||||
|
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER = 1;
|
||||||
|
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possible values for the letterbox vertical reachability
|
||||||
|
enum LetterboxVerticalReachability {
|
||||||
|
LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP = 0;
|
||||||
|
LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER = 1;
|
||||||
|
LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represents the current horizontal position for the letterboxed activity
|
||||||
|
LetterboxHorizontalReachability letterbox_position_for_horizontal_reachability = 1;
|
||||||
|
// Represents the current vertical position for the letterboxed activity
|
||||||
|
LetterboxVerticalReachability letterbox_position_for_vertical_reachability = 2;
|
||||||
|
}
|
||||||
@@ -17,14 +17,17 @@
|
|||||||
package com.android.server.wm;
|
package com.android.server.wm;
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
|
||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/** Reads letterbox configs from resources and controls their overrides at runtime. */
|
/** Reads letterbox configs from resources and controls their overrides at runtime. */
|
||||||
final class LetterboxConfiguration {
|
final class LetterboxConfiguration {
|
||||||
@@ -156,34 +159,25 @@ final class LetterboxConfiguration {
|
|||||||
// portrait device orientation.
|
// portrait device orientation.
|
||||||
private boolean mIsVerticalReachabilityEnabled;
|
private boolean mIsVerticalReachabilityEnabled;
|
||||||
|
|
||||||
|
|
||||||
// Horizontal position of a center of the letterboxed app window which is global to prevent
|
|
||||||
// "jumps" when switching between letterboxed apps. It's updated to reposition the app window
|
|
||||||
// in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
|
|
||||||
// LetterboxUiController#getHorizontalPositionMultiplier which is called from
|
|
||||||
// ActivityRecord#updateResolvedBoundsPosition.
|
|
||||||
// TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
|
|
||||||
// Overview after changing position in another app.
|
|
||||||
@LetterboxHorizontalReachabilityPosition
|
|
||||||
private volatile int mLetterboxPositionForHorizontalReachability;
|
|
||||||
|
|
||||||
// Vertical position of a center of the letterboxed app window which is global to prevent
|
|
||||||
// "jumps" when switching between letterboxed apps. It's updated to reposition the app window
|
|
||||||
// in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
|
|
||||||
// LetterboxUiController#getVerticalPositionMultiplier which is called from
|
|
||||||
// ActivityRecord#updateResolvedBoundsPosition.
|
|
||||||
// TODO(b/199426138): Global reachability setting causes a jump when resuming an app from
|
|
||||||
// Overview after changing position in another app.
|
|
||||||
@LetterboxVerticalReachabilityPosition
|
|
||||||
private volatile int mLetterboxPositionForVerticalReachability;
|
|
||||||
|
|
||||||
// Whether education is allowed for letterboxed fullscreen apps.
|
// Whether education is allowed for letterboxed fullscreen apps.
|
||||||
private boolean mIsEducationEnabled;
|
private boolean mIsEducationEnabled;
|
||||||
|
|
||||||
// Whether using split screen aspect ratio as a default aspect ratio for unresizable apps.
|
// Whether using split screen aspect ratio as a default aspect ratio for unresizable apps.
|
||||||
private boolean mIsSplitScreenAspectRatioForUnresizableAppsEnabled;
|
private boolean mIsSplitScreenAspectRatioForUnresizableAppsEnabled;
|
||||||
|
|
||||||
|
// Responsible for the persistence of letterbox[Horizontal|Vertical]PositionMultiplier
|
||||||
|
@NonNull
|
||||||
|
private final LetterboxConfigurationPersister mLetterboxConfigurationPersister;
|
||||||
|
|
||||||
LetterboxConfiguration(Context systemUiContext) {
|
LetterboxConfiguration(Context systemUiContext) {
|
||||||
|
this(systemUiContext, new LetterboxConfigurationPersister(systemUiContext,
|
||||||
|
() -> readLetterboxHorizontalReachabilityPositionFromConfig(systemUiContext),
|
||||||
|
() -> readLetterboxVerticalReachabilityPositionFromConfig(systemUiContext)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
LetterboxConfiguration(Context systemUiContext,
|
||||||
|
LetterboxConfigurationPersister letterboxConfigurationPersister) {
|
||||||
mContext = systemUiContext;
|
mContext = systemUiContext;
|
||||||
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
|
mFixedOrientationLetterboxAspectRatio = mContext.getResources().getFloat(
|
||||||
R.dimen.config_fixedOrientationLetterboxAspectRatio);
|
R.dimen.config_fixedOrientationLetterboxAspectRatio);
|
||||||
@@ -206,14 +200,14 @@ final class LetterboxConfiguration {
|
|||||||
readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
|
readLetterboxHorizontalReachabilityPositionFromConfig(mContext);
|
||||||
mDefaultPositionForVerticalReachability =
|
mDefaultPositionForVerticalReachability =
|
||||||
readLetterboxVerticalReachabilityPositionFromConfig(mContext);
|
readLetterboxVerticalReachabilityPositionFromConfig(mContext);
|
||||||
mLetterboxPositionForHorizontalReachability = mDefaultPositionForHorizontalReachability;
|
|
||||||
mLetterboxPositionForVerticalReachability = mDefaultPositionForVerticalReachability;
|
|
||||||
mIsEducationEnabled = mContext.getResources().getBoolean(
|
mIsEducationEnabled = mContext.getResources().getBoolean(
|
||||||
R.bool.config_letterboxIsEducationEnabled);
|
R.bool.config_letterboxIsEducationEnabled);
|
||||||
setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
|
setDefaultMinAspectRatioForUnresizableApps(mContext.getResources().getFloat(
|
||||||
R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
|
R.dimen.config_letterboxDefaultMinAspectRatioForUnresizableApps));
|
||||||
mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean(
|
mIsSplitScreenAspectRatioForUnresizableAppsEnabled = mContext.getResources().getBoolean(
|
||||||
R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
|
R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
|
||||||
|
mLetterboxConfigurationPersister = letterboxConfigurationPersister;
|
||||||
|
mLetterboxConfigurationPersister.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -653,7 +647,9 @@ final class LetterboxConfiguration {
|
|||||||
* <p>The position multiplier is changed after each double tap in the letterbox area.
|
* <p>The position multiplier is changed after each double tap in the letterbox area.
|
||||||
*/
|
*/
|
||||||
float getHorizontalMultiplierForReachability() {
|
float getHorizontalMultiplierForReachability() {
|
||||||
switch (mLetterboxPositionForHorizontalReachability) {
|
final int letterboxPositionForHorizontalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
|
switch (letterboxPositionForHorizontalReachability) {
|
||||||
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
|
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT:
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
|
case LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER:
|
||||||
@@ -662,10 +658,11 @@ final class LetterboxConfiguration {
|
|||||||
return 1.0f;
|
return 1.0f;
|
||||||
default:
|
default:
|
||||||
throw new AssertionError(
|
throw new AssertionError(
|
||||||
"Unexpected letterbox position type: "
|
"Unexpected letterbox position type: "
|
||||||
+ mLetterboxPositionForHorizontalReachability);
|
+ letterboxPositionForHorizontalReachability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gets vertical position of a center of the letterboxed app window when reachability
|
* Gets vertical position of a center of the letterboxed app window when reachability
|
||||||
* is enabled specified. 0 corresponds to the top side of the screen and 1 to the bottom side.
|
* is enabled specified. 0 corresponds to the top side of the screen and 1 to the bottom side.
|
||||||
@@ -673,7 +670,9 @@ final class LetterboxConfiguration {
|
|||||||
* <p>The position multiplier is changed after each double tap in the letterbox area.
|
* <p>The position multiplier is changed after each double tap in the letterbox area.
|
||||||
*/
|
*/
|
||||||
float getVerticalMultiplierForReachability() {
|
float getVerticalMultiplierForReachability() {
|
||||||
switch (mLetterboxPositionForVerticalReachability) {
|
final int letterboxPositionForVerticalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
|
||||||
|
switch (letterboxPositionForVerticalReachability) {
|
||||||
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
|
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP:
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
|
case LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER:
|
||||||
@@ -683,7 +682,7 @@ final class LetterboxConfiguration {
|
|||||||
default:
|
default:
|
||||||
throw new AssertionError(
|
throw new AssertionError(
|
||||||
"Unexpected letterbox position type: "
|
"Unexpected letterbox position type: "
|
||||||
+ mLetterboxPositionForVerticalReachability);
|
+ letterboxPositionForVerticalReachability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,7 +692,7 @@ final class LetterboxConfiguration {
|
|||||||
*/
|
*/
|
||||||
@LetterboxHorizontalReachabilityPosition
|
@LetterboxHorizontalReachabilityPosition
|
||||||
int getLetterboxPositionForHorizontalReachability() {
|
int getLetterboxPositionForHorizontalReachability() {
|
||||||
return mLetterboxPositionForHorizontalReachability;
|
return mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -702,7 +701,7 @@ final class LetterboxConfiguration {
|
|||||||
*/
|
*/
|
||||||
@LetterboxVerticalReachabilityPosition
|
@LetterboxVerticalReachabilityPosition
|
||||||
int getLetterboxPositionForVerticalReachability() {
|
int getLetterboxPositionForVerticalReachability() {
|
||||||
return mLetterboxPositionForVerticalReachability;
|
return mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */
|
/** Returns a string representing the given {@link LetterboxHorizontalReachabilityPosition}. */
|
||||||
@@ -742,9 +741,8 @@ final class LetterboxConfiguration {
|
|||||||
* right side.
|
* right side.
|
||||||
*/
|
*/
|
||||||
void movePositionForHorizontalReachabilityToNextRightStop() {
|
void movePositionForHorizontalReachabilityToNextRightStop() {
|
||||||
mLetterboxPositionForHorizontalReachability = Math.min(
|
updatePositionForHorizontalReachability(prev -> Math.min(
|
||||||
mLetterboxPositionForHorizontalReachability + 1,
|
prev + 1, LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT));
|
||||||
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -752,8 +750,7 @@ final class LetterboxConfiguration {
|
|||||||
* side.
|
* side.
|
||||||
*/
|
*/
|
||||||
void movePositionForHorizontalReachabilityToNextLeftStop() {
|
void movePositionForHorizontalReachabilityToNextLeftStop() {
|
||||||
mLetterboxPositionForHorizontalReachability =
|
updatePositionForHorizontalReachability(prev -> Math.max(prev - 1, 0));
|
||||||
Math.max(mLetterboxPositionForHorizontalReachability - 1, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -761,9 +758,8 @@ final class LetterboxConfiguration {
|
|||||||
* side.
|
* side.
|
||||||
*/
|
*/
|
||||||
void movePositionForVerticalReachabilityToNextBottomStop() {
|
void movePositionForVerticalReachabilityToNextBottomStop() {
|
||||||
mLetterboxPositionForVerticalReachability = Math.min(
|
updatePositionForVerticalReachability(prev -> Math.min(
|
||||||
mLetterboxPositionForVerticalReachability + 1,
|
prev + 1, LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM));
|
||||||
LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -771,8 +767,7 @@ final class LetterboxConfiguration {
|
|||||||
* side.
|
* side.
|
||||||
*/
|
*/
|
||||||
void movePositionForVerticalReachabilityToNextTopStop() {
|
void movePositionForVerticalReachabilityToNextTopStop() {
|
||||||
mLetterboxPositionForVerticalReachability =
|
updatePositionForVerticalReachability(prev -> Math.max(prev - 1, 0));
|
||||||
Math.max(mLetterboxPositionForVerticalReachability - 1, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -822,4 +817,26 @@ final class LetterboxConfiguration {
|
|||||||
R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
|
R.bool.config_letterboxIsSplitScreenAspectRatioForUnresizableAppsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Calculates a new letterboxPositionForHorizontalReachability value and updates the store */
|
||||||
|
private void updatePositionForHorizontalReachability(
|
||||||
|
Function<Integer, Integer> newHorizonalPositionFun) {
|
||||||
|
final int letterboxPositionForHorizontalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
|
final int nextHorizontalPosition = newHorizonalPositionFun.apply(
|
||||||
|
letterboxPositionForHorizontalReachability);
|
||||||
|
mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
|
||||||
|
nextHorizontalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calculates a new letterboxPositionForVerticalReachability value and updates the store */
|
||||||
|
private void updatePositionForVerticalReachability(
|
||||||
|
Function<Integer, Integer> newVerticalPositionFun) {
|
||||||
|
final int letterboxPositionForVerticalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
|
||||||
|
final int nextVerticalPosition = newVerticalPositionFun.apply(
|
||||||
|
letterboxPositionForVerticalReachability);
|
||||||
|
mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
|
||||||
|
nextVerticalPosition);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
||||||
|
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.AtomicFile;
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
|
||||||
|
import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
|
||||||
|
import com.android.server.wm.nano.WindowManagerProtos;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persists the values of letterboxPositionForHorizontalReachability and
|
||||||
|
* letterboxPositionForVerticalReachability for {@link LetterboxConfiguration}.
|
||||||
|
*/
|
||||||
|
class LetterboxConfigurationPersister {
|
||||||
|
|
||||||
|
private static final String TAG =
|
||||||
|
TAG_WITH_CLASS_NAME ? "LetterboxConfigurationPersister" : TAG_WM;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String LETTERBOX_CONFIGURATION_FILENAME = "letterbox_config";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final Supplier<Integer> mDefaultHorizontalReachabilitySupplier;
|
||||||
|
private final Supplier<Integer> mDefaultVerticalReachabilitySupplier;
|
||||||
|
|
||||||
|
// Horizontal position of a center of the letterboxed app window which is global to prevent
|
||||||
|
// "jumps" when switching between letterboxed apps. It's updated to reposition the app window
|
||||||
|
// in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
|
||||||
|
// LetterboxUiController#getHorizontalPositionMultiplier which is called from
|
||||||
|
// ActivityRecord#updateResolvedBoundsPosition.
|
||||||
|
@LetterboxHorizontalReachabilityPosition
|
||||||
|
private volatile int mLetterboxPositionForHorizontalReachability;
|
||||||
|
|
||||||
|
// Vertical position of a center of the letterboxed app window which is global to prevent
|
||||||
|
// "jumps" when switching between letterboxed apps. It's updated to reposition the app window
|
||||||
|
// in response to a double tap gesture (see LetterboxUiController#handleDoubleTap). Used in
|
||||||
|
// LetterboxUiController#getVerticalPositionMultiplier which is called from
|
||||||
|
// ActivityRecord#updateResolvedBoundsPosition.
|
||||||
|
@LetterboxVerticalReachabilityPosition
|
||||||
|
private volatile int mLetterboxPositionForVerticalReachability;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final AtomicFile mConfigurationFile;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Consumer<String> mCompletionCallback;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final PersisterQueue mPersisterQueue;
|
||||||
|
|
||||||
|
LetterboxConfigurationPersister(Context systemUiContext,
|
||||||
|
Supplier<Integer> defaultHorizontalReachabilitySupplier,
|
||||||
|
Supplier<Integer> defaultVerticalReachabilitySupplier) {
|
||||||
|
this(systemUiContext, defaultHorizontalReachabilitySupplier,
|
||||||
|
defaultVerticalReachabilitySupplier,
|
||||||
|
Environment.getDataSystemDirectory(), new PersisterQueue(),
|
||||||
|
/* completionCallback */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
LetterboxConfigurationPersister(Context systemUiContext,
|
||||||
|
Supplier<Integer> defaultHorizontalReachabilitySupplier,
|
||||||
|
Supplier<Integer> defaultVerticalReachabilitySupplier, File configFolder,
|
||||||
|
PersisterQueue persisterQueue, @Nullable Consumer<String> completionCallback) {
|
||||||
|
mContext = systemUiContext.createDeviceProtectedStorageContext();
|
||||||
|
mDefaultHorizontalReachabilitySupplier = defaultHorizontalReachabilitySupplier;
|
||||||
|
mDefaultVerticalReachabilitySupplier = defaultVerticalReachabilitySupplier;
|
||||||
|
mCompletionCallback = completionCallback;
|
||||||
|
final File prefFiles = new File(configFolder, LETTERBOX_CONFIGURATION_FILENAME);
|
||||||
|
mConfigurationFile = new AtomicFile(prefFiles);
|
||||||
|
mPersisterQueue = persisterQueue;
|
||||||
|
readCurrentConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Startes the persistence queue
|
||||||
|
*/
|
||||||
|
void start() {
|
||||||
|
mPersisterQueue.startPersisting();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the horizontal position of the letterboxed app window when horizontal reachability is
|
||||||
|
* enabled.
|
||||||
|
*/
|
||||||
|
@LetterboxHorizontalReachabilityPosition
|
||||||
|
int getLetterboxPositionForHorizontalReachability() {
|
||||||
|
return mLetterboxPositionForHorizontalReachability;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the vertical position of the letterboxed app window when vertical reachability is
|
||||||
|
* enabled.
|
||||||
|
*/
|
||||||
|
@LetterboxVerticalReachabilityPosition
|
||||||
|
int getLetterboxPositionForVerticalReachability() {
|
||||||
|
return mLetterboxPositionForVerticalReachability;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates letterboxPositionForVerticalReachability if different from the current value
|
||||||
|
*/
|
||||||
|
void setLetterboxPositionForHorizontalReachability(
|
||||||
|
int letterboxPositionForHorizontalReachability) {
|
||||||
|
if (mLetterboxPositionForHorizontalReachability
|
||||||
|
!= letterboxPositionForHorizontalReachability) {
|
||||||
|
mLetterboxPositionForHorizontalReachability =
|
||||||
|
letterboxPositionForHorizontalReachability;
|
||||||
|
updateConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates letterboxPositionForVerticalReachability if different from the current value
|
||||||
|
*/
|
||||||
|
void setLetterboxPositionForVerticalReachability(
|
||||||
|
int letterboxPositionForVerticalReachability) {
|
||||||
|
if (mLetterboxPositionForVerticalReachability != letterboxPositionForVerticalReachability) {
|
||||||
|
mLetterboxPositionForVerticalReachability = letterboxPositionForVerticalReachability;
|
||||||
|
updateConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void useDefaultValue() {
|
||||||
|
mLetterboxPositionForHorizontalReachability = mDefaultHorizontalReachabilitySupplier.get();
|
||||||
|
mLetterboxPositionForVerticalReachability = mDefaultVerticalReachabilitySupplier.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readCurrentConfiguration() {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
try {
|
||||||
|
fis = mConfigurationFile.openRead();
|
||||||
|
byte[] protoData = readInputStream(fis);
|
||||||
|
final WindowManagerProtos.LetterboxProto letterboxData =
|
||||||
|
WindowManagerProtos.LetterboxProto.parseFrom(protoData);
|
||||||
|
mLetterboxPositionForHorizontalReachability =
|
||||||
|
letterboxData.letterboxPositionForHorizontalReachability;
|
||||||
|
mLetterboxPositionForVerticalReachability =
|
||||||
|
letterboxData.letterboxPositionForVerticalReachability;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Slog.e(TAG,
|
||||||
|
"Error reading from LetterboxConfigurationPersister. "
|
||||||
|
+ "Using default values!", ioe);
|
||||||
|
useDefaultValue();
|
||||||
|
} finally {
|
||||||
|
if (fis != null) {
|
||||||
|
try {
|
||||||
|
fis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
useDefaultValue();
|
||||||
|
Slog.e(TAG, "Error reading from LetterboxConfigurationPersister ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateConfiguration() {
|
||||||
|
mPersisterQueue.addItem(new UpdateValuesCommand(mConfigurationFile,
|
||||||
|
mLetterboxPositionForHorizontalReachability,
|
||||||
|
mLetterboxPositionForVerticalReachability,
|
||||||
|
mCompletionCallback), /* flush */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] readInputStream(InputStream in) throws IOException {
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int size = in.read(buffer);
|
||||||
|
while (size > 0) {
|
||||||
|
outputStream.write(buffer, 0, size);
|
||||||
|
size = in.read(buffer);
|
||||||
|
}
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
} finally {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class UpdateValuesCommand implements
|
||||||
|
PersisterQueue.WriteQueueItem<UpdateValuesCommand> {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final AtomicFile mFileToUpdate;
|
||||||
|
@Nullable
|
||||||
|
private final Consumer<String> mOnComplete;
|
||||||
|
|
||||||
|
|
||||||
|
private final int mHorizontalReachability;
|
||||||
|
private final int mVerticalReachability;
|
||||||
|
|
||||||
|
UpdateValuesCommand(@NonNull AtomicFile fileToUpdate,
|
||||||
|
int horizontalReachability, int verticalReachability,
|
||||||
|
@Nullable Consumer<String> onComplete) {
|
||||||
|
mFileToUpdate = fileToUpdate;
|
||||||
|
mHorizontalReachability = horizontalReachability;
|
||||||
|
mVerticalReachability = verticalReachability;
|
||||||
|
mOnComplete = onComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process() {
|
||||||
|
final WindowManagerProtos.LetterboxProto letterboxData =
|
||||||
|
new WindowManagerProtos.LetterboxProto();
|
||||||
|
letterboxData.letterboxPositionForHorizontalReachability = mHorizontalReachability;
|
||||||
|
letterboxData.letterboxPositionForVerticalReachability = mVerticalReachability;
|
||||||
|
final byte[] bytes = WindowManagerProtos.LetterboxProto.toByteArray(letterboxData);
|
||||||
|
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
try {
|
||||||
|
fos = mFileToUpdate.startWrite();
|
||||||
|
fos.write(bytes);
|
||||||
|
mFileToUpdate.finishWrite(fos);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
mFileToUpdate.failWrite(fos);
|
||||||
|
Slog.e(TAG,
|
||||||
|
"Error writing to LetterboxConfigurationPersister. "
|
||||||
|
+ "Using default values!", ioe);
|
||||||
|
} finally {
|
||||||
|
if (mOnComplete != null) {
|
||||||
|
mOnComplete.accept("UpdateValuesCommand");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
|
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
|
||||||
|
import static com.android.server.wm.LetterboxConfigurationPersister.LETTERBOX_CONFIGURATION_FILENAME;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
import android.util.AtomicFile;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@Presubmit
|
||||||
|
public class LetterboxConfigurationPersisterTest {
|
||||||
|
|
||||||
|
private static final long TIMEOUT = 2000L; // 2 secs
|
||||||
|
|
||||||
|
private LetterboxConfigurationPersister mLetterboxConfigurationPersister;
|
||||||
|
private Context mContext;
|
||||||
|
private PersisterQueue mPersisterQueue;
|
||||||
|
private QueueState mQueueState;
|
||||||
|
private PersisterQueue.Listener mQueueListener;
|
||||||
|
private File mConfigFolder;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
mContext = getInstrumentation().getTargetContext();
|
||||||
|
mConfigFolder = mContext.getFilesDir();
|
||||||
|
mPersisterQueue = new PersisterQueue();
|
||||||
|
mQueueState = new QueueState();
|
||||||
|
mLetterboxConfigurationPersister = new LetterboxConfigurationPersister(mContext,
|
||||||
|
() -> mContext.getResources().getInteger(
|
||||||
|
R.integer.config_letterboxDefaultPositionForHorizontalReachability),
|
||||||
|
() -> mContext.getResources().getInteger(
|
||||||
|
R.integer.config_letterboxDefaultPositionForVerticalReachability),
|
||||||
|
mConfigFolder, mPersisterQueue, mQueueState);
|
||||||
|
mQueueListener = queueEmpty -> mQueueState.onItemAdded();
|
||||||
|
mPersisterQueue.addListener(mQueueListener);
|
||||||
|
mLetterboxConfigurationPersister.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tearDown() throws InterruptedException {
|
||||||
|
deleteConfiguration(mLetterboxConfigurationPersister, mPersisterQueue);
|
||||||
|
waitForCompletion(mPersisterQueue);
|
||||||
|
mPersisterQueue.removeListener(mQueueListener);
|
||||||
|
stopPersisterSafe(mPersisterQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenStoreIsCreated_valuesAreDefaults() {
|
||||||
|
final int positionForHorizontalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
|
final int defaultPositionForHorizontalReachability =
|
||||||
|
mContext.getResources().getInteger(
|
||||||
|
R.integer.config_letterboxDefaultPositionForHorizontalReachability);
|
||||||
|
Assert.assertEquals(defaultPositionForHorizontalReachability,
|
||||||
|
positionForHorizontalReachability);
|
||||||
|
final int positionForVerticalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
|
||||||
|
final int defaultPositionForVerticalReachability =
|
||||||
|
mContext.getResources().getInteger(
|
||||||
|
R.integer.config_letterboxDefaultPositionForVerticalReachability);
|
||||||
|
Assert.assertEquals(defaultPositionForVerticalReachability,
|
||||||
|
positionForVerticalReachability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenUpdatedWithNewValues_valuesAreWritten() {
|
||||||
|
mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
|
||||||
|
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
|
||||||
|
mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
|
||||||
|
LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
|
||||||
|
waitForCompletion(mPersisterQueue);
|
||||||
|
final int newPositionForHorizontalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
|
final int newPositionForVerticalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
|
||||||
|
Assert.assertEquals(LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
|
||||||
|
newPositionForHorizontalReachability);
|
||||||
|
Assert.assertEquals(LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
|
||||||
|
newPositionForVerticalReachability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenUpdatedWithNewValues_valuesAreReadAfterRestart() {
|
||||||
|
final PersisterQueue firstPersisterQueue = new PersisterQueue();
|
||||||
|
final LetterboxConfigurationPersister firstPersister = new LetterboxConfigurationPersister(
|
||||||
|
mContext, () -> -1, () -> -1, mContext.getFilesDir(), firstPersisterQueue,
|
||||||
|
mQueueState);
|
||||||
|
firstPersister.start();
|
||||||
|
firstPersister.setLetterboxPositionForHorizontalReachability(
|
||||||
|
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
|
||||||
|
firstPersister.setLetterboxPositionForVerticalReachability(
|
||||||
|
LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
|
||||||
|
waitForCompletion(firstPersisterQueue);
|
||||||
|
stopPersisterSafe(firstPersisterQueue);
|
||||||
|
final PersisterQueue secondPersisterQueue = new PersisterQueue();
|
||||||
|
final LetterboxConfigurationPersister secondPersister = new LetterboxConfigurationPersister(
|
||||||
|
mContext, () -> -1, () -> -1, mContext.getFilesDir(), secondPersisterQueue,
|
||||||
|
mQueueState);
|
||||||
|
secondPersister.start();
|
||||||
|
final int newPositionForHorizontalReachability =
|
||||||
|
secondPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
|
final int newPositionForVerticalReachability =
|
||||||
|
secondPersister.getLetterboxPositionForVerticalReachability();
|
||||||
|
Assert.assertEquals(LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
|
||||||
|
newPositionForHorizontalReachability);
|
||||||
|
Assert.assertEquals(LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
|
||||||
|
newPositionForVerticalReachability);
|
||||||
|
deleteConfiguration(secondPersister, secondPersisterQueue);
|
||||||
|
waitForCompletion(secondPersisterQueue);
|
||||||
|
stopPersisterSafe(secondPersisterQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenUpdatedWithNewValuesAndDeleted_valuesAreDefaults() {
|
||||||
|
mLetterboxConfigurationPersister.setLetterboxPositionForHorizontalReachability(
|
||||||
|
LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
|
||||||
|
mLetterboxConfigurationPersister.setLetterboxPositionForVerticalReachability(
|
||||||
|
LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
|
||||||
|
waitForCompletion(mPersisterQueue);
|
||||||
|
final int newPositionForHorizontalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
|
final int newPositionForVerticalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
|
||||||
|
Assert.assertEquals(LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
|
||||||
|
newPositionForHorizontalReachability);
|
||||||
|
Assert.assertEquals(LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
|
||||||
|
newPositionForVerticalReachability);
|
||||||
|
deleteConfiguration(mLetterboxConfigurationPersister, mPersisterQueue);
|
||||||
|
waitForCompletion(mPersisterQueue);
|
||||||
|
final int positionForHorizontalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForHorizontalReachability();
|
||||||
|
final int defaultPositionForHorizontalReachability =
|
||||||
|
mContext.getResources().getInteger(
|
||||||
|
R.integer.config_letterboxDefaultPositionForHorizontalReachability);
|
||||||
|
Assert.assertEquals(defaultPositionForHorizontalReachability,
|
||||||
|
positionForHorizontalReachability);
|
||||||
|
final int positionForVerticalReachability =
|
||||||
|
mLetterboxConfigurationPersister.getLetterboxPositionForVerticalReachability();
|
||||||
|
final int defaultPositionForVerticalReachability =
|
||||||
|
mContext.getResources().getInteger(
|
||||||
|
R.integer.config_letterboxDefaultPositionForVerticalReachability);
|
||||||
|
Assert.assertEquals(defaultPositionForVerticalReachability,
|
||||||
|
positionForVerticalReachability);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopPersisterSafe(PersisterQueue persisterQueue) {
|
||||||
|
try {
|
||||||
|
persisterQueue.stopPersisting();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForCompletion(PersisterQueue persisterQueue) {
|
||||||
|
final long endTime = System.currentTimeMillis() + TIMEOUT;
|
||||||
|
// The queue could be empty but the last item still processing and not completed. For this
|
||||||
|
// reason the completion happens when there are not more items to process and the last one
|
||||||
|
// has completed.
|
||||||
|
while (System.currentTimeMillis() < endTime && (!isQueueEmpty(persisterQueue)
|
||||||
|
|| !hasLastItemCompleted())) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException ie) { /* Nope */}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isQueueEmpty(PersisterQueue persisterQueue) {
|
||||||
|
return persisterQueue.findLastItem(
|
||||||
|
writeQueueItem -> true, PersisterQueue.WriteQueueItem.class) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasLastItemCompleted() {
|
||||||
|
return mQueueState.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteConfiguration(LetterboxConfigurationPersister persister,
|
||||||
|
PersisterQueue persisterQueue) {
|
||||||
|
final AtomicFile fileToDelete = new AtomicFile(
|
||||||
|
new File(mConfigFolder, LETTERBOX_CONFIGURATION_FILENAME));
|
||||||
|
persisterQueue.addItem(
|
||||||
|
new DeleteFileCommand(fileToDelete, mQueueState.andThen(
|
||||||
|
s -> persister.useDefaultValue())), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DeleteFileCommand implements
|
||||||
|
PersisterQueue.WriteQueueItem<DeleteFileCommand> {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final AtomicFile mFileToDelete;
|
||||||
|
@Nullable
|
||||||
|
private final Consumer<String> mOnComplete;
|
||||||
|
|
||||||
|
DeleteFileCommand(@NonNull AtomicFile fileToDelete, Consumer<String> onComplete) {
|
||||||
|
mFileToDelete = fileToDelete;
|
||||||
|
mOnComplete = onComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process() {
|
||||||
|
mFileToDelete.delete();
|
||||||
|
if (mOnComplete != null) {
|
||||||
|
mOnComplete.accept("DeleteFileCommand");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains the current length of the persister queue
|
||||||
|
private static class QueueState implements Consumer<String> {
|
||||||
|
|
||||||
|
// The current number of commands in the queue
|
||||||
|
@VisibleForTesting
|
||||||
|
private final AtomicInteger mCounter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(String s) {
|
||||||
|
mCounter.decrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onItemAdded() {
|
||||||
|
mCounter.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isEmpty() {
|
||||||
|
return mCounter.get() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||||
|
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER;
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT;
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT;
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM;
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER;
|
||||||
|
import static com.android.server.wm.LetterboxConfiguration.LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@Presubmit
|
||||||
|
public class LetterboxConfigurationTest {
|
||||||
|
|
||||||
|
private LetterboxConfiguration mLetterboxConfiguration;
|
||||||
|
private LetterboxConfigurationPersister mLetterboxConfigurationPersister;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
Context context = getInstrumentation().getTargetContext();
|
||||||
|
mLetterboxConfigurationPersister = mock(LetterboxConfigurationPersister.class);
|
||||||
|
mLetterboxConfiguration = new LetterboxConfiguration(context,
|
||||||
|
mLetterboxConfigurationPersister);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenReadingValues_storeIsInvoked() {
|
||||||
|
mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability();
|
||||||
|
verify(mLetterboxConfigurationPersister).getLetterboxPositionForHorizontalReachability();
|
||||||
|
mLetterboxConfiguration.getLetterboxPositionForVerticalReachability();
|
||||||
|
verify(mLetterboxConfigurationPersister).getLetterboxPositionForVerticalReachability();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenSettingValues_updateConfigurationIsInvoked() {
|
||||||
|
mLetterboxConfiguration.movePositionForHorizontalReachabilityToNextRightStop();
|
||||||
|
verify(mLetterboxConfigurationPersister).setLetterboxPositionForHorizontalReachability(
|
||||||
|
anyInt());
|
||||||
|
mLetterboxConfiguration.movePositionForVerticalReachabilityToNextBottomStop();
|
||||||
|
verify(mLetterboxConfigurationPersister).setLetterboxPositionForVerticalReachability(
|
||||||
|
anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenMovedHorizontally_updatePositionAccordingly() {
|
||||||
|
// Starting from center
|
||||||
|
assertForHorizontalMove(
|
||||||
|
/* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
|
||||||
|
/* expectedTime */ 1,
|
||||||
|
LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
|
||||||
|
assertForHorizontalMove(
|
||||||
|
/* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
|
||||||
|
/* expectedTime */ 1,
|
||||||
|
LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
|
||||||
|
// Starting from left
|
||||||
|
assertForHorizontalMove(
|
||||||
|
/* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
|
||||||
|
/* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
|
||||||
|
/* expectedTime */ 2,
|
||||||
|
LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
|
||||||
|
assertForHorizontalMove(
|
||||||
|
/* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT,
|
||||||
|
/* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expectedTime */ 1,
|
||||||
|
LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
|
||||||
|
// Starting from right
|
||||||
|
assertForHorizontalMove(
|
||||||
|
/* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
|
||||||
|
/* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
|
||||||
|
/* expectedTime */ 2,
|
||||||
|
LetterboxConfiguration::movePositionForHorizontalReachabilityToNextRightStop);
|
||||||
|
assertForHorizontalMove(
|
||||||
|
/* from */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_RIGHT,
|
||||||
|
/* expected */ LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expectedTime */ 2,
|
||||||
|
LetterboxConfiguration::movePositionForHorizontalReachabilityToNextLeftStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_whenMovedVertically_updatePositionAccordingly() {
|
||||||
|
// Starting from center
|
||||||
|
assertForVerticalMove(
|
||||||
|
/* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
|
||||||
|
/* expectedTime */ 1,
|
||||||
|
LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
|
||||||
|
assertForVerticalMove(
|
||||||
|
/* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
|
||||||
|
/* expectedTime */ 1,
|
||||||
|
LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
|
||||||
|
// Starting from top
|
||||||
|
assertForVerticalMove(
|
||||||
|
/* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
|
||||||
|
/* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expectedTime */ 1,
|
||||||
|
LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
|
||||||
|
assertForVerticalMove(
|
||||||
|
/* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
|
||||||
|
/* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP,
|
||||||
|
/* expectedTime */ 2,
|
||||||
|
LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
|
||||||
|
// Starting from bottom
|
||||||
|
assertForVerticalMove(
|
||||||
|
/* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
|
||||||
|
/* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_CENTER,
|
||||||
|
/* expectedTime */ 2,
|
||||||
|
LetterboxConfiguration::movePositionForVerticalReachabilityToNextTopStop);
|
||||||
|
assertForVerticalMove(
|
||||||
|
/* from */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
|
||||||
|
/* expected */ LETTERBOX_VERTICAL_REACHABILITY_POSITION_BOTTOM,
|
||||||
|
/* expectedTime */ 2,
|
||||||
|
LetterboxConfiguration::movePositionForVerticalReachabilityToNextBottomStop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertForHorizontalMove(int from, int expected, int expectedTime,
|
||||||
|
Consumer<LetterboxConfiguration> move) {
|
||||||
|
// We are in the current position
|
||||||
|
when(mLetterboxConfiguration.getLetterboxPositionForHorizontalReachability())
|
||||||
|
.thenReturn(from);
|
||||||
|
move.accept(mLetterboxConfiguration);
|
||||||
|
verify(mLetterboxConfigurationPersister,
|
||||||
|
times(expectedTime)).setLetterboxPositionForHorizontalReachability(
|
||||||
|
expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertForVerticalMove(int from, int expected, int expectedTime,
|
||||||
|
Consumer<LetterboxConfiguration> move) {
|
||||||
|
// We are in the current position
|
||||||
|
when(mLetterboxConfiguration.getLetterboxPositionForVerticalReachability())
|
||||||
|
.thenReturn(from);
|
||||||
|
move.accept(mLetterboxConfiguration);
|
||||||
|
verify(mLetterboxConfigurationPersister,
|
||||||
|
times(expectedTime)).setLetterboxPositionForVerticalReachability(
|
||||||
|
expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user