Merging ub-launcher3-master, build 5211209
Test: manual Bug: 111698021 Bug: 111699315 Bug: 111850268 Bug: 111939693 Bug: 117532945 Bug: 118118435 Bug: 118846684 Bug: 119884907 Bug: 120255489 Bug: 120505990 Bug: 120638555 Bug: 120736782 Bug: 120901833 Bug: 120997004 Bug: 121044483 Bug: 121048571 Bug: 121362965 Bug: 121414492 Change-Id: I9f6552a84d981595c9a6105413cd04177725b16d
This commit is contained in:
@@ -204,7 +204,15 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
mLauncher.getStateManager().setCurrentAnimation(anim);
|
||||
|
||||
Rect windowTargetBounds = getWindowTargetBounds(targetCompats);
|
||||
playIconAnimators(anim, v, windowTargetBounds);
|
||||
boolean isAllOpeningTargetTrs = true;
|
||||
for (int i = 0; i < targetCompats.length; i++) {
|
||||
RemoteAnimationTargetCompat target = targetCompats[i];
|
||||
if (target.mode == MODE_OPENING) {
|
||||
isAllOpeningTargetTrs &= target.isTranslucent;
|
||||
}
|
||||
if (!isAllOpeningTargetTrs) break;
|
||||
}
|
||||
playIconAnimators(anim, v, windowTargetBounds, !isAllOpeningTargetTrs);
|
||||
if (launcherClosing) {
|
||||
Pair<AnimatorSet, Runnable> launcherContentAnimator =
|
||||
getLauncherContentAnimator(true /* isAppOpening */);
|
||||
@@ -432,7 +440,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
/**
|
||||
* Animators for the "floating view" of the view used to launch the target.
|
||||
*/
|
||||
private void playIconAnimators(AnimatorSet appOpenAnimator, View v, Rect windowTargetBounds) {
|
||||
private void playIconAnimators(AnimatorSet appOpenAnimator, View v, Rect windowTargetBounds,
|
||||
boolean toggleVisibility) {
|
||||
final boolean isBubbleTextView = v instanceof BubbleTextView;
|
||||
mFloatingView = new View(mLauncher);
|
||||
if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) {
|
||||
@@ -485,7 +494,9 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
|
||||
// Swap the two views in place.
|
||||
((ViewGroup) mDragLayer.getParent()).addView(mFloatingView);
|
||||
v.setVisibility(View.INVISIBLE);
|
||||
if (toggleVisibility) {
|
||||
v.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
int[] dragLayerBounds = new int[2];
|
||||
mDragLayer.getLocationOnScreen(dragLayerBounds);
|
||||
|
||||
@@ -45,7 +45,6 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
@@ -194,7 +193,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
int topMargin = context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
|
||||
int paddingTop = targetRect.rect.top - topMargin - dp.getInsets().top;
|
||||
int paddingBottom = dp.availableHeightPx + dp.getInsets().top - targetRect.rect.bottom;
|
||||
int paddingBottom = dp.heightPx - dp.getInsets().bottom - targetRect.rect.bottom;
|
||||
|
||||
return FastOverviewState.OVERVIEW_TRANSLATION_FACTOR * (paddingBottom - paddingTop);
|
||||
}
|
||||
|
||||
@@ -343,14 +343,15 @@ public class OverviewCommandHelper {
|
||||
clipHelper.updateTargetRect(targetRect);
|
||||
clipHelper.prepareAnimation(false /* isOpening */);
|
||||
|
||||
SyncRtSurfaceTransactionApplierCompat syncTransactionApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(rootView);
|
||||
ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams()
|
||||
.setSyncTransactionApplier(new SyncRtSurfaceTransactionApplierCompat(rootView));
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
|
||||
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
|
||||
valueAnimator.addUpdateListener((v) ->
|
||||
clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue(),
|
||||
syncTransactionApplier));
|
||||
valueAnimator.addUpdateListener((v) -> {
|
||||
params.setProgress((float) v.getAnimatedValue());
|
||||
clipHelper.applyTransform(targetSet, params);
|
||||
});
|
||||
|
||||
if (targetSet.isAnimatingHome()) {
|
||||
// If we are animating home, fade in the opening targets
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.launcher3.anim.Interpolators.ACCEL;
|
||||
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
|
||||
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASK_STABILIZER;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -126,11 +127,13 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
if (mIsQuickSwitch) {
|
||||
mShouldSwitchToNext = true;
|
||||
mPrevProgressDelta = 0;
|
||||
if (mRecentsView.getTaskViewCount() > 0) {
|
||||
mRecentsView.getTaskViewAt(0).setFullscreen(true);
|
||||
TaskView runningTaskView = mRecentsView.getRunningTaskView();
|
||||
TaskView nextTaskView = mRecentsView.getNextTaskView();
|
||||
if (runningTaskView != null) {
|
||||
runningTaskView.setFullscreenProgress(1);
|
||||
}
|
||||
if (mRecentsView.getTaskViewCount() > 1) {
|
||||
mRecentsView.getTaskViewAt(1).setFullscreen(true);
|
||||
if (nextTaskView != null) {
|
||||
nextTaskView.setFullscreenProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,11 +164,13 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
mWaitingForTaskLaunch = false;
|
||||
if (mIsQuickSwitch) {
|
||||
mIsQuickSwitch = false;
|
||||
if (mRecentsView.getTaskViewCount() > 0) {
|
||||
mRecentsView.getTaskViewAt(0).setFullscreen(false);
|
||||
TaskView runningTaskView = mRecentsView.getRunningTaskView();
|
||||
TaskView nextTaskView = mRecentsView.getNextTaskView();
|
||||
if (runningTaskView != null) {
|
||||
runningTaskView.setFullscreenProgress(0);
|
||||
}
|
||||
if (mRecentsView.getTaskViewCount() > 1) {
|
||||
mRecentsView.getTaskViewAt(1).setFullscreen(false);
|
||||
if (nextTaskView != null) {
|
||||
nextTaskView.setFullscreenProgress(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,12 +272,12 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
|
||||
public void onQuickScrubProgress(float progress) {
|
||||
if (mIsQuickSwitch) {
|
||||
TaskView currentPage = mRecentsView.getTaskViewAt(0);
|
||||
TaskView nextPage = mRecentsView.getTaskViewAt(1);
|
||||
TaskView currentPage = mRecentsView.getRunningTaskView();
|
||||
TaskView nextPage = mRecentsView.getNextTaskView();
|
||||
if (currentPage == null || nextPage == null) {
|
||||
return;
|
||||
}
|
||||
if (!mFinishedTransitionToQuickScrub) {
|
||||
if (!mFinishedTransitionToQuickScrub || mStartProgress <= 0) {
|
||||
mStartProgress = mEndProgress = progress;
|
||||
} else {
|
||||
float progressDelta = progress - mEndProgress;
|
||||
@@ -285,16 +290,20 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
}
|
||||
mPrevPrevProgressDelta = mPrevProgressDelta;
|
||||
mPrevProgressDelta = progressDelta;
|
||||
float scrollDiff = nextPage.getWidth() + mRecentsView.getPageSpacing();
|
||||
int scrollDir = mRecentsView.isRtl() ? -1 : 1;
|
||||
int linearScrollDiff = (int) (progress * scrollDiff * scrollDir);
|
||||
float accelScrollDiff = ACCEL.getInterpolation(progress) * scrollDiff * scrollDir;
|
||||
int startScroll = mRecentsView.getScrollForPage(
|
||||
mRecentsView.indexOfChild(currentPage));
|
||||
int scrollDiff = mRecentsView.getScrollForPage(mRecentsView.indexOfChild(nextPage))
|
||||
- startScroll;
|
||||
|
||||
int linearScrollDiff = (int) (progress * scrollDiff);
|
||||
currentPage.setZoomScale(1 - DEACCEL_3.getInterpolation(progress)
|
||||
* TaskView.EDGE_SCALE_DOWN_FACTOR);
|
||||
currentPage.setTranslationX(linearScrollDiff + accelScrollDiff);
|
||||
if (!ENABLE_TASK_STABILIZER.get()) {
|
||||
float accelScrollDiff = ACCEL.getInterpolation(progress) * scrollDiff;
|
||||
currentPage.setTranslationX(linearScrollDiff + accelScrollDiff);
|
||||
}
|
||||
nextPage.setTranslationZ(1);
|
||||
nextPage.setTranslationY(currentPage.getTranslationY());
|
||||
int startScroll = mRecentsView.isRtl() ? mRecentsView.getMaxScrollX() : 0;
|
||||
mRecentsView.setScrollX(startScroll + linearScrollDiff);
|
||||
}
|
||||
return;
|
||||
@@ -354,9 +363,16 @@ public class QuickScrubController implements OnAlarmListener {
|
||||
: mStartedFromHome
|
||||
? QUICK_SCRUB_FROM_HOME_START_DURATION
|
||||
: QUICK_SCRUB_FROM_APP_START_DURATION;
|
||||
int pageToGoTo = mStartedFromHome || mIsQuickSwitch
|
||||
? 0
|
||||
: mRecentsView.getNextPage() + 1;
|
||||
final int pageToGoTo;
|
||||
if (mStartedFromHome) {
|
||||
pageToGoTo = 0;
|
||||
} else if (mIsQuickSwitch) {
|
||||
TaskView tv = mRecentsView.getRunningTaskView();
|
||||
pageToGoTo = tv != null ? mRecentsView.indexOfChild(tv)
|
||||
: mRecentsView.getNextPage();
|
||||
} else {
|
||||
pageToGoTo = mRecentsView.getNextPage() + 1;
|
||||
}
|
||||
goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */,
|
||||
QUICK_SCRUB_START_INTERPOLATOR);
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package com.android.quickstep;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.util.SparseBooleanArray;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
@@ -36,16 +38,20 @@ import java.util.function.Consumer;
|
||||
/**
|
||||
* Manages the recent task list from the system, caching it as necessary.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class RecentTasksList extends TaskStackChangeListener {
|
||||
|
||||
private final KeyguardManagerCompat mKeyguardManager;
|
||||
private final MainThreadExecutor mMainThreadExecutor;
|
||||
private final BackgroundExecutor mBgThreadExecutor;
|
||||
private final TaskListStabilizer mStabilizer = new TaskListStabilizer();
|
||||
|
||||
// The list change id, increments as the task list changes in the system
|
||||
private int mChangeId;
|
||||
// The last change id when the list was last loaded completely, must be <= the list change id
|
||||
private int mLastLoadedId;
|
||||
// The last change id was loaded with keysOnly = true
|
||||
private boolean mLastLoadHadKeysOnly;
|
||||
|
||||
ArrayList<Task> mTasks = new ArrayList<>();
|
||||
|
||||
@@ -57,41 +63,43 @@ public class RecentTasksList extends TaskStackChangeListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously fetches the list of recent tasks.
|
||||
* Fetches the task keys skipping any local cache.
|
||||
*/
|
||||
public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) {
|
||||
// Kick off task loading in the background
|
||||
mBgThreadExecutor.submit(() -> {
|
||||
ArrayList<Task> tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */);
|
||||
mMainThreadExecutor.execute(() -> callback.accept(tasks));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously fetches the list of recent tasks, reusing cached list if available.
|
||||
*
|
||||
* @param numTasks The maximum number of tasks to fetch
|
||||
* @param loadKeysOnly Whether to load other associated task data, or just the key
|
||||
* @param callback The callback to receive the list of recent tasks
|
||||
* @return The change id of the current task list
|
||||
*/
|
||||
public synchronized int getTasks(int numTasks, boolean loadKeysOnly,
|
||||
Consumer<ArrayList<Task>> callback) {
|
||||
public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
|
||||
final int requestLoadId = mChangeId;
|
||||
final int numLoadTasks = numTasks > 0
|
||||
? numTasks
|
||||
: Integer.MAX_VALUE;
|
||||
Runnable resultCallback = callback == null
|
||||
? () -> { }
|
||||
: () -> callback.accept(mStabilizer.reorder(mTasks));
|
||||
|
||||
if (mLastLoadedId == mChangeId) {
|
||||
if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
|
||||
// The list is up to date, callback with the same list
|
||||
mMainThreadExecutor.execute(() -> {
|
||||
if (callback != null) {
|
||||
callback.accept(mTasks);
|
||||
}
|
||||
});
|
||||
mMainThreadExecutor.execute(resultCallback);
|
||||
}
|
||||
|
||||
// Kick off task loading in the background
|
||||
mBgThreadExecutor.submit(() -> {
|
||||
ArrayList<Task> tasks = loadTasksInBackground(numLoadTasks,
|
||||
loadKeysOnly);
|
||||
ArrayList<Task> tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly);
|
||||
|
||||
mMainThreadExecutor.execute(() -> {
|
||||
mTasks = tasks;
|
||||
mLastLoadedId = requestLoadId;
|
||||
|
||||
if (callback != null) {
|
||||
callback.accept(tasks);
|
||||
}
|
||||
mLastLoadHadKeysOnly = loadKeysOnly;
|
||||
resultCallback.run();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
* @return the request id associated with this call.
|
||||
*/
|
||||
public int getTasks(Consumer<ArrayList<Task>> callback) {
|
||||
return mTaskList.getTasks(-1, false /* loadKeysOnly */, callback);
|
||||
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +124,7 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
* called on the UI thread.
|
||||
*/
|
||||
public void findTaskWithId(int taskId, Consumer<Task.TaskKey> callback) {
|
||||
mTaskList.getTasks(-1, true /* loadKeysOnly */, (tasks) -> {
|
||||
mTaskList.getTasks(true /* loadKeysOnly */, (tasks) -> {
|
||||
for (Task task : tasks) {
|
||||
if (task.key.id == taskId) {
|
||||
callback.accept(task.key);
|
||||
@@ -150,7 +150,7 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
|
||||
// Keep the cache up to date with the latest thumbnails
|
||||
int runningTaskId = RecentsModel.getRunningTaskId();
|
||||
mTaskList.getTasks(mThumbnailCache.getCacheSize(), true /* keysOnly */, (tasks) -> {
|
||||
mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> {
|
||||
for (Task task : tasks) {
|
||||
if (task.key.id == runningTaskId) {
|
||||
// Skip the running task, it's not going to have an up-to-date snapshot by the
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.quickstep;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASK_STABILIZER;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class TaskListStabilizer {
|
||||
|
||||
private static final long TASK_CACHE_TIMEOUT_MS = 5000;
|
||||
|
||||
private final SparseArray<Task> mTempMap = new SparseArray<>();
|
||||
private final IntArray mTempArray = new IntArray();
|
||||
private final IntSet mTempSet = new IntSet();
|
||||
|
||||
private final IntArray mLastStableOrder = new IntArray();
|
||||
private final IntSet mLastSet = new IntSet();
|
||||
private final IntArray mLastUnstableOrder = new IntArray();
|
||||
|
||||
private long mLastReorderTime;
|
||||
|
||||
public ArrayList<Task> reorder(ArrayList<Task> tasks) {
|
||||
if (!ENABLE_TASK_STABILIZER.get()) {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
// Create task id array
|
||||
int count = tasks.size();
|
||||
mTempArray.clear();
|
||||
mTempSet.clear();
|
||||
mTempMap.clear();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Task t = tasks.get(i);
|
||||
mTempMap.put(t.key.id, t);
|
||||
|
||||
mTempSet.add(t.key.id);
|
||||
mTempArray.add(t.key.id);
|
||||
}
|
||||
|
||||
if (mLastSet.equals(mTempSet) && isStabilizationQuickEnough()) {
|
||||
if (mLastStableOrder.equals(mTempArray)) {
|
||||
// Everything is same
|
||||
return tasks;
|
||||
}
|
||||
|
||||
if (!mLastUnstableOrder.equals(mTempArray)) {
|
||||
// Fast reordering, record the current time.
|
||||
mLastUnstableOrder.copyFrom(mTempArray);
|
||||
mLastReorderTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
// Reorder the tasks based on the last stable order.
|
||||
ArrayList<Task> sorted = new ArrayList<>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
sorted.add(mTempMap.get(mLastStableOrder.get(i)));
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
// Cache the data
|
||||
mLastStableOrder.copyFrom(mTempArray);
|
||||
mLastUnstableOrder.copyFrom(mTempArray);
|
||||
mLastSet.copyFrom(mTempSet);
|
||||
|
||||
mLastReorderTime = SystemClock.uptimeMillis();
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private boolean isStabilizationQuickEnough() {
|
||||
return (SystemClock.uptimeMillis() - mLastReorderTime) < TASK_CACHE_TIMEOUT_MS;
|
||||
}
|
||||
}
|
||||
@@ -145,8 +145,9 @@ public class TaskUtils {
|
||||
*/
|
||||
public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
|
||||
RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) {
|
||||
SyncRtSurfaceTransactionApplierCompat syncTransactionApplier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(v);
|
||||
ClipAnimationHelper.TransformParams params = new ClipAnimationHelper.TransformParams()
|
||||
.setSyncTransactionApplier(new SyncRtSurfaceTransactionApplierCompat(v));
|
||||
|
||||
final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
|
||||
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
@@ -174,8 +175,8 @@ public class TaskUtils {
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent,
|
||||
syncTransactionApplier);
|
||||
params.setProgress(1 - percent);
|
||||
RectF taskBounds = inOutHelper.applyTransform(mTargetSet, params);
|
||||
if (!skipViewChanges) {
|
||||
float scale = taskBounds.width() / mThumbnailRect.width();
|
||||
v.setScaleX(scale);
|
||||
|
||||
@@ -27,6 +27,7 @@ import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_FROM_APP_S
|
||||
import static com.android.quickstep.TouchConsumer.INTERACTION_NORMAL;
|
||||
import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
@@ -52,6 +53,7 @@ import android.view.animation.Interpolator;
|
||||
import androidx.annotation.AnyThread;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -176,6 +178,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
Math.min(1 / MIN_PROGRESS_FOR_OVERVIEW, 1 / (1 - MIN_PROGRESS_FOR_OVERVIEW));
|
||||
|
||||
private final ClipAnimationHelper mClipAnimationHelper;
|
||||
private final ClipAnimationHelper.TransformParams mTransformParams;
|
||||
|
||||
protected Runnable mGestureEndCallback;
|
||||
protected boolean mIsGoingToHome;
|
||||
@@ -256,6 +259,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer,
|
||||
this::createNewTouchProxyHandler);
|
||||
mClipAnimationHelper = new ClipAnimationHelper(context);
|
||||
mTransformParams = new ClipAnimationHelper.TransformParams();
|
||||
|
||||
initStateCallbacks();
|
||||
}
|
||||
@@ -584,11 +588,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
|
||||
RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
|
||||
if (controller != null) {
|
||||
|
||||
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, shift,
|
||||
Looper.myLooper() == mMainThreadHandler.getLooper()
|
||||
SyncRtSurfaceTransactionApplierCompat syncTransactionApplier
|
||||
= Looper.myLooper() == mMainThreadHandler.getLooper()
|
||||
? mSyncTransactionApplier
|
||||
: null);
|
||||
: null;
|
||||
mTransformParams.setProgress(shift).setSyncTransactionApplier(syncTransactionApplier);
|
||||
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
|
||||
mTransformParams);
|
||||
|
||||
boolean passedThreshold = shift > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold);
|
||||
@@ -615,6 +621,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
|
||||
}
|
||||
}
|
||||
// Update insets of the next previous task, as we might switch to it.
|
||||
TaskView nextTaskView = mRecentsView == null ? null : mRecentsView.getNextTaskView();
|
||||
if (mInteractionType == INTERACTION_NORMAL && nextTaskView != null) {
|
||||
nextTaskView.setFullscreenProgress(1 - mCurrentShift.value);
|
||||
}
|
||||
|
||||
if (mLauncherTransitionController == null || mLauncherTransitionController
|
||||
.getAnimationPlayer().isStarted()) {
|
||||
@@ -1018,10 +1029,17 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
|
||||
mRecentsView.animateUpRunningTaskIconScale();
|
||||
if (mQuickScrubController.isQuickSwitch()) {
|
||||
// Adjust the running task so that it is centered and fills the screen.
|
||||
TaskView runningTask = mRecentsView.getRunningTaskView();
|
||||
if (runningTask != null) {
|
||||
runningTask.setTranslationY(-mActivity.getResources().getDimension(
|
||||
R.dimen.task_thumbnail_half_top_margin) * 1f / mRecentsView.getScaleX());
|
||||
float insetHeight = mDp.heightPx - mDp.getInsets().top - mDp.getInsets().bottom;
|
||||
// Usually insetDiff will be 0, unless we allow apps to draw under the insets. In
|
||||
// that case (insetDiff != 0), we need to center in the system-specified available
|
||||
// height rather than launcher's inset height by adding half the insetDiff.
|
||||
float insetDiff = mDp.availableHeightPx - insetHeight;
|
||||
float topMargin = mActivity.getResources().getDimension(
|
||||
R.dimen.task_thumbnail_half_top_margin);
|
||||
runningTask.setTranslationY((insetDiff / 2 - topMargin) / mRecentsView.getScaleX());
|
||||
}
|
||||
}
|
||||
RecentsModel.INSTANCE.get(mContext).onOverviewShown(false, TAG);
|
||||
|
||||
@@ -151,14 +151,13 @@ public class ClipAnimationHelper {
|
||||
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
|
||||
}
|
||||
|
||||
public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress,
|
||||
@Nullable SyncRtSurfaceTransactionApplierCompat syncTransactionApplier) {
|
||||
public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params) {
|
||||
RectF currentRect;
|
||||
mTmpRectF.set(mTargetRect);
|
||||
Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
|
||||
float offsetYProgress = mOffsetYInterpolator.getInterpolation(progress);
|
||||
progress = mInterpolator.getInterpolation(progress);
|
||||
currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
|
||||
float offsetYProgress = mOffsetYInterpolator.getInterpolation(params.progress);
|
||||
float progress = mInterpolator.getInterpolation(params.progress);
|
||||
currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
|
||||
|
||||
synchronized (mTargetOffset) {
|
||||
// Stay lined up with the center of the target, since it moves for quick scrub.
|
||||
@@ -173,7 +172,7 @@ public class ClipAnimationHelper {
|
||||
mClipRectF.bottom =
|
||||
mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress);
|
||||
|
||||
SurfaceParams[] params = new SurfaceParams[targetSet.unfilteredApps.length];
|
||||
SurfaceParams[] surfaceParams = new SurfaceParams[targetSet.unfilteredApps.length];
|
||||
for (int i = 0; i < targetSet.unfilteredApps.length; i++) {
|
||||
RemoteAnimationTargetCompat app = targetSet.unfilteredApps[i];
|
||||
mTmpMatrix.setTranslate(app.position.x, app.position.y);
|
||||
@@ -206,10 +205,10 @@ public class ClipAnimationHelper {
|
||||
|
||||
// Since radius is in Surface space, but we draw the rounded corners in screen space, we
|
||||
// have to undo the scale.
|
||||
params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer,
|
||||
surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer,
|
||||
cornerRadius / scale);
|
||||
}
|
||||
applyParams(syncTransactionApplier, params);
|
||||
applySurfaceParams(params.syncTransactionApplier, surfaceParams);
|
||||
return currentRect;
|
||||
}
|
||||
|
||||
@@ -218,8 +217,8 @@ public class ClipAnimationHelper {
|
||||
return mCurrentRectWithInsets;
|
||||
}
|
||||
|
||||
private void applyParams(@Nullable SyncRtSurfaceTransactionApplierCompat syncTransactionApplier,
|
||||
SurfaceParams[] params) {
|
||||
private void applySurfaceParams(@Nullable SyncRtSurfaceTransactionApplierCompat
|
||||
syncTransactionApplier, SurfaceParams[] params) {
|
||||
if (syncTransactionApplier != null) {
|
||||
syncTransactionApplier.scheduleApply(params);
|
||||
} else {
|
||||
@@ -330,14 +329,14 @@ public class ClipAnimationHelper {
|
||||
canvas.concat(mTmpMatrix);
|
||||
canvas.translate(mTargetRect.left, mTargetRect.top);
|
||||
|
||||
float scale = mTargetRect.width() / mSourceRect.width();
|
||||
float insetProgress = (1 - progress);
|
||||
float scale = currentRect.width() / mTargetRect.width();
|
||||
ttv.drawOnCanvas(canvas,
|
||||
-mSourceWindowClipInsets.left * insetProgress,
|
||||
-mSourceWindowClipInsets.top * insetProgress,
|
||||
ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress,
|
||||
ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
|
||||
Utilities.mapRange(progress, mWindowCornerRadius / scale, ttv.getCornerRadius()));
|
||||
Utilities.mapRange(progress, mWindowCornerRadius * scale, ttv.getCornerRadius()));
|
||||
}
|
||||
|
||||
public RectF getTargetRect() {
|
||||
@@ -351,4 +350,25 @@ public class ClipAnimationHelper {
|
||||
public float getCurrentCornerRadius() {
|
||||
return mCurrentCornerRadius;
|
||||
}
|
||||
|
||||
public static class TransformParams {
|
||||
float progress;
|
||||
SyncRtSurfaceTransactionApplierCompat syncTransactionApplier;
|
||||
|
||||
public TransformParams() {
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
public TransformParams setProgress(float progress) {
|
||||
this.progress = progress;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TransformParams setSyncTransactionApplier(
|
||||
SyncRtSurfaceTransactionApplierCompat applier) {
|
||||
this.syncTransactionApplier = applier;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
|
||||
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
|
||||
import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.LayoutTransition;
|
||||
@@ -60,6 +61,7 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.ListView;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Insettable;
|
||||
@@ -482,6 +484,11 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
final TaskView taskView = (TaskView) getChildAt(pageIndex);
|
||||
taskView.bind(task);
|
||||
}
|
||||
TaskView runningTaskView = getRunningTaskView();
|
||||
if (runningTaskView != null) {
|
||||
setCurrentPage(indexOfChild(runningTaskView));
|
||||
}
|
||||
|
||||
if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreRestTaskView) {
|
||||
// If the taskView mapping is changing, do not preserve the visuals. Since we are
|
||||
// mostly preserving the first task, and new taskViews are added to the end, it should
|
||||
@@ -545,8 +552,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
// Keep this logic in sync with ActivityControlHelper.getTranslationYForQuickScrub.
|
||||
mTempRect.top -= mTaskTopMargin;
|
||||
setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
|
||||
dp.availableWidthPx + mInsets.left - mTempRect.right,
|
||||
dp.availableHeightPx + mInsets.top - mTempRect.bottom);
|
||||
dp.widthPx - mInsets.right - mTempRect.right,
|
||||
dp.heightPx - mInsets.bottom - mTempRect.bottom);
|
||||
}
|
||||
|
||||
protected abstract void getTaskSize(DeviceProfile dp, Rect outRect);
|
||||
@@ -749,7 +756,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
setRunningTaskIconScaledDown(runningTaskIconScaledDown);
|
||||
setRunningTaskHidden(runningTaskTileHidden);
|
||||
|
||||
setCurrentPage(0);
|
||||
TaskView tv = getRunningTaskView();
|
||||
setCurrentPage(tv == null ? 0 : indexOfChild(tv));
|
||||
|
||||
// Load the tasks (if the loading is already
|
||||
mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
|
||||
@@ -760,14 +768,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
if (runningTaskView == null) {
|
||||
// Launch the first task
|
||||
if (getTaskViewCount() > 0) {
|
||||
((TaskView) getChildAt(0)).launchTask(true /* animate */);
|
||||
getTaskViewAt(0).launchTask(true /* animate */);
|
||||
}
|
||||
} else {
|
||||
// Get the next launch task
|
||||
int runningTaskIndex = indexOfChild(runningTaskView);
|
||||
int nextTaskIndex = Math.max(0, Math.min(getTaskViewCount() - 1, runningTaskIndex + 1));
|
||||
if (nextTaskIndex < getTaskViewCount()) {
|
||||
((TaskView) getChildAt(nextTaskIndex)).launchTask(true /* animate */);
|
||||
TaskView nextTaskView = getNextTaskView();
|
||||
if (nextTaskView != null) {
|
||||
nextTaskView.launchTask(true /* animate */);
|
||||
} else {
|
||||
runningTaskView.launchTask(true /* animate */);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1140,6 +1148,19 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
child.setAlpha(mContentAlpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The most recent task that is older than the currently running task. If there is
|
||||
* currently no running task or there is no task older than it, then return null.
|
||||
*/
|
||||
@Nullable
|
||||
public TaskView getNextTaskView() {
|
||||
TaskView runningTaskView = getRunningTaskView();
|
||||
if (runningTaskView == null) {
|
||||
return null;
|
||||
}
|
||||
return getTaskViewAt(indexOfChild(runningTaskView) + 1);
|
||||
}
|
||||
|
||||
public TaskView getTaskViewAt(int index) {
|
||||
View child = getChildAt(index);
|
||||
return child == mClearAllButton ? null : (TaskView) child;
|
||||
@@ -1261,12 +1282,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
toScale, toTranslationY);
|
||||
scaleAndTranslation[1] = -scaleAndTranslation[1];
|
||||
anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
|
||||
anim.play(ObjectAnimator.ofFloat(adjacentTask, TaskView.FULLSCREEN_PROGRESS, 1));
|
||||
}
|
||||
if (taskIndex + 1 < getTaskViewCount()) {
|
||||
TaskView adjacentTask = getTaskViewAt(taskIndex + 1);
|
||||
float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask,
|
||||
toScale, toTranslationY);
|
||||
anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
|
||||
anim.play(ObjectAnimator.ofFloat(adjacentTask, TaskView.FULLSCREEN_PROGRESS, 1));
|
||||
}
|
||||
} else {
|
||||
// We are launching an adjacent task, so parallax the center and other adjacent task.
|
||||
|
||||
@@ -81,6 +81,7 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
private float mClipBottom = -1;
|
||||
private Rect mScaledInsets = new Rect();
|
||||
private boolean mIsRotated;
|
||||
|
||||
private Task mTask;
|
||||
private ThumbnailData mThumbnailData;
|
||||
@@ -144,7 +145,7 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
/**
|
||||
* Sets the alpha of the dim layer on top of this view.
|
||||
*
|
||||
* <p>
|
||||
* If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be black.
|
||||
*/
|
||||
public void setDimAlpha(float dimAlpha) {
|
||||
@@ -188,13 +189,18 @@ public class TaskThumbnailView extends View {
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (((TaskView) getParent()).isFullscreen()) {
|
||||
float fullscreenProgress = ((TaskView) getParent()).getFullscreenProgress();
|
||||
if (mIsRotated) {
|
||||
// Don't show insets in the wrong orientation.
|
||||
fullscreenProgress = 0;
|
||||
}
|
||||
if (fullscreenProgress > 0) {
|
||||
// Draw the insets if we're being drawn fullscreen (we do this for quick switch).
|
||||
drawOnCanvas(canvas,
|
||||
-mScaledInsets.left,
|
||||
-mScaledInsets.top,
|
||||
getMeasuredWidth() + mScaledInsets.right,
|
||||
getMeasuredHeight() + mScaledInsets.bottom,
|
||||
-mScaledInsets.left * fullscreenProgress,
|
||||
-mScaledInsets.top * fullscreenProgress,
|
||||
getMeasuredWidth() + mScaledInsets.right * fullscreenProgress,
|
||||
getMeasuredHeight() + mScaledInsets.bottom * fullscreenProgress,
|
||||
mCornerRadius);
|
||||
} else {
|
||||
drawOnCanvas(canvas, 0, 0, getMeasuredWidth(), getMeasuredHeight(), mCornerRadius);
|
||||
@@ -241,11 +247,11 @@ public class TaskThumbnailView extends View {
|
||||
}
|
||||
|
||||
private void updateThumbnailMatrix() {
|
||||
boolean rotate = false;
|
||||
mIsRotated = false;
|
||||
mClipBottom = -1;
|
||||
if (mBitmapShader != null && mThumbnailData != null) {
|
||||
float scale = mThumbnailData.scale;
|
||||
Rect thumbnailInsets = mThumbnailData.insets;
|
||||
Rect thumbnailInsets = mThumbnailData.insets;
|
||||
final float thumbnailWidth = mThumbnailData.thumbnail.getWidth() -
|
||||
(thumbnailInsets.left + thumbnailInsets.right) * scale;
|
||||
final float thumbnailHeight = mThumbnailData.thumbnail.getHeight() -
|
||||
@@ -262,12 +268,12 @@ public class TaskThumbnailView extends View {
|
||||
final Configuration configuration =
|
||||
getContext().getResources().getConfiguration();
|
||||
// Rotate the screenshot if not in multi-window mode
|
||||
rotate = FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION &&
|
||||
mIsRotated = FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION &&
|
||||
configuration.orientation != mThumbnailData.orientation &&
|
||||
!mActivity.isInMultiWindowModeCompat() &&
|
||||
mThumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
|
||||
// Scale the screenshot to always fit the width of the card.
|
||||
thumbnailScale = rotate
|
||||
thumbnailScale = mIsRotated
|
||||
? getMeasuredWidth() / thumbnailHeight
|
||||
: getMeasuredWidth() / thumbnailWidth;
|
||||
}
|
||||
@@ -275,7 +281,7 @@ public class TaskThumbnailView extends View {
|
||||
mScaledInsets.set(thumbnailInsets);
|
||||
Utilities.scaleRect(mScaledInsets, thumbnailScale);
|
||||
|
||||
if (rotate) {
|
||||
if (mIsRotated) {
|
||||
int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1;
|
||||
mMatrix.setRotate(90 * rotationDir);
|
||||
int newLeftInset = rotationDir == 1 ? thumbnailInsets.bottom : thumbnailInsets.top;
|
||||
@@ -299,7 +305,7 @@ public class TaskThumbnailView extends View {
|
||||
mMatrix.postScale(thumbnailScale, thumbnailScale);
|
||||
mBitmapShader.setLocalMatrix(mMatrix);
|
||||
|
||||
float bitmapHeight = Math.max((rotate ? thumbnailWidth : thumbnailHeight)
|
||||
float bitmapHeight = Math.max((mIsRotated ? thumbnailWidth : thumbnailHeight)
|
||||
* thumbnailScale, 0);
|
||||
if (Math.round(bitmapHeight) < getMeasuredHeight()) {
|
||||
mClipBottom = bitmapHeight;
|
||||
@@ -307,7 +313,7 @@ public class TaskThumbnailView extends View {
|
||||
mPaint.setShader(mBitmapShader);
|
||||
}
|
||||
|
||||
if (rotate) {
|
||||
if (mIsRotated) {
|
||||
// The overlay doesn't really work when the screenshot is rotated, so don't add it.
|
||||
mOverlay.reset();
|
||||
} else {
|
||||
|
||||
@@ -101,6 +101,19 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
}
|
||||
};
|
||||
|
||||
public static final FloatProperty<TaskView> FULLSCREEN_PROGRESS =
|
||||
new FloatProperty<TaskView>("fullscreenProgress") {
|
||||
@Override
|
||||
public void setValue(TaskView taskView, float v) {
|
||||
taskView.setFullscreenProgress(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(TaskView taskView) {
|
||||
return taskView.mFullscreenProgress;
|
||||
}
|
||||
};
|
||||
|
||||
private static final FloatProperty<TaskView> FOCUS_TRANSITION =
|
||||
new FloatProperty<TaskView>("focusTransition") {
|
||||
@Override
|
||||
@@ -139,7 +152,7 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
private DigitalWellBeingToast mDigitalWellBeingToast;
|
||||
private float mCurveScale;
|
||||
private float mZoomScale;
|
||||
private boolean mIsFullscreen;
|
||||
private float mFullscreenProgress;
|
||||
|
||||
private Animator mIconAndDimAnimator;
|
||||
private float mFocusTransitionProgress = 1;
|
||||
@@ -340,6 +353,10 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
setTranslationZ(0);
|
||||
setAlpha(1f);
|
||||
setIconScaleAndDim(1);
|
||||
if (!getRecentsView().getQuickScrubController().isQuickSwitch()) {
|
||||
// Reset full screen progress unless we are doing back to back quick switch.
|
||||
setFullscreenProgress(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -498,15 +515,21 @@ public class TaskView extends FrameLayout implements PageCallbacks {
|
||||
|
||||
/**
|
||||
* Hides the icon and shows insets when this TaskView is about to be shown fullscreen.
|
||||
* @param progress: 0 = show icon and no insets; 1 = don't show icon and show full insets.
|
||||
*/
|
||||
public void setFullscreen(boolean isFullscreen) {
|
||||
mIsFullscreen = isFullscreen;
|
||||
mIconView.setVisibility(mIsFullscreen ? INVISIBLE : VISIBLE);
|
||||
setClipChildren(!mIsFullscreen);
|
||||
setClipToPadding(!mIsFullscreen);
|
||||
public void setFullscreenProgress(float progress) {
|
||||
if (progress == mFullscreenProgress) {
|
||||
return;
|
||||
}
|
||||
mFullscreenProgress = progress;
|
||||
boolean isFullscreen = mFullscreenProgress > 0;
|
||||
mIconView.setVisibility(isFullscreen ? INVISIBLE : VISIBLE);
|
||||
setClipChildren(!isFullscreen);
|
||||
setClipToPadding(!isFullscreen);
|
||||
getThumbnail().invalidate();
|
||||
}
|
||||
|
||||
public boolean isFullscreen() {
|
||||
return mIsFullscreen;
|
||||
public float getFullscreenProgress() {
|
||||
return mFullscreenProgress;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user