/***********************************************************
** Copyright (C), 2020-2030, OPLUS Mobile Comm Corp., Ltd.
** File: - OplusFoldSwitchStateObserver.java
** Description:
** Version: 1.0
** Date : 2023/6/7 - 14:04
** Author: LiangHan@WMS
**
** ---------------------Revision History: ---------------------
** <author> <data> <version > <desc>
** LiangHan 2023/6/7 - 14:04 1.0 build this module
****************************************************************/
package com.oplus.foldswitch;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static com.android.wm.shell.startingsurface.OplusShellStartingWindowUtils.typeCasting;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceState;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.OplusWindowManager;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.PathInterpolator;
import android.view.animation.ScaleAnimation;
import android.view.animation.ClipRectAnimation;
import android.window.TransitionInfo;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.transition.TransitionAnimationUtil;
import com.android.wm.shell.transition.TransitionLog;
import com.oplus.foldswitch.ReflectionHelper;
import com.oplus.transition.OplusShellLightOSTransition;
public class OplusFoldingSwitchAnimationManager {
public static final String TAG = "FSS_OplusFoldSwitchStateObserver";
public static final int DEVICE_STATE_CLOSE = 0;
public static final int DEVICE_STATE_TENT = 1;
public static final int DEVICE_STATE_CLOSE_ALL = 100;
public static final int FOLD_SWITCHING_TRANSITION_INVALID = -1;
public static final int FOLD_SWITCHING_TRANSITION_CLOSE = 1;
public static final int FOLD_SWITCHING_TRANSITION_OPEN = 2;
private static final float FOLD_SWITCHING_ANIMATION_SCALE = 1.2f;
private static final long RESET_TIME_OUT = 1500L;
private static final Object DEVICE_STATE_LOCK = new Object();
private final OplusWindowManager mOplusWindowManager;
private final OplusFoldSwitchStateObserver mFoldSwitchStateObserver = new OplusFoldSwitchStateObserver() {
@Override
public void onFoldingSwitchStateChanged(Bundle bundle) {
if (!bundle.containsKey(KEY_DEVICE_FOLDING)) {
return;
}
boolean deviceFolding = bundle.getBoolean(KEY_DEVICE_FOLDING);
updateDeviceFolding(deviceFolding);
}
};
private final DeviceStateManager.DeviceStateCallback mDeviceStateCallback = new DeviceStateManager.DeviceStateCallback() {
@Override
public void onDeviceStateChanged(DeviceState state) {
Log.d(TAG, "onStateChanged: state = " + state);
if(state == null) {
return;
}
setDeviceState(state.getIdentifier());
}
};
private Context mContext;
private ShellExecutor mMainExecutor;
private boolean mDeviceFolding = false;
private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE_IDENTIFIER;
public OplusFoldingSwitchAnimationManager(Context context, ShellExecutor mainExecutor) {
mContext = context;
mMainExecutor = mainExecutor;
mOplusWindowManager = new OplusWindowManager();
registerDeviceStateCallback();
}
public void registerOplusFoldSwitchStateObserver() {
try {
mOplusWindowManager.registerFoldSwitchStateObserver(mFoldSwitchStateObserver);
} catch (RemoteException e) {
Log.d(TAG, "failed to register fold switch observer, error = " + e);
}
}
public void unregisterOplusFoldSwitchStateObserver() {
try {
mOplusWindowManager.unregisterFoldSwitchStateObserver(mFoldSwitchStateObserver);
} catch (RemoteException e) {
Log.d(TAG, "failed to unregister fold switch observer, error = " + e);
}
}
public boolean getDeviceFolding() {
Log.d(TAG, "getDeviceFolding: mDeviceFolding = " + mDeviceFolding);
return mDeviceFolding;
}
public boolean getDeviceFolded() {
synchronized (DEVICE_STATE_LOCK) {
return isFoldedState(mDeviceState);
}
}
public Animation[] getDeviceFoldingRotationAnimations(int delta, int originWidth, int originHeight, int finalWidth, int finalHeight) {
TransitionLog.debug("getDeviceFoldingRotationAnimations ==> delta =:" + delta
+ ",originWidth =:" + originWidth
+ ",originHeight =:" + originHeight + ",finalWidth =:" + finalWidth + ",finalHeight =:"
+ finalHeight);
int rotateExitDuration = 200;
int rotateEnterDuration = 600;
PathInterpolator enterAlphaInterpolator = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
PathInterpolator enterScaleInterpolator = new PathInterpolator(0.3f, 0f, 0.1f, 1f);
float enterScaleNum = FOLD_SWITCHING_ANIMATION_SCALE;
Animation[] screenRotateAnimations = new Animation[2];
AnimationSet rotateExitAnim = new AnimationSet(false);
rotateExitAnim.setFillBefore(true);
rotateExitAnim.setFillAfter(true);
rotateExitAnim.setFillEnabled(true);
rotateExitAnim.addAnimation(new AlphaAnimation(1, 0) {{
setDuration(rotateExitDuration);
}});
rotateExitAnim.setStartOffset(rotateExitDuration);
AnimationSet rotateEnterAnim = new AnimationSet(false);
rotateEnterAnim.setFillBefore(true);
rotateEnterAnim.setFillAfter(true);
rotateEnterAnim.setFillEnabled(true);
AlphaAnimation enterAlpha = new AlphaAnimation(1, 1);
enterAlpha.setDuration(rotateEnterDuration);
enterAlpha.setInterpolator(enterAlphaInterpolator);
ClipRectAnimation enterClipAnim = new ClipRectAnimation(new Rect(0, 0, finalWidth, finalHeight),
new Rect(0, 0, finalWidth, finalHeight));
enterClipAnim.setDuration(rotateEnterDuration);
rotateEnterAnim.addAnimation(enterClipAnim);
ScaleAnimation enterScale = new ScaleAnimation(enterScaleNum, 1, enterScaleNum, 1,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
enterScale.setDuration(rotateEnterDuration);
enterScale.setInterpolator(enterScaleInterpolator);
rotateEnterAnim.addAnimation(enterAlpha);
if (!getDeviceFolded()) {
rotateEnterAnim.addAnimation(enterScale);
}
TransitionAnimationUtil.setAnimationHasRoundedCorners(rotateExitAnim, !OplusShellLightOSTransition.IS_LIGHTOS);
TransitionAnimationUtil.setAnimationHasRoundedCorners(rotateEnterAnim, !OplusShellLightOSTransition.IS_LIGHTOS);
screenRotateAnimations[0] = rotateExitAnim;
screenRotateAnimations[1] = rotateEnterAnim;
return screenRotateAnimations;
}
public boolean skipDefaultTransitionIfNeed(TransitionInfo info, TransitionInfo.Change change) {
int foldChangeType = getFoldChangeType(info);
if ((info.getFlags() & WindowManager.TRANSIT_FLAG_INVISIBLE) != 0
&& foldChangeType == FOLD_SWITCHING_TRANSITION_OPEN
&& change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
Log.d(TAG, "skip DefaultTransition");
return true;
}
return false;
}
public void initAnimLayerWhenFolding(SurfaceControl.Transaction t, SurfaceControl animLeash,
TransitionInfo info, int startWidth, int startHeight) {
setScale(t, animLeash, info, startWidth, startHeight);
}
public int getFoldChangeType(TransitionInfo info) {
return ReflectionHelper.oplusTransitionExtendedInfoGetFoldChangeType(info);
}
public boolean cancelAnimationIfNeedWhenFolding(TransitionInfo info) {
int foldChangeType = getFoldChangeType(info);
Log.d(TAG, "cancelAnimationIfNeedWhenFolding: foldChangeType = " + foldChangeType);
if ((info.getFlags() & WindowManager.TRANSIT_FLAG_INVISIBLE) != 0
&& (foldChangeType != FOLD_SWITCHING_TRANSITION_OPEN)) {
return true;
}
return foldChangeType == FOLD_SWITCHING_TRANSITION_CLOSE;
}
private void setScale(SurfaceControl.Transaction t, SurfaceControl animLeash, TransitionInfo info,
int startWidth, int startHeight) {
if (getFoldChangeType(info) == FOLD_SWITCHING_TRANSITION_OPEN) {
final Matrix matrix = new Matrix();
final float[] tmpFloats = new float[9];
matrix.setScale(FOLD_SWITCHING_ANIMATION_SCALE, FOLD_SWITCHING_ANIMATION_SCALE);
matrix.getValues(tmpFloats);
float x = (1 - FOLD_SWITCHING_ANIMATION_SCALE) / 2 * startWidth;
float y = (1 - FOLD_SWITCHING_ANIMATION_SCALE) / 2 * startHeight;
Log.d(TAG, "setScale: x = " + x + ", y = " + y + ", startWidth = " + startWidth + ", startHeight = " + startHeight);
t.setPosition(animLeash, x, y);
t.setMatrix(animLeash,
tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
}
}
private void registerDeviceStateCallback() {
DeviceStateManager deviceStateManager = (DeviceStateManager) mContext.getSystemService(Context.DEVICE_STATE_SERVICE);
deviceStateManager.registerCallback(mMainExecutor, mDeviceStateCallback);
}
private boolean isFoldedState(int deviceState) {
return TransitionAnimationUtil.isFoldDevice() && !TransitionAnimationUtil.isFlipDevice()
&& isFoldedDeviceState(deviceState);
}
private boolean isFoldedDeviceState(int deviceState) {
return deviceState == DEVICE_STATE_CLOSE || deviceState == DEVICE_STATE_TENT
|| deviceState == DEVICE_STATE_CLOSE_ALL;
}
private void setDeviceState(int deviceState) {
synchronized (DEVICE_STATE_LOCK) {
mDeviceState = deviceState;
}
}
private void updateDeviceFolding(boolean newDeviceFolding) {
if (mDeviceFolding == newDeviceFolding) {
return;
}
Log.d(TAG, "updateDeviceFolding old = " + mDeviceFolding + ", new = " + newDeviceFolding);
mDeviceFolding = newDeviceFolding;
}
}
解析以上写好的类和类中方法的作用与含义