Remove dead code #6: Delete old recents implementation

Change-Id: I93b1257563d6352a54141bd4c90d2d4587782fd2
This commit is contained in:
Jorim Jaggi
2014-12-19 20:35:35 +01:00
parent cd3b5b52ac
commit d61f2271c4
21 changed files with 99 additions and 3396 deletions

View File

@ -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">

View File

@ -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,

View File

@ -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;
}
}

View File

@ -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
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -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;