243 lines
8.6 KiB
Java
243 lines
8.6 KiB
Java
/*
|
|
* 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.wm.shell.onehanded;
|
|
|
|
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
|
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
|
|
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
|
|
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
|
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
|
|
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
|
|
|
import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
|
|
import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.Configuration;
|
|
import android.graphics.Color;
|
|
import android.graphics.PixelFormat;
|
|
import android.graphics.Rect;
|
|
import android.os.Binder;
|
|
import android.util.Slog;
|
|
import android.view.ContextThemeWrapper;
|
|
import android.view.IWindow;
|
|
import android.view.LayoutInflater;
|
|
import android.view.SurfaceControl;
|
|
import android.view.SurfaceControlViewHost;
|
|
import android.view.SurfaceSession;
|
|
import android.view.View;
|
|
import android.view.WindowManager;
|
|
import android.view.WindowlessWindowManager;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.android.wm.shell.R;
|
|
import com.android.wm.shell.common.DisplayLayout;
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
/**
|
|
* Holds view hierarchy of a root surface and helps inflate a themeable view for background.
|
|
*/
|
|
public final class BackgroundWindowManager extends WindowlessWindowManager {
|
|
private static final String TAG = BackgroundWindowManager.class.getSimpleName();
|
|
private static final int THEME_COLOR_OFFSET = 10;
|
|
|
|
private final OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
|
|
mTransactionFactory;
|
|
|
|
private Context mContext;
|
|
private Rect mDisplayBounds;
|
|
private SurfaceControlViewHost mViewHost;
|
|
private SurfaceControl mLeash;
|
|
private View mBackgroundView;
|
|
private @OneHandedState.State int mCurrentState;
|
|
|
|
public BackgroundWindowManager(Context context) {
|
|
super(context.getResources().getConfiguration(), null /* rootSurface */,
|
|
null /* hostInputToken */);
|
|
mContext = context;
|
|
mTransactionFactory = SurfaceControl.Transaction::new;
|
|
}
|
|
|
|
@Override
|
|
public SurfaceControl getSurfaceControl(IWindow window) {
|
|
return super.getSurfaceControl(window);
|
|
}
|
|
|
|
@Override
|
|
public void setConfiguration(Configuration configuration) {
|
|
super.setConfiguration(configuration);
|
|
mContext = mContext.createConfigurationContext(configuration);
|
|
}
|
|
|
|
/**
|
|
* onConfigurationChanged events for updating background theme color.
|
|
*/
|
|
public void onConfigurationChanged() {
|
|
if (mCurrentState == STATE_ENTERING || mCurrentState == STATE_ACTIVE) {
|
|
updateThemeOnly();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* One-handed mode state changed callback
|
|
* @param newState of One-handed mode representing by {@link OneHandedState}
|
|
*/
|
|
public void onStateChanged(int newState) {
|
|
mCurrentState = newState;
|
|
}
|
|
|
|
@Override
|
|
protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
|
|
final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
|
|
.setColorLayer()
|
|
.setBufferSize(mDisplayBounds.width(), mDisplayBounds.height())
|
|
.setFormat(PixelFormat.RGB_888)
|
|
.setOpaque(true)
|
|
.setName(TAG)
|
|
.setCallsite("BackgroundWindowManager#attachToParentSurface");
|
|
mLeash = builder.build();
|
|
return mLeash;
|
|
}
|
|
|
|
/** Inflates background view on to the root surface. */
|
|
boolean initView() {
|
|
if (mBackgroundView != null || mViewHost != null) {
|
|
return false;
|
|
}
|
|
|
|
mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this,
|
|
"BackgroundWindowManager");
|
|
mBackgroundView = (View) LayoutInflater.from(mContext)
|
|
.inflate(R.layout.background_panel, null /* root */);
|
|
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
|
|
mDisplayBounds.width(), mDisplayBounds.height(), 0 /* TYPE NONE */,
|
|
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH
|
|
| FLAG_SLIPPERY, PixelFormat.TRANSLUCENT);
|
|
lp.token = new Binder();
|
|
lp.setTitle("background-panel");
|
|
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
|
|
mBackgroundView.setBackgroundColor(getThemeColorForBackground());
|
|
mViewHost.setView(mBackgroundView, lp);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Called when onDisplayAdded() or onDisplayRemoved() callback.
|
|
* @param displayLayout The latest {@link DisplayLayout} for display bounds.
|
|
*/
|
|
public void onDisplayChanged(DisplayLayout displayLayout) {
|
|
mDisplayBounds = new Rect(0, 0, displayLayout.width(), displayLayout.height());
|
|
}
|
|
|
|
private void updateThemeOnly() {
|
|
if (mBackgroundView == null || mViewHost == null || mLeash == null) {
|
|
Slog.w(TAG, "Background view or SurfaceControl does not exist when trying to "
|
|
+ "update theme only!");
|
|
return;
|
|
}
|
|
|
|
WindowManager.LayoutParams lp = (WindowManager.LayoutParams)
|
|
mBackgroundView.getLayoutParams();
|
|
mBackgroundView.setBackgroundColor(getThemeColorForBackground());
|
|
mViewHost.setView(mBackgroundView, lp);
|
|
}
|
|
|
|
/**
|
|
* Shows the background layer when One-handed mode triggered.
|
|
*/
|
|
public void showBackgroundLayer() {
|
|
if (!initView()) {
|
|
updateThemeOnly();
|
|
return;
|
|
}
|
|
if (mLeash == null) {
|
|
Slog.w(TAG, "SurfaceControl mLeash is null, can't show One-handed mode "
|
|
+ "background panel!");
|
|
return;
|
|
}
|
|
|
|
mTransactionFactory.getTransaction()
|
|
.setAlpha(mLeash, 1.0f)
|
|
.setLayer(mLeash, -1 /* at bottom-most layer */)
|
|
.show(mLeash)
|
|
.apply();
|
|
}
|
|
|
|
/**
|
|
* Remove the leash of background layer after stop One-handed mode.
|
|
*/
|
|
public void removeBackgroundLayer() {
|
|
if (mBackgroundView != null) {
|
|
mBackgroundView = null;
|
|
}
|
|
|
|
if (mViewHost != null) {
|
|
mViewHost.release();
|
|
mViewHost = null;
|
|
}
|
|
|
|
if (mLeash != null) {
|
|
mTransactionFactory.getTransaction().remove(mLeash).apply();
|
|
mLeash = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets {@link SurfaceControl} of the background layer.
|
|
* @return {@code null} if not exist.
|
|
*/
|
|
@Nullable
|
|
SurfaceControl getSurfaceControl() {
|
|
return mLeash;
|
|
}
|
|
|
|
private int getThemeColor() {
|
|
final Context themedContext = new ContextThemeWrapper(mContext,
|
|
com.android.internal.R.style.Theme_DeviceDefault_DayNight);
|
|
return themedContext.getColor(R.color.one_handed_tutorial_background_color);
|
|
}
|
|
|
|
int getThemeColorForBackground() {
|
|
final int origThemeColor = getThemeColor();
|
|
return android.graphics.Color.argb(Color.alpha(origThemeColor),
|
|
Color.red(origThemeColor) - THEME_COLOR_OFFSET,
|
|
Color.green(origThemeColor) - THEME_COLOR_OFFSET,
|
|
Color.blue(origThemeColor) - THEME_COLOR_OFFSET);
|
|
}
|
|
|
|
private float adjustColor(int origColor) {
|
|
return Math.max(origColor - THEME_COLOR_OFFSET, 0) / 255.0f;
|
|
}
|
|
|
|
void dump(@NonNull PrintWriter pw) {
|
|
final String innerPrefix = " ";
|
|
pw.println(TAG);
|
|
pw.print(innerPrefix + "mDisplayBounds=");
|
|
pw.println(mDisplayBounds);
|
|
pw.print(innerPrefix + "mViewHost=");
|
|
pw.println(mViewHost);
|
|
pw.print(innerPrefix + "mLeash=");
|
|
pw.println(mLeash);
|
|
pw.print(innerPrefix + "mBackgroundView=");
|
|
pw.println(mBackgroundView);
|
|
}
|
|
|
|
}
|