Remove dead code #6: Delete old recents implementation
Change-Id: I93b1257563d6352a54141bd4c90d2d4587782fd2
This commit is contained in:
@ -173,18 +173,6 @@
|
||||
android:excludeFromRecents="true">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".recent.RecentsActivity"
|
||||
android:label="@string/accessibility_desc_recent_apps"
|
||||
android:theme="@style/RecentsStyle"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:resumeWhilePausing="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.systemui.TOGGLE_RECENTS" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver
|
||||
android:name=".recent.RecentsPreloadReceiver"
|
||||
android:exported="false">
|
||||
|
@ -41,7 +41,7 @@ public class SystemUIApplication extends Application {
|
||||
*/
|
||||
private final Class<?>[] SERVICES = new Class[] {
|
||||
com.android.systemui.keyguard.KeyguardViewMediator.class,
|
||||
com.android.systemui.recent.Recents.class,
|
||||
com.android.systemui.recents.Recents.class,
|
||||
com.android.systemui.volume.VolumeUI.class,
|
||||
com.android.systemui.statusbar.SystemBars.class,
|
||||
com.android.systemui.usb.StorageNotification.class,
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.systemui.recent;
|
||||
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
|
||||
public class ColorDrawableWithDimensions extends ColorDrawable {
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
public ColorDrawableWithDimensions(int color, int width, int height) {
|
||||
super(color);
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
public class Constants {
|
||||
static final int MAX_ESCAPE_ANIMATION_DURATION = 500; // in ms
|
||||
static final int SNAP_BACK_DURATION = 250; // in ms
|
||||
static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it in dp/s
|
||||
public static float ALPHA_FADE_START = 0.8f; // fraction of thumbnail width where fade starts
|
||||
static final float ALPHA_FADE_END = 0.5f; // fraction of thumbnail width beyond which alpha->0
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
public class FadedEdgeDrawHelper {
|
||||
public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
|
||||
public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
|
||||
private View mScrollView;
|
||||
|
||||
private int mFadingEdgeLength;
|
||||
private boolean mIsVertical;
|
||||
private boolean mSoftwareRendered = false;
|
||||
private Paint mBlackPaint;
|
||||
private Paint mFadePaint;
|
||||
private Matrix mFadeMatrix;
|
||||
private LinearGradient mFade;
|
||||
|
||||
public static FadedEdgeDrawHelper create(Context context,
|
||||
AttributeSet attrs, View scrollView, boolean isVertical) {
|
||||
boolean isTablet = context.getResources().
|
||||
getBoolean(R.bool.config_recents_interface_for_tablets);
|
||||
if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
|
||||
return new FadedEdgeDrawHelper(context, attrs, scrollView, isVertical);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public FadedEdgeDrawHelper(Context context,
|
||||
AttributeSet attrs, View scrollView, boolean isVertical) {
|
||||
mScrollView = scrollView;
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
|
||||
mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
|
||||
ViewConfiguration.get(context).getScaledFadingEdgeLength());
|
||||
mIsVertical = isVertical;
|
||||
}
|
||||
|
||||
public void onAttachedToWindowCallback(
|
||||
LinearLayout layout, boolean hardwareAccelerated) {
|
||||
mSoftwareRendered = !hardwareAccelerated;
|
||||
if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
|
||||
|| USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
|
||||
mScrollView.setVerticalFadingEdgeEnabled(false);
|
||||
mScrollView.setHorizontalFadingEdgeEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void addViewCallback(View newLinearLayoutChild) {
|
||||
if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
|
||||
final RecentsPanelView.ViewHolder holder =
|
||||
(RecentsPanelView.ViewHolder) newLinearLayoutChild.getTag();
|
||||
holder.labelView.setDrawingCacheEnabled(true);
|
||||
holder.labelView.buildDrawingCache();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawCallback(Canvas canvas,
|
||||
int left, int right, int top, int bottom, int scrollX, int scrollY,
|
||||
float topFadingEdgeStrength, float bottomFadingEdgeStrength,
|
||||
float leftFadingEdgeStrength, float rightFadingEdgeStrength, int mPaddingTop) {
|
||||
|
||||
if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
|
||||
|| USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
|
||||
if (mFadePaint == null) {
|
||||
mFadePaint = new Paint();
|
||||
mFadeMatrix = new Matrix();
|
||||
// use use a height of 1, and then wack the matrix each time we
|
||||
// actually use it.
|
||||
mFade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
|
||||
// PULL OUT THIS CONSTANT
|
||||
mFadePaint.setShader(mFade);
|
||||
}
|
||||
|
||||
// draw the fade effect
|
||||
boolean drawTop = false;
|
||||
boolean drawBottom = false;
|
||||
boolean drawLeft = false;
|
||||
boolean drawRight = false;
|
||||
|
||||
float topFadeStrength = 0.0f;
|
||||
float bottomFadeStrength = 0.0f;
|
||||
float leftFadeStrength = 0.0f;
|
||||
float rightFadeStrength = 0.0f;
|
||||
|
||||
final float fadeHeight = mFadingEdgeLength;
|
||||
int length = (int) fadeHeight;
|
||||
|
||||
// clip the fade length if top and bottom fades overlap
|
||||
// overlapping fades produce odd-looking artifacts
|
||||
if (mIsVertical && (top + length > bottom - length)) {
|
||||
length = (bottom - top) / 2;
|
||||
}
|
||||
|
||||
// also clip horizontal fades if necessary
|
||||
if (!mIsVertical && (left + length > right - length)) {
|
||||
length = (right - left) / 2;
|
||||
}
|
||||
|
||||
if (mIsVertical) {
|
||||
topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
|
||||
drawTop = topFadeStrength * fadeHeight > 1.0f;
|
||||
bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
|
||||
drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
|
||||
}
|
||||
|
||||
if (!mIsVertical) {
|
||||
leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
|
||||
drawLeft = leftFadeStrength * fadeHeight > 1.0f;
|
||||
rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
|
||||
drawRight = rightFadeStrength * fadeHeight > 1.0f;
|
||||
}
|
||||
|
||||
if (drawTop) {
|
||||
mFadeMatrix.setScale(1, fadeHeight * topFadeStrength);
|
||||
mFadeMatrix.postTranslate(left, top);
|
||||
mFade.setLocalMatrix(mFadeMatrix);
|
||||
mFadePaint.setShader(mFade);
|
||||
canvas.drawRect(left, top, right, top + length, mFadePaint);
|
||||
|
||||
if (mBlackPaint == null) {
|
||||
// Draw under the status bar at the top
|
||||
mBlackPaint = new Paint();
|
||||
mBlackPaint.setColor(0xFF000000);
|
||||
}
|
||||
canvas.drawRect(left, top - mPaddingTop, right, top, mBlackPaint);
|
||||
}
|
||||
|
||||
if (drawBottom) {
|
||||
mFadeMatrix.setScale(1, fadeHeight * bottomFadeStrength);
|
||||
mFadeMatrix.postRotate(180);
|
||||
mFadeMatrix.postTranslate(left, bottom);
|
||||
mFade.setLocalMatrix(mFadeMatrix);
|
||||
mFadePaint.setShader(mFade);
|
||||
canvas.drawRect(left, bottom - length, right, bottom, mFadePaint);
|
||||
}
|
||||
|
||||
if (drawLeft) {
|
||||
mFadeMatrix.setScale(1, fadeHeight * leftFadeStrength);
|
||||
mFadeMatrix.postRotate(-90);
|
||||
mFadeMatrix.postTranslate(left, top);
|
||||
mFade.setLocalMatrix(mFadeMatrix);
|
||||
mFadePaint.setShader(mFade);
|
||||
canvas.drawRect(left, top, left + length, bottom, mFadePaint);
|
||||
}
|
||||
|
||||
if (drawRight) {
|
||||
mFadeMatrix.setScale(1, fadeHeight * rightFadeStrength);
|
||||
mFadeMatrix.postRotate(90);
|
||||
mFadeMatrix.postTranslate(right, top);
|
||||
mFade.setLocalMatrix(mFadeMatrix);
|
||||
mFadePaint.setShader(mFade);
|
||||
canvas.drawRect(right - length, top, right, bottom, mFadePaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getVerticalFadingEdgeLength() {
|
||||
return mFadingEdgeLength;
|
||||
}
|
||||
|
||||
public int getHorizontalFadingEdgeLength() {
|
||||
return mFadingEdgeLength;
|
||||
}
|
||||
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.systemui.recent;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
/*
|
||||
* This is a helper class that listens to updates from the corresponding animation.
|
||||
* For the first two frames, it adjusts the current play time of the animation to
|
||||
* prevent jank at the beginning of the animation
|
||||
*/
|
||||
public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
|
||||
implements ValueAnimator.AnimatorUpdateListener {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final int MAX_DELAY = 1000;
|
||||
private static final int IDEAL_FRAME_DURATION = 16;
|
||||
private View mTarget;
|
||||
private long mStartFrame;
|
||||
private long mStartTime = -1;
|
||||
private boolean mHandlingOnAnimationUpdate;
|
||||
private boolean mAdjustedSecondFrameTime;
|
||||
|
||||
private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
|
||||
private static long sGlobalFrameCounter;
|
||||
|
||||
public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
|
||||
mTarget = target;
|
||||
animator.addUpdateListener(this);
|
||||
}
|
||||
|
||||
public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) {
|
||||
mTarget = target;
|
||||
vpa.setListener(this);
|
||||
}
|
||||
|
||||
// only used for ViewPropertyAnimators
|
||||
public void onAnimationStart(Animator animation) {
|
||||
final ValueAnimator va = (ValueAnimator) animation;
|
||||
va.addUpdateListener(FirstFrameAnimatorHelper.this);
|
||||
onAnimationUpdate(va);
|
||||
}
|
||||
|
||||
public static void initializeDrawListener(View view) {
|
||||
if (sGlobalDrawListener != null) {
|
||||
view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
|
||||
}
|
||||
sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() {
|
||||
private long mTime = System.currentTimeMillis();
|
||||
public void onDraw() {
|
||||
sGlobalFrameCounter++;
|
||||
if (DEBUG) {
|
||||
long newTime = System.currentTimeMillis();
|
||||
Log.d("FirstFrameAnimatorHelper", "TICK " + (newTime - mTime));
|
||||
mTime = newTime;
|
||||
}
|
||||
}
|
||||
};
|
||||
view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
|
||||
}
|
||||
|
||||
public void onAnimationUpdate(final ValueAnimator animation) {
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
if (mStartTime == -1) {
|
||||
mStartFrame = sGlobalFrameCounter;
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
|
||||
if (!mHandlingOnAnimationUpdate &&
|
||||
// If the current play time exceeds the duration, the animation
|
||||
// will get finished, even if we call setCurrentPlayTime -- therefore
|
||||
// don't adjust the animation in that case
|
||||
animation.getCurrentPlayTime() < animation.getDuration()) {
|
||||
mHandlingOnAnimationUpdate = true;
|
||||
long frameNum = sGlobalFrameCounter - mStartFrame;
|
||||
// If we haven't drawn our first frame, reset the time to t = 0
|
||||
// (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
|
||||
// are no longer in the foreground and no frames are being rendered ever)
|
||||
if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY) {
|
||||
// The first frame on animations doesn't always trigger an invalidate...
|
||||
// force an invalidate here to make sure the animation continues to advance
|
||||
mTarget.getRootView().invalidate();
|
||||
animation.setCurrentPlayTime(0);
|
||||
|
||||
// For the second frame, if the first frame took more than 16ms,
|
||||
// adjust the start time and pretend it took only 16ms anyway. This
|
||||
// prevents a large jump in the animation due to an expensive first frame
|
||||
} else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
|
||||
!mAdjustedSecondFrameTime &&
|
||||
currentTime > mStartTime + IDEAL_FRAME_DURATION) {
|
||||
animation.setCurrentPlayTime(IDEAL_FRAME_DURATION);
|
||||
mAdjustedSecondFrameTime = true;
|
||||
} else {
|
||||
if (frameNum > 1) {
|
||||
mTarget.post(new Runnable() {
|
||||
public void run() {
|
||||
animation.removeUpdateListener(FirstFrameAnimatorHelper.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (DEBUG) print(animation);
|
||||
}
|
||||
mHandlingOnAnimationUpdate = false;
|
||||
} else {
|
||||
if (DEBUG) print(animation);
|
||||
}
|
||||
}
|
||||
|
||||
public void print(ValueAnimator animation) {
|
||||
float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
|
||||
Log.d("FirstFrameAnimatorHelper", sGlobalFrameCounter +
|
||||
"(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
|
||||
mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
|
||||
}
|
||||
}
|
@ -1,586 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppGlobals;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class RecentTasksLoader implements View.OnTouchListener {
|
||||
static final String TAG = "RecentTasksLoader";
|
||||
static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
|
||||
|
||||
private static final int DISPLAY_TASKS = 20;
|
||||
private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
|
||||
|
||||
private Context mContext;
|
||||
private RecentsPanelView mRecentsPanel;
|
||||
|
||||
private Object mFirstTaskLock = new Object();
|
||||
private TaskDescription mFirstTask;
|
||||
private boolean mFirstTaskLoaded;
|
||||
|
||||
private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader;
|
||||
private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader;
|
||||
private Handler mHandler;
|
||||
|
||||
private int mIconDpi;
|
||||
private ColorDrawableWithDimensions mDefaultThumbnailBackground;
|
||||
private ColorDrawableWithDimensions mDefaultIconBackground;
|
||||
private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
|
||||
|
||||
private boolean mFirstScreenful;
|
||||
private ArrayList<TaskDescription> mLoadedTasks;
|
||||
|
||||
private enum State { LOADING, LOADED, CANCELLED };
|
||||
private State mState = State.CANCELLED;
|
||||
|
||||
|
||||
private static RecentTasksLoader sInstance;
|
||||
public static RecentTasksLoader getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new RecentTasksLoader(context);
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private RecentTasksLoader(Context context) {
|
||||
mContext = context;
|
||||
mHandler = new Handler();
|
||||
|
||||
final Resources res = context.getResources();
|
||||
|
||||
// get the icon size we want -- on tablets, we use bigger icons
|
||||
boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
|
||||
if (isTablet) {
|
||||
ActivityManager activityManager =
|
||||
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
mIconDpi = activityManager.getLauncherLargeIconDensity();
|
||||
} else {
|
||||
mIconDpi = res.getDisplayMetrics().densityDpi;
|
||||
}
|
||||
|
||||
// Render default icon (just a blank image)
|
||||
int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size);
|
||||
int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi);
|
||||
mDefaultIconBackground = new ColorDrawableWithDimensions(0x00000000, iconSize, iconSize);
|
||||
|
||||
// Render the default thumbnail background
|
||||
int thumbnailWidth =
|
||||
(int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
|
||||
int thumbnailHeight =
|
||||
(int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
|
||||
int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background);
|
||||
|
||||
mDefaultThumbnailBackground =
|
||||
new ColorDrawableWithDimensions(color, thumbnailWidth, thumbnailHeight);
|
||||
}
|
||||
|
||||
public void setRecentsPanel(RecentsPanelView newRecentsPanel, RecentsPanelView caller) {
|
||||
// Only allow clearing mRecentsPanel if the caller is the current recentsPanel
|
||||
if (newRecentsPanel != null || mRecentsPanel == caller) {
|
||||
mRecentsPanel = newRecentsPanel;
|
||||
if (mRecentsPanel != null) {
|
||||
mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable getDefaultThumbnail() {
|
||||
return mDefaultThumbnailBackground;
|
||||
}
|
||||
|
||||
public Drawable getDefaultIcon() {
|
||||
return mDefaultIconBackground;
|
||||
}
|
||||
|
||||
public ArrayList<TaskDescription> getLoadedTasks() {
|
||||
return mLoadedTasks;
|
||||
}
|
||||
|
||||
public void remove(TaskDescription td) {
|
||||
mLoadedTasks.remove(td);
|
||||
}
|
||||
|
||||
public boolean isFirstScreenful() {
|
||||
return mFirstScreenful;
|
||||
}
|
||||
|
||||
private boolean isCurrentHomeActivity(ComponentName component, ActivityInfo homeInfo) {
|
||||
if (homeInfo == null) {
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
|
||||
.resolveActivityInfo(pm, 0);
|
||||
}
|
||||
return homeInfo != null
|
||||
&& homeInfo.packageName.equals(component.getPackageName())
|
||||
&& homeInfo.name.equals(component.getClassName());
|
||||
}
|
||||
|
||||
// Create an TaskDescription, returning null if the title or icon is null
|
||||
TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent,
|
||||
ComponentName origActivity, CharSequence description, int userId) {
|
||||
Intent intent = new Intent(baseIntent);
|
||||
if (origActivity != null) {
|
||||
intent.setComponent(origActivity);
|
||||
}
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final IPackageManager ipm = AppGlobals.getPackageManager();
|
||||
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
ResolveInfo resolveInfo = null;
|
||||
try {
|
||||
resolveInfo = ipm.resolveIntent(intent, null, 0, userId);
|
||||
} catch (RemoteException re) {
|
||||
}
|
||||
if (resolveInfo != null) {
|
||||
final ActivityInfo info = resolveInfo.activityInfo;
|
||||
final String title = info.loadLabel(pm).toString();
|
||||
|
||||
if (title != null && title.length() > 0) {
|
||||
if (DEBUG) Log.v(TAG, "creating activity desc for id="
|
||||
+ persistentTaskId + ", label=" + title);
|
||||
|
||||
TaskDescription item = new TaskDescription(taskId,
|
||||
persistentTaskId, resolveInfo, baseIntent, info.packageName,
|
||||
description, userId);
|
||||
item.setLabel(title);
|
||||
|
||||
return item;
|
||||
} else {
|
||||
if (DEBUG) Log.v(TAG, "SKIPPING item " + persistentTaskId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void loadThumbnailAndIcon(TaskDescription td) {
|
||||
final ActivityManager am = (ActivityManager)
|
||||
mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final Bitmap thumbnail = SystemServicesProxy.getThumbnail(am, td.persistentTaskId);
|
||||
Drawable icon = getFullResIcon(td.resolveInfo, pm);
|
||||
if (td.userId != UserHandle.myUserId()) {
|
||||
// Need to badge the icon
|
||||
icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(td.userId));
|
||||
}
|
||||
if (DEBUG) Log.v(TAG, "Loaded bitmap for task "
|
||||
+ td + ": " + thumbnail);
|
||||
synchronized (td) {
|
||||
if (thumbnail != null) {
|
||||
td.setThumbnail(new BitmapDrawable(mContext.getResources(), thumbnail));
|
||||
} else {
|
||||
td.setThumbnail(mDefaultThumbnailBackground);
|
||||
}
|
||||
if (icon != null) {
|
||||
td.setIcon(icon);
|
||||
}
|
||||
td.setLoaded(true);
|
||||
}
|
||||
}
|
||||
|
||||
Drawable getFullResDefaultActivityIcon() {
|
||||
return getFullResIcon(Resources.getSystem(),
|
||||
com.android.internal.R.mipmap.sym_def_app_icon);
|
||||
}
|
||||
|
||||
Drawable getFullResIcon(Resources resources, int iconId) {
|
||||
try {
|
||||
return resources.getDrawableForDensity(iconId, mIconDpi);
|
||||
} catch (Resources.NotFoundException e) {
|
||||
return getFullResDefaultActivityIcon();
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
|
||||
Resources resources;
|
||||
try {
|
||||
resources = packageManager.getResourcesForApplication(
|
||||
info.activityInfo.applicationInfo);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
resources = null;
|
||||
}
|
||||
if (resources != null) {
|
||||
int iconId = info.activityInfo.getIconResource();
|
||||
if (iconId != 0) {
|
||||
return getFullResIcon(resources, iconId);
|
||||
}
|
||||
}
|
||||
return getFullResDefaultActivityIcon();
|
||||
}
|
||||
|
||||
Runnable mPreloadTasksRunnable = new Runnable() {
|
||||
public void run() {
|
||||
loadTasksInBackground();
|
||||
}
|
||||
};
|
||||
|
||||
// additional optimization when we have software system buttons - start loading the recent
|
||||
// tasks on touch down
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent ev) {
|
||||
int action = ev.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
preloadRecentTasksList();
|
||||
} else if (action == MotionEvent.ACTION_CANCEL) {
|
||||
cancelPreloadingRecentTasksList();
|
||||
} else if (action == MotionEvent.ACTION_UP) {
|
||||
// Remove the preloader if we haven't called it yet
|
||||
mHandler.removeCallbacks(mPreloadTasksRunnable);
|
||||
if (!v.isPressed()) {
|
||||
cancelLoadingThumbnailsAndIcons();
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void preloadRecentTasksList() {
|
||||
mHandler.post(mPreloadTasksRunnable);
|
||||
}
|
||||
|
||||
public void cancelPreloadingRecentTasksList() {
|
||||
cancelLoadingThumbnailsAndIcons();
|
||||
mHandler.removeCallbacks(mPreloadTasksRunnable);
|
||||
}
|
||||
|
||||
public void cancelLoadingThumbnailsAndIcons(RecentsPanelView caller) {
|
||||
// Only oblige this request if it comes from the current RecentsPanel
|
||||
// (eg when you rotate, the old RecentsPanel request should be ignored)
|
||||
if (mRecentsPanel == caller) {
|
||||
cancelLoadingThumbnailsAndIcons();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void cancelLoadingThumbnailsAndIcons() {
|
||||
if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTaskLoader != null) {
|
||||
mTaskLoader.cancel(false);
|
||||
mTaskLoader = null;
|
||||
}
|
||||
if (mThumbnailLoader != null) {
|
||||
mThumbnailLoader.cancel(false);
|
||||
mThumbnailLoader = null;
|
||||
}
|
||||
mLoadedTasks = null;
|
||||
if (mRecentsPanel != null) {
|
||||
mRecentsPanel.onTaskLoadingCancelled();
|
||||
}
|
||||
mFirstScreenful = false;
|
||||
mState = State.CANCELLED;
|
||||
}
|
||||
|
||||
private void clearFirstTask() {
|
||||
synchronized (mFirstTaskLock) {
|
||||
mFirstTask = null;
|
||||
mFirstTaskLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void preloadFirstTask() {
|
||||
Thread bgLoad = new Thread() {
|
||||
public void run() {
|
||||
TaskDescription first = loadFirstTask();
|
||||
synchronized(mFirstTaskLock) {
|
||||
if (mCancelPreloadingFirstTask) {
|
||||
clearFirstTask();
|
||||
} else {
|
||||
mFirstTask = first;
|
||||
mFirstTaskLoaded = true;
|
||||
}
|
||||
mPreloadingFirstTask = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
synchronized(mFirstTaskLock) {
|
||||
if (!mPreloadingFirstTask) {
|
||||
clearFirstTask();
|
||||
mPreloadingFirstTask = true;
|
||||
bgLoad.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelPreloadingFirstTask() {
|
||||
synchronized(mFirstTaskLock) {
|
||||
if (mPreloadingFirstTask) {
|
||||
mCancelPreloadingFirstTask = true;
|
||||
} else {
|
||||
clearFirstTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean mPreloadingFirstTask;
|
||||
boolean mCancelPreloadingFirstTask;
|
||||
public TaskDescription getFirstTask() {
|
||||
while(true) {
|
||||
synchronized(mFirstTaskLock) {
|
||||
if (mFirstTaskLoaded) {
|
||||
return mFirstTask;
|
||||
} else if (!mFirstTaskLoaded && !mPreloadingFirstTask) {
|
||||
mFirstTask = loadFirstTask();
|
||||
mFirstTaskLoaded = true;
|
||||
return mFirstTask;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(3);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TaskDescription loadFirstTask() {
|
||||
final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
|
||||
final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(1,
|
||||
ActivityManager.RECENT_IGNORE_UNAVAILABLE | ActivityManager.RECENT_INCLUDE_PROFILES,
|
||||
UserHandle.CURRENT.getIdentifier());
|
||||
TaskDescription item = null;
|
||||
if (recentTasks.size() > 0) {
|
||||
ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(0);
|
||||
|
||||
Intent intent = new Intent(recentInfo.baseIntent);
|
||||
if (recentInfo.origActivity != null) {
|
||||
intent.setComponent(recentInfo.origActivity);
|
||||
}
|
||||
|
||||
// Don't load the current home activity.
|
||||
if (isCurrentHomeActivity(intent.getComponent(), null)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Don't load ourselves
|
||||
if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
item = createTaskDescription(recentInfo.id,
|
||||
recentInfo.persistentId, recentInfo.baseIntent,
|
||||
recentInfo.origActivity, recentInfo.description,
|
||||
recentInfo.userId);
|
||||
if (item != null) {
|
||||
loadThumbnailAndIcon(item);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void loadTasksInBackground() {
|
||||
loadTasksInBackground(false);
|
||||
}
|
||||
public void loadTasksInBackground(final boolean zeroeth) {
|
||||
if (mState != State.CANCELLED) {
|
||||
return;
|
||||
}
|
||||
mState = State.LOADING;
|
||||
mFirstScreenful = true;
|
||||
|
||||
final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails =
|
||||
new LinkedBlockingQueue<TaskDescription>();
|
||||
mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() {
|
||||
@Override
|
||||
protected void onProgressUpdate(ArrayList<TaskDescription>... values) {
|
||||
if (!isCancelled()) {
|
||||
ArrayList<TaskDescription> newTasks = values[0];
|
||||
// do a callback to RecentsPanelView to let it know we have more values
|
||||
// how do we let it know we're all done? just always call back twice
|
||||
if (mRecentsPanel != null) {
|
||||
mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful);
|
||||
}
|
||||
if (mLoadedTasks == null) {
|
||||
mLoadedTasks = new ArrayList<TaskDescription>();
|
||||
}
|
||||
mLoadedTasks.addAll(newTasks);
|
||||
mFirstScreenful = false;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
// We load in two stages: first, we update progress with just the first screenful
|
||||
// of items. Then, we update with the rest of the items
|
||||
final int origPri = Process.getThreadPriority(Process.myTid());
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
final ActivityManager am = (ActivityManager)
|
||||
mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
|
||||
final List<ActivityManager.RecentTaskInfo> recentTasks =
|
||||
am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
|
||||
| ActivityManager.RECENT_INCLUDE_PROFILES);
|
||||
int numTasks = recentTasks.size();
|
||||
ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
|
||||
.addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
|
||||
|
||||
boolean firstScreenful = true;
|
||||
ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
|
||||
|
||||
// skip the first task - assume it's either the home screen or the current activity.
|
||||
final int first = 0;
|
||||
for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) {
|
||||
if (isCancelled()) {
|
||||
break;
|
||||
}
|
||||
final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i);
|
||||
|
||||
Intent intent = new Intent(recentInfo.baseIntent);
|
||||
if (recentInfo.origActivity != null) {
|
||||
intent.setComponent(recentInfo.origActivity);
|
||||
}
|
||||
|
||||
// Don't load the current home activity.
|
||||
if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't load ourselves
|
||||
if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TaskDescription item = createTaskDescription(recentInfo.id,
|
||||
recentInfo.persistentId, recentInfo.baseIntent,
|
||||
recentInfo.origActivity, recentInfo.description,
|
||||
recentInfo.userId);
|
||||
|
||||
if (item != null) {
|
||||
while (true) {
|
||||
try {
|
||||
tasksWaitingForThumbnails.put(item);
|
||||
break;
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
tasks.add(item);
|
||||
if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) {
|
||||
publishProgress(tasks);
|
||||
tasks = new ArrayList<TaskDescription>();
|
||||
firstScreenful = false;
|
||||
//break;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isCancelled()) {
|
||||
publishProgress(tasks);
|
||||
if (firstScreenful) {
|
||||
// always should publish two updates
|
||||
publishProgress(new ArrayList<TaskDescription>());
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
tasksWaitingForThumbnails.put(new TaskDescription());
|
||||
break;
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
Process.setThreadPriority(origPri);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails);
|
||||
}
|
||||
|
||||
private void loadThumbnailsAndIconsInBackground(
|
||||
final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) {
|
||||
// continually read items from tasksWaitingForThumbnails and load
|
||||
// thumbnails and icons for them. finish thread when cancelled or there
|
||||
// is a null item in tasksWaitingForThumbnails
|
||||
mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() {
|
||||
@Override
|
||||
protected void onProgressUpdate(TaskDescription... values) {
|
||||
if (!isCancelled()) {
|
||||
TaskDescription td = values[0];
|
||||
if (td.isNull()) { // end sentinel
|
||||
mState = State.LOADED;
|
||||
} else {
|
||||
if (mRecentsPanel != null) {
|
||||
mRecentsPanel.onTaskThumbnailLoaded(td);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
final int origPri = Process.getThreadPriority(Process.myTid());
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
|
||||
while (true) {
|
||||
if (isCancelled()) {
|
||||
break;
|
||||
}
|
||||
TaskDescription td = null;
|
||||
while (td == null) {
|
||||
try {
|
||||
td = tasksWaitingForThumbnails.take();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
if (td.isNull()) { // end sentinel
|
||||
publishProgress(td);
|
||||
break;
|
||||
}
|
||||
loadThumbnailAndIcon(td);
|
||||
|
||||
publishProgress(td);
|
||||
}
|
||||
|
||||
Process.setThreadPriority(origPri);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.systemui.recent;
|
||||
|
||||
import android.app.ActivityOptions;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.RecentsComponent;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.recents.AlternateRecentsComponent;
|
||||
|
||||
|
||||
public class Recents extends SystemUI implements RecentsComponent {
|
||||
private static final String TAG = "Recents";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
// Which recents to use
|
||||
boolean mUseAlternateRecents = true;
|
||||
boolean mBootCompleted = false;
|
||||
static AlternateRecentsComponent sAlternateRecents;
|
||||
|
||||
/** Returns the Recents component, creating a new one in-process if necessary. */
|
||||
public static AlternateRecentsComponent getRecentsComponent(Context context,
|
||||
boolean forceInitialize) {
|
||||
if (sAlternateRecents == null) {
|
||||
sAlternateRecents = new AlternateRecentsComponent(context);
|
||||
if (forceInitialize) {
|
||||
sAlternateRecents.onStart();
|
||||
sAlternateRecents.onBootCompleted();
|
||||
}
|
||||
}
|
||||
return sAlternateRecents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (mUseAlternateRecents) {
|
||||
if (sAlternateRecents == null) {
|
||||
sAlternateRecents = getRecentsComponent(mContext, false);
|
||||
}
|
||||
sAlternateRecents.onStart();
|
||||
}
|
||||
|
||||
putComponent(RecentsComponent.class, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBootCompleted() {
|
||||
if (mUseAlternateRecents) {
|
||||
if (sAlternateRecents != null) {
|
||||
sAlternateRecents.onBootCompleted();
|
||||
}
|
||||
}
|
||||
mBootCompleted = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.onShowRecents(triggeredFromAltTab);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.onHideRecents(triggeredFromAltTab, triggeredFromHomeKey);
|
||||
} else {
|
||||
Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
|
||||
intent.setPackage("com.android.systemui");
|
||||
sendBroadcastSafely(intent);
|
||||
|
||||
RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
|
||||
if (mUseAlternateRecents) {
|
||||
// Launch the alternate recents if required
|
||||
sAlternateRecents.onToggleRecents();
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "toggle recents panel");
|
||||
try {
|
||||
TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask();
|
||||
|
||||
Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
|
||||
intent.setClassName("com.android.systemui",
|
||||
"com.android.systemui.recent.RecentsActivity");
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||
|
||||
if (firstTask == null) {
|
||||
if (RecentsActivity.forceOpaqueBackground(mContext)) {
|
||||
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
|
||||
R.anim.recents_launch_from_launcher_enter,
|
||||
R.anim.recents_launch_from_launcher_exit);
|
||||
mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
|
||||
UserHandle.USER_CURRENT));
|
||||
} else {
|
||||
// The correct window animation will be applied via the activity's style
|
||||
mContext.startActivityAsUser(intent, new UserHandle(
|
||||
UserHandle.USER_CURRENT));
|
||||
}
|
||||
|
||||
} else {
|
||||
Bitmap first = null;
|
||||
if (firstTask.getThumbnail() instanceof BitmapDrawable) {
|
||||
first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
|
||||
} else {
|
||||
first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
||||
Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
|
||||
d.draw(new Canvas(first));
|
||||
}
|
||||
final Resources res = mContext.getResources();
|
||||
|
||||
float thumbWidth = res
|
||||
.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
|
||||
float thumbHeight = res
|
||||
.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
|
||||
if (first == null) {
|
||||
throw new RuntimeException("Recents thumbnail is null");
|
||||
}
|
||||
if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
|
||||
first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
|
||||
true);
|
||||
if (first == null) {
|
||||
throw new RuntimeException("Recents thumbnail is null");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DisplayMetrics dm = new DisplayMetrics();
|
||||
display.getMetrics(dm);
|
||||
// calculate it here, but consider moving it elsewhere
|
||||
// first, determine which orientation you're in.
|
||||
final Configuration config = res.getConfiguration();
|
||||
int x, y;
|
||||
|
||||
if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
float appLabelLeftMargin = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_app_label_left_margin);
|
||||
float appLabelWidth = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_app_label_width);
|
||||
float thumbLeftMargin = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_thumbnail_left_margin);
|
||||
float thumbBgPadding = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_thumbnail_bg_padding);
|
||||
|
||||
float width = appLabelLeftMargin +
|
||||
+appLabelWidth
|
||||
+ thumbLeftMargin
|
||||
+ thumbWidth
|
||||
+ 2 * thumbBgPadding;
|
||||
|
||||
x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth
|
||||
+ thumbBgPadding + thumbLeftMargin);
|
||||
y = (int) (dm.heightPixels
|
||||
- res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height)
|
||||
- thumbBgPadding);
|
||||
if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
|
||||
x = dm.widthPixels - x - res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_thumbnail_width);
|
||||
}
|
||||
|
||||
} else { // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
float thumbTopMargin = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_thumbnail_top_margin);
|
||||
float thumbBgPadding = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_thumbnail_bg_padding);
|
||||
float textPadding = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_text_description_padding);
|
||||
float labelTextSize = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_app_label_text_size);
|
||||
Paint p = new Paint();
|
||||
p.setTextSize(labelTextSize);
|
||||
float labelTextHeight = p.getFontMetricsInt().bottom
|
||||
- p.getFontMetricsInt().top;
|
||||
float descriptionTextSize = res.getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_app_description_text_size);
|
||||
p.setTextSize(descriptionTextSize);
|
||||
float descriptionTextHeight = p.getFontMetricsInt().bottom
|
||||
- p.getFontMetricsInt().top;
|
||||
|
||||
float statusBarHeight = res.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.status_bar_height);
|
||||
float recentsItemTopPadding = statusBarHeight;
|
||||
|
||||
float height = thumbTopMargin
|
||||
+ thumbHeight
|
||||
+ 2 * thumbBgPadding + textPadding + labelTextHeight
|
||||
+ recentsItemTopPadding + textPadding + descriptionTextHeight;
|
||||
float recentsItemRightPadding = res
|
||||
.getDimensionPixelSize(R.dimen.status_bar_recents_item_padding);
|
||||
float recentsScrollViewRightPadding = res
|
||||
.getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin);
|
||||
x = (int) (dm.widthPixels - res
|
||||
.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width)
|
||||
- thumbBgPadding - recentsItemRightPadding
|
||||
- recentsScrollViewRightPadding);
|
||||
y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
|
||||
+ recentsItemTopPadding + thumbBgPadding + statusBarHeight);
|
||||
}
|
||||
|
||||
ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
|
||||
statusBarView,
|
||||
first, x, y,
|
||||
new ActivityOptions.OnAnimationStartedListener() {
|
||||
public void onAnimationStarted() {
|
||||
Intent intent =
|
||||
new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
|
||||
intent.setPackage("com.android.systemui");
|
||||
sendBroadcastSafely(intent);
|
||||
}
|
||||
});
|
||||
intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
|
||||
startActivitySafely(intent, opts.toBundle());
|
||||
}
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "Failed to launch RecentAppsIntent", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preloadRecents() {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.onPreloadRecents();
|
||||
} else {
|
||||
Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
|
||||
intent.setClassName("com.android.systemui",
|
||||
"com.android.systemui.recent.RecentsPreloadReceiver");
|
||||
sendBroadcastSafely(intent);
|
||||
|
||||
RecentTasksLoader.getInstance(mContext).preloadFirstTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelPreloadingRecents() {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.onCancelPreloadingRecents();
|
||||
} else {
|
||||
Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
|
||||
intent.setClassName("com.android.systemui",
|
||||
"com.android.systemui.recent.RecentsPreloadReceiver");
|
||||
sendBroadcastSafely(intent);
|
||||
|
||||
RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showNextAffiliatedTask() {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.onShowNextAffiliatedTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPrevAffiliatedTask() {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.onShowPrevAffiliatedTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(Callbacks cb) {
|
||||
if (mUseAlternateRecents) {
|
||||
sAlternateRecents.setRecentsComponentCallback(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send broadcast only if BOOT_COMPLETED
|
||||
*/
|
||||
private void sendBroadcastSafely(Intent intent) {
|
||||
if (!mBootCompleted) return;
|
||||
mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start activity only if BOOT_COMPLETED
|
||||
*/
|
||||
private void startActivitySafely(Intent intent, Bundle opts) {
|
||||
if (!mBootCompleted) return;
|
||||
mContext.startActivityAsUser(intent, opts, new UserHandle(UserHandle.USER_CURRENT));
|
||||
}
|
||||
}
|
@ -1,248 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.systemui.recent;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.WallpaperManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.StatusBarPanel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RecentsActivity extends Activity {
|
||||
public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.recent.action.TOGGLE_RECENTS";
|
||||
public static final String PRELOAD_INTENT = "com.android.systemui.recent.action.PRELOAD";
|
||||
public static final String CANCEL_PRELOAD_INTENT = "com.android.systemui.recent.CANCEL_PRELOAD";
|
||||
public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.recent.action.CLOSE";
|
||||
public static final String WINDOW_ANIMATION_START_INTENT = "com.android.systemui.recent.action.WINDOW_ANIMATION_START";
|
||||
public static final String PRELOAD_PERMISSION = "com.android.systemui.recent.permission.PRELOAD";
|
||||
public static final String WAITING_FOR_WINDOW_ANIMATION_PARAM = "com.android.systemui.recent.WAITING_FOR_WINDOW_ANIMATION";
|
||||
private static final String WAS_SHOWING = "was_showing";
|
||||
|
||||
private RecentsPanelView mRecentsPanel;
|
||||
private IntentFilter mIntentFilter;
|
||||
private boolean mShowing;
|
||||
private boolean mForeground;
|
||||
|
||||
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (CLOSE_RECENTS_INTENT.equals(intent.getAction())) {
|
||||
if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
|
||||
if (mShowing && !mForeground) {
|
||||
// Captures the case right before we transition to another activity
|
||||
mRecentsPanel.show(false);
|
||||
}
|
||||
}
|
||||
} else if (WINDOW_ANIMATION_START_INTENT.equals(intent.getAction())) {
|
||||
if (mRecentsPanel != null) {
|
||||
mRecentsPanel.onWindowAnimationStart();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public class TouchOutsideListener implements View.OnTouchListener {
|
||||
private StatusBarPanel mPanel;
|
||||
|
||||
public TouchOutsideListener(StatusBarPanel panel) {
|
||||
mPanel = panel;
|
||||
}
|
||||
|
||||
public boolean onTouch(View v, MotionEvent ev) {
|
||||
final int action = ev.getAction();
|
||||
if (action == MotionEvent.ACTION_OUTSIDE
|
||||
|| (action == MotionEvent.ACTION_DOWN
|
||||
&& !mPanel.isInContentArea((int) ev.getX(), (int) ev.getY()))) {
|
||||
dismissAndGoHome();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
overridePendingTransition(
|
||||
R.anim.recents_return_to_launcher_enter,
|
||||
R.anim.recents_return_to_launcher_exit);
|
||||
mForeground = false;
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mShowing = false;
|
||||
if (mRecentsPanel != null) {
|
||||
mRecentsPanel.onUiHidden();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private void updateWallpaperVisibility(boolean visible) {
|
||||
int wpflags = visible ? WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER : 0;
|
||||
int curflags = getWindow().getAttributes().flags
|
||||
& WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
|
||||
if (wpflags != curflags) {
|
||||
getWindow().setFlags(wpflags, WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean forceOpaqueBackground(Context context) {
|
||||
return WallpaperManager.getInstance(context).getWallpaperInfo() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
// Hide wallpaper if it's not a static image
|
||||
if (forceOpaqueBackground(this)) {
|
||||
updateWallpaperVisibility(false);
|
||||
} else {
|
||||
updateWallpaperVisibility(true);
|
||||
}
|
||||
mShowing = true;
|
||||
if (mRecentsPanel != null) {
|
||||
// Call and refresh the recent tasks list in case we didn't preload tasks
|
||||
// or in case we don't get an onNewIntent
|
||||
mRecentsPanel.refreshRecentTasksList();
|
||||
mRecentsPanel.refreshViews();
|
||||
}
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
mForeground = true;
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
dismissAndGoBack();
|
||||
}
|
||||
|
||||
public void dismissAndGoHome() {
|
||||
if (mRecentsPanel != null) {
|
||||
Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
|
||||
homeIntent.addCategory(Intent.CATEGORY_HOME);
|
||||
homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
||||
startActivityAsUser(homeIntent, new UserHandle(UserHandle.USER_CURRENT));
|
||||
mRecentsPanel.show(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void dismissAndGoBack() {
|
||||
if (mRecentsPanel != null) {
|
||||
final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
|
||||
final List<ActivityManager.RecentTaskInfo> recentTasks =
|
||||
am.getRecentTasks(2,
|
||||
ActivityManager.RECENT_WITH_EXCLUDED |
|
||||
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
|
||||
ActivityManager.RECENT_INCLUDE_PROFILES);
|
||||
if (recentTasks.size() > 1 &&
|
||||
mRecentsPanel.simulateClick(recentTasks.get(1).persistentId)) {
|
||||
// recents panel will take care of calling show(false) through simulateClick
|
||||
return;
|
||||
}
|
||||
mRecentsPanel.show(false);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
getWindow().addPrivateFlags(
|
||||
WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR);
|
||||
setContentView(R.layout.status_bar_recent_panel);
|
||||
mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
|
||||
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
|
||||
mRecentsPanel.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
|
||||
final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
|
||||
recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
|
||||
mRecentsPanel.setMinSwipeAlpha(
|
||||
getResources().getInteger(R.integer.config_recent_item_min_alpha) / 100f);
|
||||
|
||||
if (savedInstanceState == null ||
|
||||
savedInstanceState.getBoolean(WAS_SHOWING)) {
|
||||
handleIntent(getIntent(), (savedInstanceState == null));
|
||||
}
|
||||
mIntentFilter = new IntentFilter();
|
||||
mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
|
||||
mIntentFilter.addAction(WINDOW_ANIMATION_START_INTENT);
|
||||
registerReceiver(mIntentReceiver, mIntentFilter);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putBoolean(WAS_SHOWING, mRecentsPanel.isShowing());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
RecentTasksLoader.getInstance(this).setRecentsPanel(null, mRecentsPanel);
|
||||
unregisterReceiver(mIntentReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
handleIntent(intent, true);
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent, boolean checkWaitingForAnimationParam) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
if (TOGGLE_RECENTS_INTENT.equals(intent.getAction())) {
|
||||
if (mRecentsPanel != null) {
|
||||
if (mRecentsPanel.isShowing()) {
|
||||
dismissAndGoBack();
|
||||
} else {
|
||||
final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
|
||||
boolean waitingForWindowAnimation = checkWaitingForAnimationParam &&
|
||||
intent.getBooleanExtra(WAITING_FOR_WINDOW_ANIMATION_PARAM, false);
|
||||
mRecentsPanel.show(true, recentTasksLoader.getLoadedTasks(),
|
||||
recentTasksLoader.isFirstScreenful(), waitingForWindowAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isForeground() {
|
||||
return mForeground;
|
||||
}
|
||||
|
||||
boolean isActivityShowing() {
|
||||
return mShowing;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface RecentsCallback {
|
||||
static final int SWIPE_LEFT = 0;
|
||||
static final int SWIPE_RIGHT = 1;
|
||||
static final int SWIPE_UP = 2;
|
||||
static final int SWIPE_DOWN = 3;
|
||||
|
||||
void handleOnClick(View selectedView);
|
||||
void handleSwipe(View selectedView);
|
||||
void handleLongPress(View selectedView, View anchorView, View thumbnailView);
|
||||
void dismiss();
|
||||
}
|
@ -1,391 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SwipeHelper;
|
||||
import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class RecentsHorizontalScrollView extends HorizontalScrollView
|
||||
implements SwipeHelper.Callback, RecentsPanelView.RecentsScrollView {
|
||||
private static final String TAG = RecentsPanelView.TAG;
|
||||
private static final boolean DEBUG = RecentsPanelView.DEBUG;
|
||||
private LinearLayout mLinearLayout;
|
||||
private TaskDescriptionAdapter mAdapter;
|
||||
private RecentsCallback mCallback;
|
||||
protected int mLastScrollPosition;
|
||||
private SwipeHelper mSwipeHelper;
|
||||
private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
|
||||
private HashSet<View> mRecycledViews;
|
||||
private int mNumItemsInOneScreenful;
|
||||
private Runnable mOnScrollListener;
|
||||
|
||||
public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, 0);
|
||||
mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, context);
|
||||
mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, false);
|
||||
mRecycledViews = new HashSet<View>();
|
||||
}
|
||||
|
||||
public void setMinSwipeAlpha(float minAlpha) {
|
||||
mSwipeHelper.setMinSwipeProgress(minAlpha);
|
||||
}
|
||||
|
||||
private int scrollPositionOfMostRecent() {
|
||||
return mLinearLayout.getWidth() - getWidth();
|
||||
}
|
||||
|
||||
private void addToRecycledViews(View v) {
|
||||
if (mRecycledViews.size() < mNumItemsInOneScreenful) {
|
||||
mRecycledViews.add(v);
|
||||
}
|
||||
}
|
||||
|
||||
public View findViewForTask(int persistentTaskId) {
|
||||
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
|
||||
View v = mLinearLayout.getChildAt(i);
|
||||
RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
|
||||
if (holder.taskDescription.persistentTaskId == persistentTaskId) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void update() {
|
||||
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
|
||||
View v = mLinearLayout.getChildAt(i);
|
||||
addToRecycledViews(v);
|
||||
mAdapter.recycleView(v);
|
||||
}
|
||||
LayoutTransition transitioner = getLayoutTransition();
|
||||
setLayoutTransition(null);
|
||||
|
||||
mLinearLayout.removeAllViews();
|
||||
Iterator<View> recycledViews = mRecycledViews.iterator();
|
||||
for (int i = 0; i < mAdapter.getCount(); i++) {
|
||||
View old = null;
|
||||
if (recycledViews.hasNext()) {
|
||||
old = recycledViews.next();
|
||||
recycledViews.remove();
|
||||
old.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
final View view = mAdapter.getView(i, old, mLinearLayout);
|
||||
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
mFadedEdgeDrawHelper.addViewCallback(view);
|
||||
}
|
||||
|
||||
OnTouchListener noOpListener = new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mCallback.dismiss();
|
||||
}
|
||||
});
|
||||
// We don't want a click sound when we dimiss recents
|
||||
view.setSoundEffectsEnabled(false);
|
||||
|
||||
OnClickListener launchAppListener = new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mCallback.handleOnClick(view);
|
||||
}
|
||||
};
|
||||
|
||||
RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
|
||||
final View thumbnailView = holder.thumbnailView;
|
||||
OnLongClickListener longClickListener = new OnLongClickListener() {
|
||||
public boolean onLongClick(View v) {
|
||||
final View anchorView = view.findViewById(R.id.app_description);
|
||||
mCallback.handleLongPress(view, anchorView, thumbnailView);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
thumbnailView.setClickable(true);
|
||||
thumbnailView.setOnClickListener(launchAppListener);
|
||||
thumbnailView.setOnLongClickListener(longClickListener);
|
||||
|
||||
// We don't want to dismiss recents if a user clicks on the app title
|
||||
// (we also don't want to launch the app either, though, because the
|
||||
// app title is a small target and doesn't have great click feedback)
|
||||
final View appTitle = view.findViewById(R.id.app_label);
|
||||
appTitle.setContentDescription(" ");
|
||||
appTitle.setOnTouchListener(noOpListener);
|
||||
mLinearLayout.addView(view);
|
||||
}
|
||||
setLayoutTransition(transitioner);
|
||||
|
||||
// Scroll to end after initial layout.
|
||||
|
||||
final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
|
||||
public void onGlobalLayout() {
|
||||
mLastScrollPosition = scrollPositionOfMostRecent();
|
||||
scrollTo(mLastScrollPosition, 0);
|
||||
final ViewTreeObserver observer = getViewTreeObserver();
|
||||
if (observer.isAlive()) {
|
||||
observer.removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewInLayout(final View view) {
|
||||
dismissChild(view);
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
|
||||
return mSwipeHelper.onInterceptTouchEvent(ev) ||
|
||||
super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return mSwipeHelper.onTouchEvent(ev) ||
|
||||
super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
public boolean canChildBeDismissed(View v) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAntiFalsingNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFalsingThresholdFactor() {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
public void dismissChild(View v) {
|
||||
mSwipeHelper.dismissChild(v, 0);
|
||||
}
|
||||
|
||||
public void onChildDismissed(View v) {
|
||||
addToRecycledViews(v);
|
||||
mLinearLayout.removeView(v);
|
||||
mCallback.handleSwipe(v);
|
||||
// Restore the alpha/translation parameters to what they were before swiping
|
||||
// (for when these items are recycled)
|
||||
View contentView = getChildContentView(v);
|
||||
contentView.setAlpha(1f);
|
||||
contentView.setTranslationY(0);
|
||||
}
|
||||
|
||||
public void onBeginDrag(View v) {
|
||||
// We do this so the underlying ScrollView knows that it won't get
|
||||
// the chance to intercept events anymore
|
||||
requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
|
||||
public void onDragCancelled(View v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildSnappedBack(View animView) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public View getChildAtPosition(MotionEvent ev) {
|
||||
final float x = ev.getX() + getScrollX();
|
||||
final float y = ev.getY() + getScrollY();
|
||||
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
|
||||
View item = mLinearLayout.getChildAt(i);
|
||||
if (x >= item.getLeft() && x < item.getRight()
|
||||
&& y >= item.getTop() && y < item.getBottom()) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public View getChildContentView(View v) {
|
||||
return v.findViewById(R.id.recent_item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
|
||||
mFadedEdgeDrawHelper.drawCallback(canvas,
|
||||
left, right, top, bottom, getScrollX(), getScrollY(),
|
||||
0, 0,
|
||||
getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), getPaddingTop());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||
super.onScrollChanged(l, t, oldl, oldt);
|
||||
if (mOnScrollListener != null) {
|
||||
mOnScrollListener.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnScrollListener(Runnable listener) {
|
||||
mOnScrollListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVerticalFadingEdgeLength() {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
|
||||
} else {
|
||||
return super.getVerticalFadingEdgeLength();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHorizontalFadingEdgeLength() {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
|
||||
} else {
|
||||
return super.getHorizontalFadingEdgeLength();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
setScrollbarFadingEnabled(true);
|
||||
mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
|
||||
final int leftPadding = getContext().getResources()
|
||||
.getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
|
||||
setOverScrollEffectPadding(leftPadding, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
float densityScale = getResources().getDisplayMetrics().density;
|
||||
mSwipeHelper.setDensityScale(densityScale);
|
||||
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
|
||||
mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
|
||||
}
|
||||
|
||||
private void setOverScrollEffectPadding(int leftPadding, int i) {
|
||||
// TODO Add to (Vertical)ScrollView
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
// Skip this work if a transition is running; it sets the scroll values independently
|
||||
// and should not have those animated values clobbered by this logic
|
||||
LayoutTransition transition = mLinearLayout.getLayoutTransition();
|
||||
if (transition != null && transition.isRunning()) {
|
||||
return;
|
||||
}
|
||||
// Keep track of the last visible item in the list so we can restore it
|
||||
// to the bottom when the orientation changes.
|
||||
mLastScrollPosition = scrollPositionOfMostRecent();
|
||||
|
||||
// This has to happen post-layout, so run it "in the future"
|
||||
post(new Runnable() {
|
||||
public void run() {
|
||||
// Make sure we're still not clobbering the transition-set values, since this
|
||||
// runnable launches asynchronously
|
||||
LayoutTransition transition = mLinearLayout.getLayoutTransition();
|
||||
if (transition == null || !transition.isRunning()) {
|
||||
scrollTo(mLastScrollPosition, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setAdapter(TaskDescriptionAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
mAdapter.registerDataSetObserver(new DataSetObserver() {
|
||||
public void onChanged() {
|
||||
update();
|
||||
}
|
||||
|
||||
public void onInvalidated() {
|
||||
update();
|
||||
}
|
||||
});
|
||||
DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
int childWidthMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
|
||||
int childheightMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
|
||||
View child = mAdapter.createView(mLinearLayout);
|
||||
child.measure(childWidthMeasureSpec, childheightMeasureSpec);
|
||||
mNumItemsInOneScreenful =
|
||||
(int) Math.ceil(dm.widthPixels / (double) child.getMeasuredWidth());
|
||||
addToRecycledViews(child);
|
||||
|
||||
for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
|
||||
addToRecycledViews(mAdapter.createView(mLinearLayout));
|
||||
}
|
||||
}
|
||||
|
||||
public int numItemsInOneScreenful() {
|
||||
return mNumItemsInOneScreenful;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutTransition(LayoutTransition transition) {
|
||||
// The layout transition applies to our embedded LinearLayout
|
||||
mLinearLayout.setLayoutTransition(transition);
|
||||
}
|
||||
|
||||
public void setCallback(RecentsCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
}
|
@ -1,813 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.LayoutTransition;
|
||||
import android.animation.TimeInterpolator;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.ActivityOptions;
|
||||
import android.app.TaskStackBuilder;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Shader.TileMode;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.view.ViewRootImpl;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ImageView.ScaleType;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.BaseStatusBar;
|
||||
import com.android.systemui.statusbar.StatusBarPanel;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
|
||||
StatusBarPanel, Animator.AnimatorListener {
|
||||
static final String TAG = "RecentsPanelView";
|
||||
static final boolean DEBUG = PhoneStatusBar.DEBUG || false;
|
||||
private PopupMenu mPopup;
|
||||
private View mRecentsScrim;
|
||||
private View mRecentsNoApps;
|
||||
private RecentsScrollView mRecentsContainer;
|
||||
|
||||
private boolean mShowing;
|
||||
private boolean mWaitingToShow;
|
||||
private ViewHolder mItemToAnimateInWhenWindowAnimationIsFinished;
|
||||
private boolean mAnimateIconOfFirstTask;
|
||||
private boolean mWaitingForWindowAnimation;
|
||||
private long mWindowAnimationStartTime;
|
||||
private boolean mCallUiHiddenBeforeNextReload;
|
||||
|
||||
private RecentTasksLoader mRecentTasksLoader;
|
||||
private ArrayList<TaskDescription> mRecentTaskDescriptions;
|
||||
private TaskDescriptionAdapter mListAdapter;
|
||||
private int mThumbnailWidth;
|
||||
private boolean mFitThumbnailToXY;
|
||||
private int mRecentItemLayoutId;
|
||||
private boolean mHighEndGfx;
|
||||
|
||||
public static interface RecentsScrollView {
|
||||
public int numItemsInOneScreenful();
|
||||
public void setAdapter(TaskDescriptionAdapter adapter);
|
||||
public void setCallback(RecentsCallback callback);
|
||||
public void setMinSwipeAlpha(float minAlpha);
|
||||
public View findViewForTask(int persistentTaskId);
|
||||
public void drawFadedEdges(Canvas c, int left, int right, int top, int bottom);
|
||||
public void setOnScrollListener(Runnable listener);
|
||||
}
|
||||
|
||||
private final class OnLongClickDelegate implements View.OnLongClickListener {
|
||||
View mOtherView;
|
||||
OnLongClickDelegate(View other) {
|
||||
mOtherView = other;
|
||||
}
|
||||
public boolean onLongClick(View v) {
|
||||
return mOtherView.performLongClick();
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ final static class ViewHolder {
|
||||
View thumbnailView;
|
||||
ImageView thumbnailViewImage;
|
||||
Drawable thumbnailViewDrawable;
|
||||
ImageView iconView;
|
||||
TextView labelView;
|
||||
TextView descriptionView;
|
||||
View calloutLine;
|
||||
TaskDescription taskDescription;
|
||||
boolean loadedThumbnailAndIcon;
|
||||
}
|
||||
|
||||
/* package */ final class TaskDescriptionAdapter extends BaseAdapter {
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
public TaskDescriptionAdapter(Context context) {
|
||||
mInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return mRecentTaskDescriptions != null ? mRecentTaskDescriptions.size() : 0;
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return position; // we only need the index
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return position; // we just need something unique for this position
|
||||
}
|
||||
|
||||
public View createView(ViewGroup parent) {
|
||||
View convertView = mInflater.inflate(mRecentItemLayoutId, parent, false);
|
||||
ViewHolder holder = new ViewHolder();
|
||||
holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
|
||||
holder.thumbnailViewImage =
|
||||
(ImageView) convertView.findViewById(R.id.app_thumbnail_image);
|
||||
// If we set the default thumbnail now, we avoid an onLayout when we update
|
||||
// the thumbnail later (if they both have the same dimensions)
|
||||
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
|
||||
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
|
||||
holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
|
||||
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
|
||||
holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
|
||||
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
|
||||
|
||||
convertView.setTag(holder);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = createView(parent);
|
||||
}
|
||||
final ViewHolder holder = (ViewHolder) convertView.getTag();
|
||||
|
||||
// index is reverse since most recent appears at the bottom...
|
||||
final int index = mRecentTaskDescriptions.size() - position - 1;
|
||||
|
||||
final TaskDescription td = mRecentTaskDescriptions.get(index);
|
||||
|
||||
holder.labelView.setText(td.getLabel());
|
||||
holder.thumbnailView.setContentDescription(td.getLabel());
|
||||
holder.loadedThumbnailAndIcon = td.isLoaded();
|
||||
if (td.isLoaded()) {
|
||||
updateThumbnail(holder, td.getThumbnail(), true, false);
|
||||
updateIcon(holder, td.getIcon(), true, false);
|
||||
}
|
||||
if (index == 0) {
|
||||
if (mAnimateIconOfFirstTask) {
|
||||
ViewHolder oldHolder = mItemToAnimateInWhenWindowAnimationIsFinished;
|
||||
if (oldHolder != null) {
|
||||
oldHolder.iconView.setAlpha(1f);
|
||||
oldHolder.iconView.setTranslationX(0f);
|
||||
oldHolder.iconView.setTranslationY(0f);
|
||||
oldHolder.labelView.setAlpha(1f);
|
||||
oldHolder.labelView.setTranslationX(0f);
|
||||
oldHolder.labelView.setTranslationY(0f);
|
||||
if (oldHolder.calloutLine != null) {
|
||||
oldHolder.calloutLine.setAlpha(1f);
|
||||
oldHolder.calloutLine.setTranslationX(0f);
|
||||
oldHolder.calloutLine.setTranslationY(0f);
|
||||
}
|
||||
}
|
||||
mItemToAnimateInWhenWindowAnimationIsFinished = holder;
|
||||
int translation = -getResources().getDimensionPixelSize(
|
||||
R.dimen.status_bar_recents_app_icon_translate_distance);
|
||||
final Configuration config = getResources().getConfiguration();
|
||||
if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
|
||||
translation = -translation;
|
||||
}
|
||||
holder.iconView.setAlpha(0f);
|
||||
holder.iconView.setTranslationX(translation);
|
||||
holder.labelView.setAlpha(0f);
|
||||
holder.labelView.setTranslationX(translation);
|
||||
holder.calloutLine.setAlpha(0f);
|
||||
holder.calloutLine.setTranslationX(translation);
|
||||
} else {
|
||||
holder.iconView.setAlpha(0f);
|
||||
holder.iconView.setTranslationY(translation);
|
||||
}
|
||||
if (!mWaitingForWindowAnimation) {
|
||||
animateInIconOfFirstTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
holder.thumbnailView.setTag(td);
|
||||
holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
|
||||
holder.taskDescription = td;
|
||||
return convertView;
|
||||
}
|
||||
|
||||
public void recycleView(View v) {
|
||||
ViewHolder holder = (ViewHolder) v.getTag();
|
||||
updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
|
||||
holder.iconView.setImageDrawable(mRecentTasksLoader.getDefaultIcon());
|
||||
holder.iconView.setVisibility(INVISIBLE);
|
||||
holder.iconView.animate().cancel();
|
||||
holder.labelView.setText(null);
|
||||
holder.labelView.animate().cancel();
|
||||
holder.thumbnailView.setContentDescription(null);
|
||||
holder.thumbnailView.setTag(null);
|
||||
holder.thumbnailView.setOnLongClickListener(null);
|
||||
holder.thumbnailView.setVisibility(INVISIBLE);
|
||||
holder.iconView.setAlpha(1f);
|
||||
holder.iconView.setTranslationX(0f);
|
||||
holder.iconView.setTranslationY(0f);
|
||||
holder.labelView.setAlpha(1f);
|
||||
holder.labelView.setTranslationX(0f);
|
||||
holder.labelView.setTranslationY(0f);
|
||||
if (holder.calloutLine != null) {
|
||||
holder.calloutLine.setAlpha(1f);
|
||||
holder.calloutLine.setTranslationX(0f);
|
||||
holder.calloutLine.setTranslationY(0f);
|
||||
holder.calloutLine.animate().cancel();
|
||||
}
|
||||
holder.taskDescription = null;
|
||||
holder.loadedThumbnailAndIcon = false;
|
||||
}
|
||||
}
|
||||
|
||||
public RecentsPanelView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public RecentsPanelView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
updateValuesFromResources();
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecentsPanelView,
|
||||
defStyle, 0);
|
||||
|
||||
mRecentItemLayoutId = a.getResourceId(R.styleable.RecentsPanelView_recentItemLayout, 0);
|
||||
mRecentTasksLoader = RecentTasksLoader.getInstance(context);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public int numItemsInOneScreenful() {
|
||||
return mRecentsContainer.numItemsInOneScreenful();
|
||||
}
|
||||
|
||||
private boolean pointInside(int x, int y, View v) {
|
||||
final int l = v.getLeft();
|
||||
final int r = v.getRight();
|
||||
final int t = v.getTop();
|
||||
final int b = v.getBottom();
|
||||
return x >= l && x < r && y >= t && y < b;
|
||||
}
|
||||
|
||||
public boolean isInContentArea(int x, int y) {
|
||||
return pointInside(x, y, (View) mRecentsContainer);
|
||||
}
|
||||
|
||||
public void show(boolean show) {
|
||||
show(show, null, false, false);
|
||||
}
|
||||
|
||||
public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
|
||||
boolean firstScreenful, boolean animateIconOfFirstTask) {
|
||||
if (show && mCallUiHiddenBeforeNextReload) {
|
||||
onUiHidden();
|
||||
recentTaskDescriptions = null;
|
||||
mAnimateIconOfFirstTask = false;
|
||||
mWaitingForWindowAnimation = false;
|
||||
} else {
|
||||
mAnimateIconOfFirstTask = animateIconOfFirstTask;
|
||||
mWaitingForWindowAnimation = animateIconOfFirstTask;
|
||||
}
|
||||
if (show) {
|
||||
mWaitingToShow = true;
|
||||
refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
|
||||
showIfReady();
|
||||
} else {
|
||||
showImpl(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void showIfReady() {
|
||||
// mWaitingToShow => there was a touch up on the recents button
|
||||
// mRecentTaskDescriptions != null => we've created views for the first screenful of items
|
||||
if (mWaitingToShow && mRecentTaskDescriptions != null) {
|
||||
showImpl(true);
|
||||
}
|
||||
}
|
||||
|
||||
static void sendCloseSystemWindows(Context context, String reason) {
|
||||
if (ActivityManagerNative.isSystemReady()) {
|
||||
try {
|
||||
ActivityManagerNative.getDefault().closeSystemDialogs(reason);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showImpl(boolean show) {
|
||||
sendCloseSystemWindows(getContext(), BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
|
||||
|
||||
mShowing = show;
|
||||
|
||||
if (show) {
|
||||
// if there are no apps, bring up a "No recent apps" message
|
||||
boolean noApps = mRecentTaskDescriptions != null
|
||||
&& (mRecentTaskDescriptions.size() == 0);
|
||||
mRecentsNoApps.setAlpha(1f);
|
||||
mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
|
||||
|
||||
onAnimationEnd(null);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
requestFocus();
|
||||
} else {
|
||||
mWaitingToShow = false;
|
||||
// call onAnimationEnd() and clearRecentTasksList() in onUiHidden()
|
||||
mCallUiHiddenBeforeNextReload = true;
|
||||
if (mPopup != null) {
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAttachedToWindow () {
|
||||
super.onAttachedToWindow();
|
||||
final ViewRootImpl root = getViewRootImpl();
|
||||
if (root != null) {
|
||||
root.setDrawDuringWindowsAnimating(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void onUiHidden() {
|
||||
mCallUiHiddenBeforeNextReload = false;
|
||||
if (!mShowing && mRecentTaskDescriptions != null) {
|
||||
onAnimationEnd(null);
|
||||
clearRecentTasksList();
|
||||
}
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
((RecentsActivity) getContext()).dismissAndGoHome();
|
||||
}
|
||||
|
||||
public void dismissAndGoBack() {
|
||||
((RecentsActivity) getContext()).dismissAndGoBack();
|
||||
}
|
||||
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mShowing) {
|
||||
final LayoutTransition transitioner = new LayoutTransition();
|
||||
((ViewGroup)mRecentsContainer).setLayoutTransition(transitioner);
|
||||
createCustomAnimations(transitioner);
|
||||
} else {
|
||||
((ViewGroup)mRecentsContainer).setLayoutTransition(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchHoverEvent(MotionEvent event) {
|
||||
// Ignore hover events outside of this panel bounds since such events
|
||||
// generate spurious accessibility events with the panel content when
|
||||
// tapping outside of it, thus confusing the user.
|
||||
final int x = (int) event.getX();
|
||||
final int y = (int) event.getY();
|
||||
if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
|
||||
return super.dispatchHoverEvent(event);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the panel is showing, or, if it's animating, whether it will be
|
||||
* when the animation is done.
|
||||
*/
|
||||
public boolean isShowing() {
|
||||
return mShowing;
|
||||
}
|
||||
|
||||
public void setRecentTasksLoader(RecentTasksLoader loader) {
|
||||
mRecentTasksLoader = loader;
|
||||
}
|
||||
|
||||
public void updateValuesFromResources() {
|
||||
final Resources res = getContext().getResources();
|
||||
mThumbnailWidth = Math.round(res.getDimension(R.dimen.status_bar_recents_thumbnail_width));
|
||||
mFitThumbnailToXY = res.getBoolean(R.bool.config_recents_thumbnail_image_fits_to_xy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mRecentsContainer = (RecentsScrollView) findViewById(R.id.recents_container);
|
||||
mRecentsContainer.setOnScrollListener(new Runnable() {
|
||||
public void run() {
|
||||
// need to redraw the faded edges
|
||||
invalidate();
|
||||
}
|
||||
});
|
||||
mListAdapter = new TaskDescriptionAdapter(getContext());
|
||||
mRecentsContainer.setAdapter(mListAdapter);
|
||||
mRecentsContainer.setCallback(this);
|
||||
|
||||
mRecentsScrim = findViewById(R.id.recents_bg_protect);
|
||||
mRecentsNoApps = findViewById(R.id.recents_no_apps);
|
||||
|
||||
if (mRecentsScrim != null) {
|
||||
mHighEndGfx = ActivityManager.isHighEndGfx();
|
||||
if (!mHighEndGfx) {
|
||||
mRecentsScrim.setBackground(null);
|
||||
} else if (mRecentsScrim.getBackground() instanceof BitmapDrawable) {
|
||||
// In order to save space, we make the background texture repeat in the Y direction
|
||||
((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setMinSwipeAlpha(float minAlpha) {
|
||||
mRecentsContainer.setMinSwipeAlpha(minAlpha);
|
||||
}
|
||||
|
||||
private void createCustomAnimations(LayoutTransition transitioner) {
|
||||
transitioner.setDuration(200);
|
||||
transitioner.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
|
||||
transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
|
||||
}
|
||||
|
||||
private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) {
|
||||
if (icon != null) {
|
||||
h.iconView.setImageDrawable(icon);
|
||||
if (show && h.iconView.getVisibility() != View.VISIBLE) {
|
||||
if (anim) {
|
||||
h.iconView.setAnimation(
|
||||
AnimationUtils.loadAnimation(getContext(), R.anim.recent_appear));
|
||||
}
|
||||
h.iconView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateThumbnail(ViewHolder h, Drawable thumbnail, boolean show, boolean anim) {
|
||||
if (thumbnail != null) {
|
||||
// Should remove the default image in the frame
|
||||
// that this now covers, to improve scrolling speed.
|
||||
// That can't be done until the anim is complete though.
|
||||
h.thumbnailViewImage.setImageDrawable(thumbnail);
|
||||
|
||||
// scale the image to fill the full width of the ImageView. do this only if
|
||||
// we haven't set a bitmap before, or if the bitmap size has changed
|
||||
if (h.thumbnailViewDrawable == null ||
|
||||
h.thumbnailViewDrawable.getIntrinsicWidth() != thumbnail.getIntrinsicWidth() ||
|
||||
h.thumbnailViewDrawable.getIntrinsicHeight() != thumbnail.getIntrinsicHeight()) {
|
||||
if (mFitThumbnailToXY) {
|
||||
h.thumbnailViewImage.setScaleType(ScaleType.FIT_XY);
|
||||
} else {
|
||||
Matrix scaleMatrix = new Matrix();
|
||||
float scale = mThumbnailWidth / (float) thumbnail.getIntrinsicWidth();
|
||||
scaleMatrix.setScale(scale, scale);
|
||||
h.thumbnailViewImage.setScaleType(ScaleType.MATRIX);
|
||||
h.thumbnailViewImage.setImageMatrix(scaleMatrix);
|
||||
}
|
||||
}
|
||||
if (show && h.thumbnailView.getVisibility() != View.VISIBLE) {
|
||||
if (anim) {
|
||||
h.thumbnailView.setAnimation(
|
||||
AnimationUtils.loadAnimation(getContext(), R.anim.recent_appear));
|
||||
}
|
||||
h.thumbnailView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
h.thumbnailViewDrawable = thumbnail;
|
||||
}
|
||||
}
|
||||
|
||||
void onTaskThumbnailLoaded(TaskDescription td) {
|
||||
synchronized (td) {
|
||||
if (mRecentsContainer != null) {
|
||||
ViewGroup container = (ViewGroup) mRecentsContainer;
|
||||
if (container instanceof RecentsScrollView) {
|
||||
container = (ViewGroup) container.findViewById(
|
||||
R.id.recents_linear_layout);
|
||||
}
|
||||
// Look for a view showing this thumbnail, to update.
|
||||
for (int i=0; i < container.getChildCount(); i++) {
|
||||
View v = container.getChildAt(i);
|
||||
if (v.getTag() instanceof ViewHolder) {
|
||||
ViewHolder h = (ViewHolder)v.getTag();
|
||||
if (!h.loadedThumbnailAndIcon && h.taskDescription == td) {
|
||||
// only fade in the thumbnail if recents is already visible-- we
|
||||
// show it immediately otherwise
|
||||
//boolean animateShow = mShowing &&
|
||||
// mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD;
|
||||
boolean animateShow = false;
|
||||
updateIcon(h, td.getIcon(), true, animateShow);
|
||||
updateThumbnail(h, td.getThumbnail(), true, animateShow);
|
||||
h.loadedThumbnailAndIcon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
showIfReady();
|
||||
}
|
||||
|
||||
private void animateInIconOfFirstTask() {
|
||||
if (mItemToAnimateInWhenWindowAnimationIsFinished != null &&
|
||||
!mRecentTasksLoader.isFirstScreenful()) {
|
||||
int timeSinceWindowAnimation =
|
||||
(int) (System.currentTimeMillis() - mWindowAnimationStartTime);
|
||||
final int minStartDelay = 150;
|
||||
final int startDelay = Math.max(0, Math.min(
|
||||
minStartDelay - timeSinceWindowAnimation, minStartDelay));
|
||||
final int duration = 250;
|
||||
final ViewHolder holder = mItemToAnimateInWhenWindowAnimationIsFinished;
|
||||
final TimeInterpolator cubic = new DecelerateInterpolator(1.5f);
|
||||
FirstFrameAnimatorHelper.initializeDrawListener(holder.iconView);
|
||||
for (View v :
|
||||
new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
|
||||
if (v != null) {
|
||||
ViewPropertyAnimator vpa = v.animate().translationX(0).translationY(0)
|
||||
.alpha(1f).setStartDelay(startDelay)
|
||||
.setDuration(duration).setInterpolator(cubic);
|
||||
FirstFrameAnimatorHelper h = new FirstFrameAnimatorHelper(vpa, v);
|
||||
}
|
||||
}
|
||||
mItemToAnimateInWhenWindowAnimationIsFinished = null;
|
||||
mAnimateIconOfFirstTask = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void onWindowAnimationStart() {
|
||||
mWaitingForWindowAnimation = false;
|
||||
mWindowAnimationStartTime = System.currentTimeMillis();
|
||||
animateInIconOfFirstTask();
|
||||
}
|
||||
|
||||
public void clearRecentTasksList() {
|
||||
// Clear memory used by screenshots
|
||||
if (mRecentTaskDescriptions != null) {
|
||||
mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(this);
|
||||
onTaskLoadingCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
public void onTaskLoadingCancelled() {
|
||||
// Gets called by RecentTasksLoader when it's cancelled
|
||||
if (mRecentTaskDescriptions != null) {
|
||||
mRecentTaskDescriptions = null;
|
||||
mListAdapter.notifyDataSetInvalidated();
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshViews() {
|
||||
mListAdapter.notifyDataSetInvalidated();
|
||||
updateUiElements();
|
||||
showIfReady();
|
||||
}
|
||||
|
||||
public void refreshRecentTasksList() {
|
||||
refreshRecentTasksList(null, false);
|
||||
}
|
||||
|
||||
private void refreshRecentTasksList(
|
||||
ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
|
||||
if (mRecentTaskDescriptions == null && recentTasksList != null) {
|
||||
onTasksLoaded(recentTasksList, firstScreenful);
|
||||
} else {
|
||||
mRecentTasksLoader.loadTasksInBackground();
|
||||
}
|
||||
}
|
||||
|
||||
public void onTasksLoaded(ArrayList<TaskDescription> tasks, boolean firstScreenful) {
|
||||
if (mRecentTaskDescriptions == null) {
|
||||
mRecentTaskDescriptions = new ArrayList<TaskDescription>(tasks);
|
||||
} else {
|
||||
mRecentTaskDescriptions.addAll(tasks);
|
||||
}
|
||||
if (((RecentsActivity) getContext()).isActivityShowing()) {
|
||||
refreshViews();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUiElements() {
|
||||
final int items = mRecentTaskDescriptions != null
|
||||
? mRecentTaskDescriptions.size() : 0;
|
||||
|
||||
((View) mRecentsContainer).setVisibility(items > 0 ? View.VISIBLE : View.GONE);
|
||||
|
||||
// Set description for accessibility
|
||||
int numRecentApps = mRecentTaskDescriptions != null
|
||||
? mRecentTaskDescriptions.size() : 0;
|
||||
String recentAppsAccessibilityDescription;
|
||||
if (numRecentApps == 0) {
|
||||
recentAppsAccessibilityDescription =
|
||||
getResources().getString(R.string.status_bar_no_recent_apps);
|
||||
} else {
|
||||
recentAppsAccessibilityDescription = getResources().getQuantityString(
|
||||
R.plurals.status_bar_accessibility_recent_apps, numRecentApps, numRecentApps);
|
||||
}
|
||||
setContentDescription(recentAppsAccessibilityDescription);
|
||||
}
|
||||
|
||||
public boolean simulateClick(int persistentTaskId) {
|
||||
View v = mRecentsContainer.findViewForTask(persistentTaskId);
|
||||
if (v != null) {
|
||||
handleOnClick(v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void handleOnClick(View view) {
|
||||
ViewHolder holder = (ViewHolder) view.getTag();
|
||||
TaskDescription ad = holder.taskDescription;
|
||||
final Context context = view.getContext();
|
||||
final ActivityManager am = (ActivityManager)
|
||||
context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
|
||||
Bitmap bm = null;
|
||||
boolean usingDrawingCache = true;
|
||||
if (holder.thumbnailViewDrawable instanceof BitmapDrawable) {
|
||||
bm = ((BitmapDrawable) holder.thumbnailViewDrawable).getBitmap();
|
||||
if (bm.getWidth() == holder.thumbnailViewImage.getWidth() &&
|
||||
bm.getHeight() == holder.thumbnailViewImage.getHeight()) {
|
||||
usingDrawingCache = false;
|
||||
}
|
||||
}
|
||||
if (usingDrawingCache) {
|
||||
holder.thumbnailViewImage.setDrawingCacheEnabled(true);
|
||||
bm = holder.thumbnailViewImage.getDrawingCache();
|
||||
}
|
||||
Bundle opts = (bm == null) ?
|
||||
null :
|
||||
ActivityOptions.makeThumbnailScaleUpAnimation(
|
||||
holder.thumbnailViewImage, bm, 0, 0, null).toBundle();
|
||||
|
||||
show(false);
|
||||
if (ad.taskId >= 0) {
|
||||
// This is an active task; it should just go to the foreground.
|
||||
am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME,
|
||||
opts);
|
||||
} else {
|
||||
Intent intent = ad.intent;
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
|
||||
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
if (DEBUG) Log.v(TAG, "Starting activity " + intent);
|
||||
try {
|
||||
context.startActivityAsUser(intent, opts,
|
||||
new UserHandle(ad.userId));
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "Recents does not have the permission to launch " + intent, e);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "Error launching activity " + intent, e);
|
||||
}
|
||||
}
|
||||
if (usingDrawingCache) {
|
||||
holder.thumbnailViewImage.setDrawingCacheEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
handleOnClick(view);
|
||||
}
|
||||
|
||||
public void handleSwipe(View view) {
|
||||
TaskDescription ad = ((ViewHolder) view.getTag()).taskDescription;
|
||||
if (ad == null) {
|
||||
Log.v(TAG, "Not able to find activity description for swiped task; view=" + view +
|
||||
" tag=" + view.getTag());
|
||||
return;
|
||||
}
|
||||
if (DEBUG) Log.v(TAG, "Jettison " + ad.getLabel());
|
||||
mRecentTaskDescriptions.remove(ad);
|
||||
mRecentTasksLoader.remove(ad);
|
||||
|
||||
// Handled by widget containers to enable LayoutTransitions properly
|
||||
// mListAdapter.notifyDataSetChanged();
|
||||
|
||||
if (mRecentTaskDescriptions.size() == 0) {
|
||||
dismissAndGoBack();
|
||||
}
|
||||
|
||||
// Currently, either direction means the same thing, so ignore direction and remove
|
||||
// the task.
|
||||
final ActivityManager am = (ActivityManager)
|
||||
getContext().getSystemService(Context.ACTIVITY_SERVICE);
|
||||
if (am != null) {
|
||||
am.removeTask(ad.persistentTaskId);
|
||||
|
||||
// Accessibility feedback
|
||||
setContentDescription(
|
||||
getContext().getString(R.string.accessibility_recents_item_dismissed, ad.getLabel()));
|
||||
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
|
||||
setContentDescription(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void startApplicationDetailsActivity(String packageName, int userId) {
|
||||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
Uri.fromParts("package", packageName, null));
|
||||
intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
|
||||
TaskStackBuilder.create(getContext())
|
||||
.addNextIntentWithParentStack(intent).startActivities(null, new UserHandle(userId));
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (mPopup != null) {
|
||||
return true;
|
||||
} else {
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleLongPress(
|
||||
final View selectedView, final View anchorView, final View thumbnailView) {
|
||||
thumbnailView.setSelected(true);
|
||||
final PopupMenu popup =
|
||||
new PopupMenu(getContext(), anchorView == null ? selectedView : anchorView);
|
||||
mPopup = popup;
|
||||
popup.getMenuInflater().inflate(R.menu.recent_popup_menu, popup.getMenu());
|
||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
if (item.getItemId() == R.id.recent_remove_item) {
|
||||
((ViewGroup) mRecentsContainer).removeViewInLayout(selectedView);
|
||||
} else if (item.getItemId() == R.id.recent_inspect_item) {
|
||||
ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
|
||||
if (viewHolder != null) {
|
||||
final TaskDescription ad = viewHolder.taskDescription;
|
||||
startApplicationDetailsActivity(ad.packageName, ad.userId);
|
||||
show(false);
|
||||
} else {
|
||||
throw new IllegalStateException("Oops, no tag on view " + selectedView);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
|
||||
public void onDismiss(PopupMenu menu) {
|
||||
thumbnailView.setSelected(false);
|
||||
mPopup = null;
|
||||
}
|
||||
});
|
||||
popup.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
super.dispatchDraw(canvas);
|
||||
|
||||
int paddingLeft = getPaddingLeft();
|
||||
final boolean offsetRequired = isPaddingOffsetRequired();
|
||||
if (offsetRequired) {
|
||||
paddingLeft += getLeftPaddingOffset();
|
||||
}
|
||||
|
||||
int left = getScrollX() + paddingLeft;
|
||||
int right = left + getRight() - getLeft() - getPaddingRight() - paddingLeft;
|
||||
int top = getScrollY() + getFadeTop(offsetRequired);
|
||||
int bottom = top + getFadeHeight(offsetRequired);
|
||||
|
||||
if (offsetRequired) {
|
||||
right += getRightPaddingOffset();
|
||||
bottom += getBottomPaddingOffset();
|
||||
}
|
||||
mRecentsContainer.drawFadedEdges(canvas, left, right, top, bottom);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 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.systemui.recent;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class RecentsPreloadReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (RecentsActivity.PRELOAD_INTENT.equals(intent.getAction())) {
|
||||
RecentTasksLoader.getInstance(context).preloadRecentTasksList();
|
||||
} else if (RecentsActivity.CANCEL_PRELOAD_INTENT.equals(intent.getAction())){
|
||||
RecentTasksLoader.getInstance(context).cancelPreloadingRecentTasksList();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,401 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SwipeHelper;
|
||||
import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class RecentsVerticalScrollView extends ScrollView
|
||||
implements SwipeHelper.Callback, RecentsPanelView.RecentsScrollView {
|
||||
private static final String TAG = RecentsPanelView.TAG;
|
||||
private static final boolean DEBUG = RecentsPanelView.DEBUG;
|
||||
private LinearLayout mLinearLayout;
|
||||
private TaskDescriptionAdapter mAdapter;
|
||||
private RecentsCallback mCallback;
|
||||
protected int mLastScrollPosition;
|
||||
private SwipeHelper mSwipeHelper;
|
||||
private FadedEdgeDrawHelper mFadedEdgeDrawHelper;
|
||||
private HashSet<View> mRecycledViews;
|
||||
private int mNumItemsInOneScreenful;
|
||||
private Runnable mOnScrollListener;
|
||||
|
||||
public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, 0);
|
||||
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context);
|
||||
|
||||
mFadedEdgeDrawHelper = FadedEdgeDrawHelper.create(context, attrs, this, true);
|
||||
mRecycledViews = new HashSet<View>();
|
||||
}
|
||||
|
||||
public void setMinSwipeAlpha(float minAlpha) {
|
||||
mSwipeHelper.setMinSwipeProgress(minAlpha);
|
||||
}
|
||||
|
||||
private int scrollPositionOfMostRecent() {
|
||||
return mLinearLayout.getHeight() - getHeight() + getPaddingTop();
|
||||
}
|
||||
|
||||
private void addToRecycledViews(View v) {
|
||||
if (mRecycledViews.size() < mNumItemsInOneScreenful) {
|
||||
mRecycledViews.add(v);
|
||||
}
|
||||
}
|
||||
|
||||
public View findViewForTask(int persistentTaskId) {
|
||||
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
|
||||
View v = mLinearLayout.getChildAt(i);
|
||||
RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
|
||||
if (holder.taskDescription.persistentTaskId == persistentTaskId) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void update() {
|
||||
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
|
||||
View v = mLinearLayout.getChildAt(i);
|
||||
addToRecycledViews(v);
|
||||
mAdapter.recycleView(v);
|
||||
}
|
||||
LayoutTransition transitioner = getLayoutTransition();
|
||||
setLayoutTransition(null);
|
||||
|
||||
mLinearLayout.removeAllViews();
|
||||
|
||||
// Once we can clear the data associated with individual item views,
|
||||
// we can get rid of the removeAllViews() and the code below will
|
||||
// recycle them.
|
||||
Iterator<View> recycledViews = mRecycledViews.iterator();
|
||||
for (int i = 0; i < mAdapter.getCount(); i++) {
|
||||
View old = null;
|
||||
if (recycledViews.hasNext()) {
|
||||
old = recycledViews.next();
|
||||
recycledViews.remove();
|
||||
old.setVisibility(VISIBLE);
|
||||
}
|
||||
final View view = mAdapter.getView(i, old, mLinearLayout);
|
||||
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
mFadedEdgeDrawHelper.addViewCallback(view);
|
||||
}
|
||||
|
||||
OnTouchListener noOpListener = new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mCallback.dismiss();
|
||||
}
|
||||
});
|
||||
// We don't want a click sound when we dimiss recents
|
||||
view.setSoundEffectsEnabled(false);
|
||||
|
||||
OnClickListener launchAppListener = new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mCallback.handleOnClick(view);
|
||||
}
|
||||
};
|
||||
|
||||
RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag();
|
||||
final View thumbnailView = holder.thumbnailView;
|
||||
OnLongClickListener longClickListener = new OnLongClickListener() {
|
||||
public boolean onLongClick(View v) {
|
||||
final View anchorView = view.findViewById(R.id.app_description);
|
||||
mCallback.handleLongPress(view, anchorView, thumbnailView);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
thumbnailView.setClickable(true);
|
||||
thumbnailView.setOnClickListener(launchAppListener);
|
||||
thumbnailView.setOnLongClickListener(longClickListener);
|
||||
|
||||
// We don't want to dismiss recents if a user clicks on the app title
|
||||
// (we also don't want to launch the app either, though, because the
|
||||
// app title is a small target and doesn't have great click feedback)
|
||||
final View appTitle = view.findViewById(R.id.app_label);
|
||||
appTitle.setContentDescription(" ");
|
||||
appTitle.setOnTouchListener(noOpListener);
|
||||
final View calloutLine = view.findViewById(R.id.recents_callout_line);
|
||||
if (calloutLine != null) {
|
||||
calloutLine.setOnTouchListener(noOpListener);
|
||||
}
|
||||
|
||||
mLinearLayout.addView(view);
|
||||
}
|
||||
setLayoutTransition(transitioner);
|
||||
|
||||
// Scroll to end after initial layout.
|
||||
final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() {
|
||||
public void onGlobalLayout() {
|
||||
mLastScrollPosition = scrollPositionOfMostRecent();
|
||||
scrollTo(0, mLastScrollPosition);
|
||||
final ViewTreeObserver observer = getViewTreeObserver();
|
||||
if (observer.isAlive()) {
|
||||
observer.removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(updateScroll);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewInLayout(final View view) {
|
||||
dismissChild(view);
|
||||
}
|
||||
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
|
||||
return mSwipeHelper.onInterceptTouchEvent(ev) ||
|
||||
super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
return mSwipeHelper.onTouchEvent(ev) ||
|
||||
super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
public boolean canChildBeDismissed(View v) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAntiFalsingNeeded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFalsingThresholdFactor() {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
public void dismissChild(View v) {
|
||||
mSwipeHelper.dismissChild(v, 0);
|
||||
}
|
||||
|
||||
public void onChildDismissed(View v) {
|
||||
addToRecycledViews(v);
|
||||
mLinearLayout.removeView(v);
|
||||
mCallback.handleSwipe(v);
|
||||
// Restore the alpha/translation parameters to what they were before swiping
|
||||
// (for when these items are recycled)
|
||||
View contentView = getChildContentView(v);
|
||||
contentView.setAlpha(1f);
|
||||
contentView.setTranslationX(0);
|
||||
}
|
||||
|
||||
public void onBeginDrag(View v) {
|
||||
// We do this so the underlying ScrollView knows that it won't get
|
||||
// the chance to intercept events anymore
|
||||
requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
|
||||
public void onDragCancelled(View v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildSnappedBack(View animView) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateSwipeProgress(View animView, boolean dismissable, float swipeProgress) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public View getChildAtPosition(MotionEvent ev) {
|
||||
final float x = ev.getX() + getScrollX();
|
||||
final float y = ev.getY() + getScrollY();
|
||||
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
|
||||
View item = mLinearLayout.getChildAt(i);
|
||||
if (item.getVisibility() == View.VISIBLE
|
||||
&& x >= item.getLeft() && x < item.getRight()
|
||||
&& y >= item.getTop() && y < item.getBottom()) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public View getChildContentView(View v) {
|
||||
return v.findViewById(R.id.recent_item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawFadedEdges(Canvas canvas, int left, int right, int top, int bottom) {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
final boolean offsetRequired = isPaddingOffsetRequired();
|
||||
mFadedEdgeDrawHelper.drawCallback(canvas,
|
||||
left, right, top + getFadeTop(offsetRequired), bottom, getScrollX(), getScrollY(),
|
||||
getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
|
||||
0, 0, getPaddingTop());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
|
||||
super.onScrollChanged(l, t, oldl, oldt);
|
||||
if (mOnScrollListener != null) {
|
||||
mOnScrollListener.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnScrollListener(Runnable listener) {
|
||||
mOnScrollListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVerticalFadingEdgeLength() {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
return mFadedEdgeDrawHelper.getVerticalFadingEdgeLength();
|
||||
} else {
|
||||
return super.getVerticalFadingEdgeLength();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHorizontalFadingEdgeLength() {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
return mFadedEdgeDrawHelper.getHorizontalFadingEdgeLength();
|
||||
} else {
|
||||
return super.getHorizontalFadingEdgeLength();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
setScrollbarFadingEnabled(true);
|
||||
mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
|
||||
final int leftPadding = getContext().getResources()
|
||||
.getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
|
||||
setOverScrollEffectPadding(leftPadding, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
if (mFadedEdgeDrawHelper != null) {
|
||||
mFadedEdgeDrawHelper.onAttachedToWindowCallback(mLinearLayout, isHardwareAccelerated());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
float densityScale = getResources().getDisplayMetrics().density;
|
||||
mSwipeHelper.setDensityScale(densityScale);
|
||||
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
|
||||
mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
|
||||
}
|
||||
|
||||
private void setOverScrollEffectPadding(int leftPadding, int i) {
|
||||
// TODO Add to (Vertical)ScrollView
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
// Skip this work if a transition is running; it sets the scroll values independently
|
||||
// and should not have those animated values clobbered by this logic
|
||||
LayoutTransition transition = mLinearLayout.getLayoutTransition();
|
||||
if (transition != null && transition.isRunning()) {
|
||||
return;
|
||||
}
|
||||
// Keep track of the last visible item in the list so we can restore it
|
||||
// to the bottom when the orientation changes.
|
||||
mLastScrollPosition = scrollPositionOfMostRecent();
|
||||
|
||||
// This has to happen post-layout, so run it "in the future"
|
||||
post(new Runnable() {
|
||||
public void run() {
|
||||
// Make sure we're still not clobbering the transition-set values, since this
|
||||
// runnable launches asynchronously
|
||||
LayoutTransition transition = mLinearLayout.getLayoutTransition();
|
||||
if (transition == null || !transition.isRunning()) {
|
||||
scrollTo(0, mLastScrollPosition);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setAdapter(TaskDescriptionAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
mAdapter.registerDataSetObserver(new DataSetObserver() {
|
||||
public void onChanged() {
|
||||
update();
|
||||
}
|
||||
|
||||
public void onInvalidated() {
|
||||
update();
|
||||
}
|
||||
});
|
||||
|
||||
DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
int childWidthMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST);
|
||||
int childheightMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST);
|
||||
View child = mAdapter.createView(mLinearLayout);
|
||||
child.measure(childWidthMeasureSpec, childheightMeasureSpec);
|
||||
mNumItemsInOneScreenful =
|
||||
(int) Math.ceil(dm.heightPixels / (double) child.getMeasuredHeight());
|
||||
addToRecycledViews(child);
|
||||
|
||||
for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) {
|
||||
addToRecycledViews(mAdapter.createView(mLinearLayout));
|
||||
}
|
||||
}
|
||||
|
||||
public int numItemsInOneScreenful() {
|
||||
return mNumItemsInOneScreenful;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutTransition(LayoutTransition transition) {
|
||||
// The layout transition applies to our embedded LinearLayout
|
||||
mLinearLayout.setLayoutTransition(transition);
|
||||
}
|
||||
|
||||
public void setCallback(RecentsCallback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.systemui.recent;
|
||||
|
||||
import android.os.UserHandle;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
public final class TaskDescription {
|
||||
final ResolveInfo resolveInfo;
|
||||
final int taskId; // application task id for curating apps
|
||||
final int persistentTaskId; // persistent id
|
||||
final Intent intent; // launch intent for application
|
||||
final String packageName; // used to override animations (see onClick())
|
||||
final CharSequence description;
|
||||
final int userId;
|
||||
|
||||
private Drawable mThumbnail; // generated by Activity.onCreateThumbnail()
|
||||
private Drawable mIcon; // application package icon
|
||||
private CharSequence mLabel; // application package label
|
||||
private boolean mLoaded;
|
||||
|
||||
public TaskDescription(int _taskId, int _persistentTaskId,
|
||||
ResolveInfo _resolveInfo, Intent _intent,
|
||||
String _packageName, CharSequence _description, int _userId) {
|
||||
resolveInfo = _resolveInfo;
|
||||
intent = _intent;
|
||||
taskId = _taskId;
|
||||
persistentTaskId = _persistentTaskId;
|
||||
|
||||
description = _description;
|
||||
packageName = _packageName;
|
||||
userId = _userId;
|
||||
}
|
||||
|
||||
public TaskDescription() {
|
||||
resolveInfo = null;
|
||||
intent = null;
|
||||
taskId = -1;
|
||||
persistentTaskId = -1;
|
||||
|
||||
description = null;
|
||||
packageName = null;
|
||||
userId = UserHandle.USER_NULL;
|
||||
}
|
||||
|
||||
public void setLoaded(boolean loaded) {
|
||||
mLoaded = loaded;
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return mLoaded;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return resolveInfo == null;
|
||||
}
|
||||
|
||||
// mark all these as locked?
|
||||
public CharSequence getLabel() {
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public void setLabel(CharSequence label) {
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public Drawable getIcon() {
|
||||
return mIcon;
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
mIcon = icon;
|
||||
}
|
||||
|
||||
public void setThumbnail(Drawable thumbnail) {
|
||||
mThumbnail = thumbnail;
|
||||
}
|
||||
|
||||
public Drawable getThumbnail() {
|
||||
return mThumbnail;
|
||||
}
|
||||
}
|
@ -37,10 +37,12 @@ import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Pair;
|
||||
import android.view.Display;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.RecentsComponent;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.recents.misc.Console;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
|
||||
@ -69,7 +71,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@interface ProxyFromAnyToPrimaryUser {}
|
||||
|
||||
/** A proxy implementation for the recents component */
|
||||
public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener {
|
||||
public class Recents extends SystemUI
|
||||
implements ActivityOptions.OnAnimationStartedListener, RecentsComponent {
|
||||
|
||||
final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab";
|
||||
final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey";
|
||||
@ -149,8 +152,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
|
||||
static RecentsComponent.Callbacks sRecentsComponentCallbacks;
|
||||
static RecentsTaskLoadPlan sInstanceLoadPlan;
|
||||
static Recents sInstance;
|
||||
|
||||
Context mContext;
|
||||
LayoutInflater mInflater;
|
||||
SystemServicesProxy mSystemServicesProxy;
|
||||
Handler mHandler;
|
||||
@ -178,28 +181,22 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
boolean mTriggeredFromAltTab;
|
||||
long mLastToggleTime;
|
||||
|
||||
public AlternateRecentsComponent(Context context) {
|
||||
RecentsTaskLoader.initialize(context);
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mContext = context;
|
||||
mSystemServicesProxy = new SystemServicesProxy(context);
|
||||
mHandler = new Handler();
|
||||
mTaskStackBounds = new Rect();
|
||||
public Recents() {
|
||||
}
|
||||
|
||||
// Register the task stack listener
|
||||
mTaskStackListener = new TaskStackListenerImpl(mHandler);
|
||||
mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
|
||||
|
||||
// Only the owner has the callback to update the SysUI visibility flags, so all non-owner
|
||||
// instances of AlternateRecentsComponent needs to notify the owner when the visibility
|
||||
// changes.
|
||||
if (mSystemServicesProxy.isForegroundUserOwner()) {
|
||||
mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(AlternateRecentsComponent.ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
|
||||
mContext.registerReceiverAsUser(mProxyBroadcastReceiver, UserHandle.CURRENT, filter,
|
||||
null, mHandler);
|
||||
/**
|
||||
* Gets the singleton instance and starts it if needed. On the primary user on the device, this
|
||||
* component gets started as a normal {@link SystemUI} component. On a secondary user, this
|
||||
* lifecycle doesn't exist, so we need to start it manually here if needed.
|
||||
*/
|
||||
public static Recents getInstanceAndStartIfNeeded(Context ctx) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new Recents();
|
||||
sInstance.mContext = ctx;
|
||||
sInstance.start();
|
||||
sInstance.onBootCompleted();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/** Creates a new broadcast intent */
|
||||
@ -213,7 +210,32 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
|
||||
/** Initializes the Recents. */
|
||||
@ProxyFromPrimaryToCurrentUser
|
||||
public void onStart() {
|
||||
@Override
|
||||
public void start() {
|
||||
if (sInstance == null) {
|
||||
sInstance = this;
|
||||
}
|
||||
RecentsTaskLoader.initialize(mContext);
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
mSystemServicesProxy = new SystemServicesProxy(mContext);
|
||||
mHandler = new Handler();
|
||||
mTaskStackBounds = new Rect();
|
||||
|
||||
// Register the task stack listener
|
||||
mTaskStackListener = new TaskStackListenerImpl(mHandler);
|
||||
mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
|
||||
|
||||
// Only the owner has the callback to update the SysUI visibility flags, so all non-owner
|
||||
// instances of AlternateRecentsComponent needs to notify the owner when the visibility
|
||||
// changes.
|
||||
if (mSystemServicesProxy.isForegroundUserOwner()) {
|
||||
mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Recents.ACTION_PROXY_NOTIFY_RECENTS_VISIBLITY_TO_OWNER);
|
||||
mContext.registerReceiverAsUser(mProxyBroadcastReceiver, UserHandle.CURRENT, filter,
|
||||
null, mHandler);
|
||||
}
|
||||
|
||||
// Initialize some static datastructures
|
||||
TaskStackViewLayoutAlgorithm.initializeCurve();
|
||||
// Load the header bar layout
|
||||
@ -229,17 +251,20 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
|
||||
launchOpts.onlyLoadForCache = true;
|
||||
loader.loadTasks(mContext, plan, launchOpts);
|
||||
putComponent(Recents.class, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootCompleted() {
|
||||
mBootCompleted = true;
|
||||
}
|
||||
|
||||
/** Shows the Recents. */
|
||||
@ProxyFromPrimaryToCurrentUser
|
||||
public void onShowRecents(boolean triggeredFromAltTab) {
|
||||
@Override
|
||||
public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
|
||||
if (mSystemServicesProxy.isForegroundUserOwner()) {
|
||||
showRecents(triggeredFromAltTab);
|
||||
showRecentsInternal(triggeredFromAltTab);
|
||||
} else {
|
||||
Intent intent = createLocalBroadcastIntent(mContext,
|
||||
RecentsUserEventProxyReceiver.ACTION_PROXY_SHOW_RECENTS_TO_USER);
|
||||
@ -247,7 +272,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
|
||||
}
|
||||
}
|
||||
void showRecents(boolean triggeredFromAltTab) {
|
||||
|
||||
void showRecentsInternal(boolean triggeredFromAltTab) {
|
||||
mTriggeredFromAltTab = triggeredFromAltTab;
|
||||
|
||||
try {
|
||||
@ -259,9 +285,10 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
|
||||
/** Hides the Recents. */
|
||||
@ProxyFromPrimaryToCurrentUser
|
||||
public void onHideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
|
||||
@Override
|
||||
public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
|
||||
if (mSystemServicesProxy.isForegroundUserOwner()) {
|
||||
hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
|
||||
hideRecentsInternal(triggeredFromAltTab, triggeredFromHomeKey);
|
||||
} else {
|
||||
Intent intent = createLocalBroadcastIntent(mContext,
|
||||
RecentsUserEventProxyReceiver.ACTION_PROXY_HIDE_RECENTS_TO_USER);
|
||||
@ -270,7 +297,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
|
||||
}
|
||||
}
|
||||
void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
|
||||
|
||||
void hideRecentsInternal(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
|
||||
if (mBootCompleted) {
|
||||
ActivityManager.RunningTaskInfo topTask = getTopMostTask();
|
||||
if (topTask != null && isRecentsTopMost(topTask, null)) {
|
||||
@ -285,16 +313,18 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
|
||||
/** Toggles the Recents activity. */
|
||||
@ProxyFromPrimaryToCurrentUser
|
||||
public void onToggleRecents() {
|
||||
@Override
|
||||
public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
|
||||
if (mSystemServicesProxy.isForegroundUserOwner()) {
|
||||
toggleRecents();
|
||||
toggleRecentsInternal();
|
||||
} else {
|
||||
Intent intent = createLocalBroadcastIntent(mContext,
|
||||
RecentsUserEventProxyReceiver.ACTION_PROXY_TOGGLE_RECENTS_TO_USER);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
|
||||
}
|
||||
}
|
||||
void toggleRecents() {
|
||||
|
||||
void toggleRecentsInternal() {
|
||||
mTriggeredFromAltTab = false;
|
||||
|
||||
try {
|
||||
@ -306,16 +336,18 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
|
||||
/** Preloads info for the Recents activity. */
|
||||
@ProxyFromPrimaryToCurrentUser
|
||||
public void onPreloadRecents() {
|
||||
@Override
|
||||
public void preloadRecents() {
|
||||
if (mSystemServicesProxy.isForegroundUserOwner()) {
|
||||
preloadRecents();
|
||||
preloadRecentsInternal();
|
||||
} else {
|
||||
Intent intent = createLocalBroadcastIntent(mContext,
|
||||
RecentsUserEventProxyReceiver.ACTION_PROXY_PRELOAD_RECENTS_TO_USER);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
|
||||
}
|
||||
}
|
||||
void preloadRecents() {
|
||||
|
||||
void preloadRecentsInternal() {
|
||||
// Preload only the raw task list into a new load plan (which will be consumed by the
|
||||
// RecentsActivity)
|
||||
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
|
||||
@ -323,7 +355,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
sInstanceLoadPlan.preloadRawTasks(true);
|
||||
}
|
||||
|
||||
public void onCancelPreloadingRecents() {
|
||||
@Override
|
||||
public void cancelPreloadingRecents() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@ -398,11 +431,13 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
}
|
||||
}
|
||||
|
||||
public void onShowNextAffiliatedTask() {
|
||||
@Override
|
||||
public void showNextAffiliatedTask() {
|
||||
showRelativeAffiliatedTask(true);
|
||||
}
|
||||
|
||||
public void onShowPrevAffiliatedTask() {
|
||||
@Override
|
||||
public void showPrevAffiliatedTask() {
|
||||
showRelativeAffiliatedTask(false);
|
||||
}
|
||||
|
||||
@ -745,7 +780,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta
|
||||
}
|
||||
|
||||
/** Sets the RecentsComponent callbacks. */
|
||||
public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) {
|
||||
@Override
|
||||
public void setCallback(RecentsComponent.Callbacks cb) {
|
||||
sRecentsComponentCallbacks = cb;
|
||||
}
|
||||
|
@ -130,20 +130,20 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action.equals(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY)) {
|
||||
if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
|
||||
if (action.equals(Recents.ACTION_HIDE_RECENTS_ACTIVITY)) {
|
||||
if (intent.getBooleanExtra(Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false)) {
|
||||
// If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
|
||||
dismissRecentsToFocusedTaskOrHome(false);
|
||||
} else if (intent.getBooleanExtra(AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) {
|
||||
} else if (intent.getBooleanExtra(Recents.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) {
|
||||
// Otherwise, dismiss Recents to Home
|
||||
dismissRecentsToHome(true);
|
||||
} else {
|
||||
// Do nothing, another activity is being launched on top of Recents
|
||||
}
|
||||
} else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
|
||||
} else if (action.equals(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
|
||||
// If we are toggling Recents, then first unfilter any filtered stacks first
|
||||
dismissRecentsToFocusedTaskOrHome(true);
|
||||
} else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) {
|
||||
} else if (action.equals(Recents.ACTION_START_ENTER_ANIMATION)) {
|
||||
// Trigger the enter animation
|
||||
onEnterAnimationTriggered();
|
||||
// Notify the fallback receiver that we have successfully got the broadcast
|
||||
@ -185,7 +185,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
// If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
|
||||
// reconstructing the task stack
|
||||
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
|
||||
RecentsTaskLoadPlan plan = AlternateRecentsComponent.consumeInstanceLoadPlan();
|
||||
RecentsTaskLoadPlan plan = Recents.consumeInstanceLoadPlan();
|
||||
if (plan == null) {
|
||||
plan = loader.createLoadPlan(this);
|
||||
}
|
||||
@ -436,13 +436,13 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
mVisible = true;
|
||||
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
|
||||
SystemServicesProxy ssp = loader.getSystemServicesProxy();
|
||||
AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, true);
|
||||
Recents.notifyVisibilityChanged(this, ssp, true);
|
||||
|
||||
// Register the broadcast receiver to handle messages from our service
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY);
|
||||
filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY);
|
||||
filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION);
|
||||
filter.addAction(Recents.ACTION_HIDE_RECENTS_ACTIVITY);
|
||||
filter.addAction(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY);
|
||||
filter.addAction(Recents.ACTION_START_ENTER_ANIMATION);
|
||||
registerReceiver(mServiceBroadcastReceiver, filter);
|
||||
|
||||
// Register any broadcast receivers for the task loader
|
||||
@ -458,7 +458,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
|
||||
mVisible = false;
|
||||
RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
|
||||
SystemServicesProxy ssp = loader.getSystemServicesProxy();
|
||||
AlternateRecentsComponent.notifyVisibilityChanged(this, ssp, false);
|
||||
Recents.notifyVisibilityChanged(this, ssp, false);
|
||||
|
||||
// Notify the views that we are no longer visible
|
||||
mRecentsView.onRecentsHidden();
|
||||
|
@ -19,8 +19,6 @@ package com.android.systemui.recents;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import com.android.systemui.recent.Recents;
|
||||
|
||||
|
||||
/**
|
||||
* A proxy for Recents events which happens strictly for non-owner users.
|
||||
@ -39,28 +37,27 @@ public class RecentsUserEventProxyReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
AlternateRecentsComponent recents = Recents.getRecentsComponent(
|
||||
context.getApplicationContext(), true);
|
||||
Recents recents = Recents.getInstanceAndStartIfNeeded(context);
|
||||
switch (intent.getAction()) {
|
||||
case ACTION_PROXY_SHOW_RECENTS_TO_USER: {
|
||||
boolean triggeredFromAltTab = intent.getBooleanExtra(
|
||||
AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
|
||||
recents.showRecents(triggeredFromAltTab);
|
||||
Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
|
||||
recents.showRecentsInternal(triggeredFromAltTab);
|
||||
break;
|
||||
}
|
||||
case ACTION_PROXY_HIDE_RECENTS_TO_USER: {
|
||||
boolean triggeredFromAltTab = intent.getBooleanExtra(
|
||||
AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
|
||||
Recents.EXTRA_TRIGGERED_FROM_ALT_TAB, false);
|
||||
boolean triggeredFromHome = intent.getBooleanExtra(
|
||||
AlternateRecentsComponent.EXTRA_TRIGGERED_FROM_HOME_KEY, false);
|
||||
recents.hideRecents(triggeredFromAltTab, triggeredFromHome);
|
||||
Recents.EXTRA_TRIGGERED_FROM_HOME_KEY, false);
|
||||
recents.hideRecentsInternal(triggeredFromAltTab, triggeredFromHome);
|
||||
break;
|
||||
}
|
||||
case ACTION_PROXY_TOGGLE_RECENTS_TO_USER:
|
||||
recents.toggleRecents();
|
||||
recents.toggleRecentsInternal();
|
||||
break;
|
||||
case ACTION_PROXY_PRELOAD_RECENTS_TO_USER:
|
||||
recents.preloadRecents();
|
||||
recents.preloadRecentsInternal();
|
||||
break;
|
||||
case ACTION_PROXY_CONFIG_CHANGE_TO_USER:
|
||||
recents.configurationChanged();
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.recent;
|
||||
package com.android.systemui.recents;
|
||||
|
||||
import android.animation.ArgbEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
@ -41,7 +41,6 @@ import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.recents.model.RecentsTaskLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -91,6 +91,7 @@ import com.android.systemui.RecentsComponent;
|
||||
import com.android.systemui.SearchPanelView;
|
||||
import com.android.systemui.SwipeHelper;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.recents.Recents;
|
||||
import com.android.systemui.statusbar.NotificationData.Entry;
|
||||
import com.android.systemui.statusbar.phone.NavigationBarView;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
@ -531,7 +532,7 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
mBarService = IStatusBarService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
|
||||
|
||||
mRecents = getComponent(RecentsComponent.class);
|
||||
mRecents = getComponent(Recents.class);
|
||||
mRecents.setCallback(this);
|
||||
|
||||
final Configuration currentConfig = mContext.getResources().getConfiguration();
|
||||
|
@ -128,7 +128,7 @@ import com.android.systemui.doze.DozeHost;
|
||||
import com.android.systemui.doze.DozeLog;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.qs.QSPanel;
|
||||
import com.android.systemui.recent.ScreenPinningRequest;
|
||||
import com.android.systemui.recents.ScreenPinningRequest;
|
||||
import com.android.systemui.statusbar.ActivatableNotificationView;
|
||||
import com.android.systemui.statusbar.BackDropView;
|
||||
import com.android.systemui.statusbar.BaseStatusBar;
|
||||
|
Reference in New Issue
Block a user