diff options
Diffstat (limited to 'libs')
10 files changed, 127 insertions, 56 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java index 59a765d49a14..7440f19a6e7c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/TaskView.java @@ -87,16 +87,12 @@ public class TaskView extends SurfaceView implements SurfaceHolder.Callback, super(context, null, 0, 0, true /* disableBackgroundLayer */); mTaskOrganizer = organizer; + mExecutor = organizer.getExecutor(); setUseAlpha(); getHolder().addCallback(this); mGuard.open("release"); } - // TODO: Use TaskOrganizer executor when part of wmshell proper - public void setExecutor(Executor executor) { - mExecutor = executor; - } - /** * Only one listener may be set on the view, throws an exception otherwise. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 318a0bd42940..4bf01f7cffac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -59,7 +59,6 @@ import com.android.internal.policy.ScreenDecorationsUtils; import com.android.wm.shell.R; import com.android.wm.shell.TaskView; import com.android.wm.shell.common.AlphaOptimizedButton; -import com.android.wm.shell.common.HandlerExecutor; import com.android.wm.shell.common.TriangleShape; import java.io.FileDescriptor; @@ -304,11 +303,6 @@ public class BubbleExpandedView extends LinearLayout { setLayoutDirection(LAYOUT_DIRECTION_LOCALE); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mTaskView.setExecutor(new HandlerExecutor(getHandler())); - } /** * Initialize {@link BubbleController} and {@link BubbleStackView} here, this method must need * to be called after view inflate. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java index 50d9fe8629ac..e97fe0a9111c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java @@ -112,7 +112,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { } if (mMoving) { final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos; - mSplitLayout.updateDividePosition(position); + mSplitLayout.updateDivideBounds(position); } break; case MotionEvent.ACTION_UP: @@ -131,7 +131,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos; final DividerSnapAlgorithm.SnapTarget snapTarget = mSplitLayout.findSnapTarget(position, velocity); - mSplitLayout.setSnapTarget(snapTarget); + mSplitLayout.snapToTarget(position, snapTarget); break; } return true; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index e11037f55cfa..4c70b5d32108 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -22,6 +22,9 @@ import static android.view.WindowManager.DOCKED_TOP; import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END; import static com.android.internal.policy.DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -31,6 +34,7 @@ import android.view.SurfaceControl; import androidx.annotation.Nullable; import com.android.internal.policy.DividerSnapAlgorithm; +import com.android.wm.shell.animation.Interpolators; /** * Records and handles layout of splits. Helps to calculate proper bounds when configuration or @@ -145,17 +149,23 @@ public class SplitLayout { * Updates bounds with the passing position. Usually used to update recording bounds while * performing animation or dragging divider bar to resize the splits. */ - public void updateDividePosition(int position) { + void updateDivideBounds(int position) { updateBounds(position); mLayoutChangeListener.onBoundsChanging(this); } + void setDividePosition(int position) { + mDividePosition = position; + updateBounds(mDividePosition); + mLayoutChangeListener.onBoundsChanged(this); + } + /** * Sets new divide position and updates bounds correspondingly. Notifies listener if the new * target indicates dismissing split. */ - public void setSnapTarget(DividerSnapAlgorithm.SnapTarget snapTarget) { - switch(snapTarget.flag) { + public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) { + switch (snapTarget.flag) { case FLAG_DISMISS_START: mLayoutChangeListener.onSnappedToDismiss(false /* snappedToEnd */); break; @@ -163,9 +173,7 @@ public class SplitLayout { mLayoutChangeListener.onSnappedToDismiss(true /* snappedToEnd */); break; default: - mDividePosition = snapTarget.position; - updateBounds(mDividePosition); - mLayoutChangeListener.onBoundsChanged(this); + flingDividePosition(currentPosition, snapTarget.position); break; } } @@ -189,6 +197,27 @@ public class SplitLayout { isLandscape ? DOCKED_LEFT : DOCKED_TOP /* dockSide */); } + private void flingDividePosition(int from, int to) { + ValueAnimator animator = ValueAnimator + .ofInt(from, to) + .setDuration(250); + animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + animator.addUpdateListener( + animation -> updateDivideBounds((int) animation.getAnimatedValue())); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setDividePosition(to); + } + + @Override + public void onAnimationCancel(Animator animation) { + setDividePosition(to); + } + }); + animator.start(); + } + private static boolean isLandscape(Rect bounds) { return bounds.width() > bounds.height(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index d65ad62cdbbb..a944e3bc50cf 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -63,6 +63,16 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { private String mStartOneHandedDescription; private String mStopOneHandedDescription; + private enum ONE_HANDED_TRIGGER_STATE { + UNSET, ENTERING, EXITING + } + /** + * Current One-Handed trigger state. + * Note: This is a dynamic state, whenever last state has been confirmed + * (i.e. onStartFinished() or onStopFinished()), the state should be set "UNSET" at final. + */ + private ONE_HANDED_TRIGGER_STATE mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET; + /** * Container of the tutorial panel showing at outside region when one handed starting */ @@ -74,6 +84,21 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { public void onTutorialAnimationUpdate(int offset) { mUpdateHandler.post(() -> onAnimationUpdate(offset)); } + + @Override + public void onOneHandedAnimationStart( + OneHandedAnimationController.OneHandedTransitionAnimator animator) { + mUpdateHandler.post(() -> { + final Rect startValue = (Rect) animator.getStartValue(); + if (mTriggerState == ONE_HANDED_TRIGGER_STATE.UNSET) { + mTriggerState = (startValue.top == 0) + ? ONE_HANDED_TRIGGER_STATE.ENTERING : ONE_HANDED_TRIGGER_STATE.EXITING; + if (mCanShowTutorial && mTriggerState == ONE_HANDED_TRIGGER_STATE.ENTERING) { + createTutorialTarget(); + } + } + }); + } }; public OneHandedTutorialHandler(Context context) { @@ -100,9 +125,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { R.string.accessibility_action_start_one_handed); mStopOneHandedDescription = context.getResources().getString( R.string.accessibility_action_stop_one_handed); - if (mCanShowTutorial) { - createOrUpdateTutorialTarget(); - } } @Override @@ -111,6 +133,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { updateFinished(View.VISIBLE, 0f); updateTutorialCount(); announcementForScreenReader(true); + mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET; }); } @@ -119,6 +142,8 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { mUpdateHandler.post(() -> { updateFinished(View.INVISIBLE, -mTargetViewContainer.getHeight()); announcementForScreenReader(false); + removeTutorialFromWindowManager(); + mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET; }); } @@ -126,7 +151,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { if (!canShowTutorial()) { return; } - mTargetViewContainer.setVisibility(visible); mTargetViewContainer.setTranslationY(finalPosition); } @@ -155,24 +179,23 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { * Adds the tutorial target view to the WindowManager and update its layout, so it's ready * to be animated in. */ - private void createOrUpdateTutorialTarget() { - mUpdateHandler.post(() -> { - if (!mTargetViewContainer.isAttachedToWindow()) { - mTargetViewContainer.setVisibility(View.INVISIBLE); - - try { - mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams()); - } catch (IllegalStateException e) { - // This shouldn't happen, but if the target is already added, just update its - // layout params. - mWindowManager.updateViewLayout( - mTargetViewContainer, getTutorialTargetLayoutParams()); - } - } else { - mWindowManager.updateViewLayout(mTargetViewContainer, - getTutorialTargetLayoutParams()); + private void createTutorialTarget() { + if (!mTargetViewContainer.isAttachedToWindow()) { + try { + mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams()); + } catch (IllegalStateException e) { + // This shouldn't happen, but if the target is already added, just update its + // layout params. + mWindowManager.updateViewLayout( + mTargetViewContainer, getTutorialTargetLayoutParams()); } - }); + } + } + + private void removeTutorialFromWindowManager() { + if (mTargetViewContainer.isAttachedToWindow()) { + mWindowManager.removeViewImmediate(mTargetViewContainer); + } } OneHandedAnimationCallback getAnimationCallback() { @@ -193,7 +216,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; lp.setFitInsetsTypes(0 /* types */); lp.setTitle("one-handed-tutorial-overlay"); - return lp; } @@ -206,10 +228,12 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { private boolean canShowTutorial() { if (!mCanShowTutorial) { + // Since canSHowTutorial() will be called in onAnimationUpdate() and we still need to + // hide Tutorial text in the period of continuously onAnimationUpdate() API call, + // so we have to hide mTargetViewContainer here. mTargetViewContainer.setVisibility(View.GONE); return false; } - return true; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java index eb82357f2dea..71710af4ffb5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java @@ -26,6 +26,7 @@ import android.annotation.Nullable; import android.graphics.Rect; import android.os.Handler; import android.util.Slog; +import android.view.Choreographer; import android.view.SurfaceControl; import android.window.TaskOrganizer; import android.window.WindowContainerToken; @@ -338,6 +339,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor SurfaceControl.Transaction t = mTransactionPool.acquire(); float value = (float) animation.getAnimatedValue(); onProgress(value, t); + t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId()); t.apply(); mTransactionPool.release(t); }); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java index c6496ad6246f..ba071666b5aa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.RemoteException; import android.util.AttributeSet; import android.util.Slog; +import android.view.Choreographer; import android.view.Display; import android.view.MotionEvent; import android.view.PointerIcon; @@ -1108,6 +1109,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, } resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect, mOtherTaskRect); if (ownTransaction) { + t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId()); t.apply(); mTiles.releaseTransaction(t); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java index 34f772faf9a9..11bf4ff2fd35 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TaskViewTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -96,8 +97,8 @@ public class TaskViewTest extends ShellTestCase { return null; }).when(mExecutor).execute(any()); + when(mOrganizer.getExecutor()).thenReturn(mExecutor); mTaskView = new TaskView(mContext, mOrganizer); - mTaskView.setExecutor(mExecutor); mTaskView.setListener(mViewListener); } @@ -111,7 +112,6 @@ public class TaskViewTest extends ShellTestCase { @Test public void testSetPendingListener_throwsException() { TaskView taskView = new TaskView(mContext, mOrganizer); - mTaskView.setExecutor(mExecutor); taskView.setListener(mViewListener); try { taskView.setListener(mViewListener); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java index d87f4c60fad4..9fdd59bee176 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java @@ -69,24 +69,27 @@ public class SplitLayoutTests extends ShellTestCase { } @Test - public void testUpdateDividePosition() { - mSplitLayout.updateDividePosition(anyInt()); + public void testUpdateDivideBounds() { + mSplitLayout.updateDivideBounds(anyInt()); verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class)); } @Test - public void testSetSnapTarget() { - DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0, + @UiThreadTest + public void testSnapToTarget() { + DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */, DividerSnapAlgorithm.SnapTarget.FLAG_NONE); - mSplitLayout.setSnapTarget(snapTarget); - verify(mLayoutChangeListener).onBoundsChanged(any(SplitLayout.class)); + mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget); + verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class)); // verify it callbacks properly when the snap target indicates dismissing split. - snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START); - mSplitLayout.setSnapTarget(snapTarget); + snapTarget = getSnapTarget(0 /* position */, + DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START); + mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget); verify(mLayoutChangeListener).onSnappedToDismiss(eq(false)); - snapTarget = getSnapTarget(0, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END); - mSplitLayout.setSnapTarget(snapTarget); + snapTarget = getSnapTarget(0 /* position */, + DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_END); + mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget); verify(mLayoutChangeListener).onSnappedToDismiss(eq(true)); } diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp index a2964d6627a1..10c80774fd16 100644 --- a/libs/hwui/jni/Typeface.cpp +++ b/libs/hwui/jni/Typeface.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_VIEW #include "FontUtils.h" #include "GraphicsJNI.h" #include "fonts/Font.h" @@ -25,8 +26,13 @@ #include <minikin/FontCollection.h> #include <minikin/FontFamily.h> #include <minikin/SystemFonts.h> +#include <utils/TraceUtils.h> + +#include <mutex> +#include <unordered_map> using namespace android; +using android::uirenderer::TraceUtils; static inline Typeface* toTypeface(jlong ptr) { return reinterpret_cast<Typeface*>(ptr); @@ -149,6 +155,20 @@ static void Typeface_registerGenericFamily(JNIEnv *env, jobject, jstring familyN toTypeface(ptr)->fFontCollection); } +static sk_sp<SkData> makeSkDataCached(const std::string& path) { + // We don't clear cache as Typeface objects created by Typeface_readTypefaces() will be stored + // in a static field and will not be garbage collected. + static std::unordered_map<std::string, sk_sp<SkData>> cache; + static std::mutex mutex; + ALOG_ASSERT(!path.empty()); + std::lock_guard lock{mutex}; + sk_sp<SkData>& entry = cache[path]; + if (entry.get() == nullptr) { + entry = SkData::MakeFromFileName(path.c_str()); + } + return entry; +} + static std::function<std::shared_ptr<minikin::MinikinFont>()> readMinikinFontSkia( minikin::BufferReader* reader) { std::string_view fontPath = reader->readString(); @@ -158,8 +178,9 @@ static std::function<std::shared_ptr<minikin::MinikinFont>()> readMinikinFontSki std::tie(axesPtr, axesCount) = reader->readArray<minikin::FontVariation>(); return [fontPath, fontIndex, axesPtr, axesCount]() -> std::shared_ptr<minikin::MinikinFont> { std::string path(fontPath.data(), fontPath.size()); - sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str()); - if (data == nullptr) { + ATRACE_FORMAT("Loading font %s", path.c_str()); + sk_sp<SkData> data = makeSkDataCached(path); + if (data.get() == nullptr) { // This may happen if: // 1. When the process failed to open the file (e.g. invalid path or permission). // 2. When the process failed to map the file (e.g. hitting max_map_count limit). |