Merge "Recents: apps scale down to thumbnails now" into jb-mr1-dev

This commit is contained in:
Michael Jurka
2012-08-23 04:57:54 -07:00
committed by Android (Google) Code Review
16 changed files with 637 additions and 611 deletions

View File

@@ -53,6 +53,7 @@
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application
android:name="com.android.systemui.SystemUIApplication"
android:persistent="true"
android:allowClearUserData="false"
android:allowBackup="false"
@@ -96,6 +97,16 @@
android:excludeFromRecents="true">
</activity>
<activity android:name=".recent.RecentsActivity"
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:exported="true">
<intent-filter>
<action android:name="com.android.systemui.TOGGLE_RECENTS" />
</intent-filter>
</activity>
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbConfirmActivity"
android:exported="true"

View File

@@ -26,11 +26,6 @@
android:layout_width="match_parent"
systemui:recentItemLayout="@layout/status_bar_recent_item"
>
<View
android:id="@+id/recents_transition_background"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/status_bar_recents_background"
@@ -40,12 +35,6 @@
android:clipToPadding="false"
android:clipChildren="false">
<ImageView
android:id="@+id/recents_transition_placeholder_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible" />
<com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"

View File

@@ -26,11 +26,6 @@
android:layout_width="match_parent"
systemui:recentItemLayout="@layout/status_bar_recent_item"
>
<View
android:id="@+id/recents_transition_background"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/status_bar_recents_background"
@@ -38,12 +33,6 @@
android:layout_height="match_parent"
android:layout_alignParentBottom="true">
<ImageView
android:id="@+id/recents_transition_placeholder_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible" />
<com.android.systemui.recent.RecentsVerticalScrollView
android:id="@+id/recents_container"
android:layout_width="match_parent"

View File

@@ -28,11 +28,6 @@
android:clipChildren="false"
systemui:recentItemLayout="@layout/system_bar_recent_item"
>
<View
android:id="@+id/recents_transition_background"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:visibility="invisible" />
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/recents_bg_protect_tile"
@@ -42,11 +37,6 @@
android:layout_marginBottom="@*android:dimen/system_bar_height"
android:clipToPadding="false"
android:clipChildren="false">
<ImageView
android:id="@+id/recents_transition_placeholder_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible" />
<com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
android:layout_width="wrap_content"

View File

@@ -28,6 +28,7 @@
<!-- Size of application thumbnail -->
<dimen name="status_bar_recents_thumbnail_width">164dp</dimen>
<dimen name="status_bar_recents_thumbnail_height">145dp</dimen>
<dimen name="status_bar_recents_thumbnail_bg_padding">4dp</dimen>
<!-- Size of application label text -->
<dimen name="status_bar_recents_app_label_text_size">14dip</dimen>

View File

@@ -0,0 +1,32 @@
/*
* 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;
import android.app.Application;
import com.android.systemui.recent.RecentTasksLoader;
public class SystemUIApplication extends Application {
private RecentTasksLoader mRecentTasksLoader;
public RecentTasksLoader getRecentTasksLoader() {
if (mRecentTasksLoader == null) {
mRecentTasksLoader = new RecentTasksLoader(this);
}
return mRecentTasksLoader;
}
}

View File

@@ -1,191 +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.AnimatorSet;
import android.animation.AnimatorSet.Builder;
import android.animation.ObjectAnimator;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.Slog;
import android.view.View;
import com.android.systemui.R;
/* package */ class Choreographer implements Animator.AnimatorListener {
// should group this into a multi-property animation
private static final int OPEN_DURATION = 136;
private static final int CLOSE_DURATION = 230;
private static final int SCRIM_DURATION = 400;
private static final String TAG = RecentsPanelView.TAG;
private static final boolean DEBUG = RecentsPanelView.DEBUG;
boolean mVisible;
int mPanelHeight;
RecentsPanelView mRootView;
View mScrimView;
View mContentView;
View mNoRecentAppsView;
AnimatorSet mContentAnim;
Animator.AnimatorListener mListener;
// the panel will start to appear this many px from the end
final int HYPERSPACE_OFFRAMP = 200;
public Choreographer(RecentsPanelView root, View scrim, View content,
View noRecentApps, Animator.AnimatorListener listener) {
mRootView = root;
mScrimView = scrim;
mContentView = content;
mListener = listener;
mNoRecentAppsView = noRecentApps;
}
void createAnimation(boolean appearing) {
float start, end;
// 0: on-screen
// height: off-screen
float y = mContentView.getTranslationY();
if (appearing) {
// we want to go from near-the-top to the top, unless we're half-open in the right
// general vicinity
start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
end = 0;
} else {
start = y;
end = y;
}
Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
start, end);
posAnim.setInterpolator(appearing
? new android.view.animation.DecelerateInterpolator(2.5f)
: new android.view.animation.AccelerateInterpolator(2.5f));
posAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
Animator fadeAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
fadeAnim.setInterpolator(appearing
? new android.view.animation.AccelerateInterpolator(1.0f)
: new android.view.animation.AccelerateInterpolator(2.5f));
fadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
Animator noRecentAppsFadeAnim = null;
if (mNoRecentAppsView != null && // doesn't exist on large devices
mNoRecentAppsView.getVisibility() == View.VISIBLE) {
noRecentAppsFadeAnim = ObjectAnimator.ofFloat(mNoRecentAppsView, "alpha",
mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
noRecentAppsFadeAnim.setInterpolator(appearing
? new android.view.animation.AccelerateInterpolator(1.0f)
: new android.view.animation.DecelerateInterpolator(1.0f));
noRecentAppsFadeAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
}
mContentAnim = new AnimatorSet();
final Builder builder = mContentAnim.play(fadeAnim).with(posAnim);
if (noRecentAppsFadeAnim != null) {
builder.with(noRecentAppsFadeAnim);
}
if (appearing) {
Drawable background = mScrimView.getBackground();
if (background != null) {
Animator bgAnim = ObjectAnimator.ofInt(background,
"alpha", appearing ? 0 : 255, appearing ? 255 : 0);
bgAnim.setDuration(appearing ? SCRIM_DURATION : CLOSE_DURATION);
builder.with(bgAnim);
}
} else {
final Resources res = mRootView.getResources();
boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
if (!isTablet) {
View recentsTransitionBackground =
mRootView.findViewById(R.id.recents_transition_background);
recentsTransitionBackground.setVisibility(View.VISIBLE);
Drawable bgDrawable = new ColorDrawable(0xFF000000);
recentsTransitionBackground.setBackground(bgDrawable);
Animator bgAnim = ObjectAnimator.ofInt(bgDrawable, "alpha", 0, 255);
bgAnim.setDuration(CLOSE_DURATION);
bgAnim.setInterpolator(new android.view.animation.AccelerateInterpolator(1f));
builder.with(bgAnim);
}
}
mContentAnim.addListener(this);
if (mListener != null) {
mContentAnim.addListener(mListener);
}
}
void startAnimation(boolean appearing) {
if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
createAnimation(appearing);
// isHardwareAccelerated() checks if we're attached to a window and if that
// window is HW accelerated-- we were sometimes not attached to a window
// and buildLayer was throwing an IllegalStateException
if (mContentView.isHardwareAccelerated()) {
mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mContentView.buildLayer();
}
mContentAnim.start();
mVisible = appearing;
}
void jumpTo(boolean appearing) {
mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
if (mScrimView.getBackground() != null) {
mScrimView.getBackground().setAlpha(appearing ? 255 : 0);
}
View recentsTransitionBackground =
mRootView.findViewById(R.id.recents_transition_background);
recentsTransitionBackground.setVisibility(View.INVISIBLE);
mRootView.requestLayout();
}
public void setPanelHeight(int h) {
if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
mPanelHeight = h;
}
public void onAnimationCancel(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationCancel");
// force this to zero so we close the window
mVisible = false;
}
public void onAnimationEnd(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationEnd");
if (!mVisible) {
mRootView.hideWindow();
}
mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
mContentView.setAlpha(1f);
mContentAnim = null;
}
public void onAnimationRepeat(Animator animation) {
}
public void onAnimationStart(Animator animation) {
}
}

View File

@@ -32,6 +32,8 @@ import android.os.Handler;
import android.os.Process;
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.statusbar.phone.PhoneStatusBar;
@@ -42,7 +44,7 @@ import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class RecentTasksLoader {
public class RecentTasksLoader implements View.OnTouchListener {
static final String TAG = "RecentTasksLoader";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
@@ -51,17 +53,43 @@ public class RecentTasksLoader {
private Context mContext;
private RecentsPanelView mRecentsPanel;
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 Bitmap mDefaultThumbnailBackground;
private Bitmap mDefaultIconBackground;
private int mNumTasksInFirstScreenful;
private int mNumTasksInFirstScreenful = Integer.MAX_VALUE;
private boolean mFirstScreenful;
private ArrayList<TaskDescription> mLoadedTasks;
private enum State { LOADING, LOADED, CANCELLED };
private State mState = State.CANCELLED;
public TaskDescription getFirstTask() {
while (!mFirstTaskLoaded) {
if (mState == State.CANCELLED) {
loadTasksInBackground();
}
try {
if (mState == State.LOADED) {
break;
}
Thread.sleep(5);
} catch (InterruptedException e) {
}
}
return mFirstTask;
}
public RecentTasksLoader(Context context) {
mContext = context;
mHandler = new Handler();
final Resources res = context.getResources();
@@ -91,16 +119,16 @@ public class RecentTasksLoader {
Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(mDefaultThumbnailBackground);
c.drawColor(color);
// If we're using the cache, begin listening to the activity manager for
// updated thumbnails
final ActivityManager am = (ActivityManager)
mContext.getSystemService(Context.ACTIVITY_SERVICE);
}
public void setRecentsPanel(RecentsPanelView recentsPanel) {
mRecentsPanel = recentsPanel;
mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful();
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 Bitmap getDefaultThumbnail() {
@@ -111,26 +139,33 @@ public class RecentTasksLoader {
return mDefaultIconBackground;
}
// Create an TaskDescription, returning null if the title or icon is null, or if it's the
// home activity
public ArrayList<TaskDescription> getLoadedTasks() {
return mLoadedTasks;
}
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, ActivityInfo homeInfo) {
ComponentName origActivity, CharSequence description) {
Intent intent = new Intent(baseIntent);
if (origActivity != null) {
intent.setComponent(origActivity);
}
final PackageManager pm = mContext.getPackageManager();
if (homeInfo == null) {
homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
}
// Don't load the current home activity.
if (homeInfo != null
&& homeInfo.packageName.equals(intent.getComponent().getPackageName())
&& homeInfo.name.equals(intent.getComponent().getClassName())) {
return null;
}
intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
| Intent.FLAG_ACTIVITY_NEW_TASK);
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
@@ -207,7 +242,43 @@ public class RecentTasksLoader {
return getFullResDefaultActivityIcon();
}
public void cancelLoadingThumbnailsAndIcons() {
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) {
mHandler.post(mPreloadTasksRunnable);
} else if (action == MotionEvent.ACTION_CANCEL) {
cancelLoadingThumbnailsAndIcons();
mHandler.removeCallbacks(mPreloadTasksRunnable);
} 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 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 (mTaskLoader != null) {
mTaskLoader.cancel(false);
mTaskLoader = null;
@@ -216,11 +287,26 @@ public class RecentTasksLoader {
mThumbnailLoader.cancel(false);
mThumbnailLoader = null;
}
mLoadedTasks = null;
mFirstTask = null;
mFirstTaskLoaded = false;
if (mRecentsPanel != null) {
mRecentsPanel.onTaskLoadingCancelled();
}
mFirstScreenful = false;
mState = State.CANCELLED;
}
public void loadTasksInBackground() {
// cancel all previous loading of tasks and thumbnails
cancelLoadingThumbnailsAndIcons();
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>() {
@@ -230,7 +316,14 @@ public class RecentTasksLoader {
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
mRecentsPanel.onTasksLoaded(newTasks);
if (mRecentsPanel != null) {
mRecentsPanel.onTasksLoaded(newTasks, mFirstScreenful);
}
if (mLoadedTasks == null) {
mLoadedTasks = new ArrayList<TaskDescription>();
}
mLoadedTasks.addAll(newTasks);
mFirstScreenful = false;
}
}
@Override
@@ -254,15 +347,34 @@ public class RecentTasksLoader {
ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>();
// skip the first task - assume it's either the home screen or the current activity.
final int first = 1;
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)) {
if (index == 0) {
mFirstTaskLoaded = true;
}
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, homeInfo);
recentInfo.origActivity, recentInfo.description);
if (item != null) {
while (true) {
@@ -317,7 +429,13 @@ public class RecentTasksLoader {
protected void onProgressUpdate(TaskDescription... values) {
if (!isCancelled()) {
TaskDescription td = values[0];
mRecentsPanel.onTaskThumbnailLoaded(td);
if (td.isNull()) { // end sentinel
mState = State.LOADED;
} else {
if (mRecentsPanel != null) {
mRecentsPanel.onTaskThumbnailLoaded(td);
}
}
}
}
@Override
@@ -336,19 +454,25 @@ public class RecentTasksLoader {
} catch (InterruptedException e) {
}
}
if (td.isNull()) {
if (td.isNull()) { // end sentinel
publishProgress(td);
break;
}
loadThumbnailAndIcon(td);
synchronized(td) {
publishProgress(td);
if (!mFirstTaskLoaded) {
mFirstTask = td;
mFirstTaskLoaded = true;
}
publishProgress(td);
}
Process.setThreadPriority(origPri);
return null;
}
};
mFirstTask = null;
mFirstTaskLoaded = false;
mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}

View File

@@ -0,0 +1,176 @@
/*
* 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.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 com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
public class RecentsActivity extends Activity {
public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.TOGGLE_RECENTS";
public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.CLOSE_RECENTS";
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 (mRecentsPanel != null && mRecentsPanel.isShowing()) {
if (mShowing && !mForeground) {
// Captures the case right before we transition to another activity
mRecentsPanel.show(false);
}
}
}
};
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() {
mForeground = false;
super.onPause();
}
@Override
public void onStop() {
mShowing = false;
if (mRecentsPanel != null) {
mRecentsPanel.onUiHidden();
}
super.onStop();
}
@Override
public void onStart() {
mShowing = true;
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 SystemUIApplication app = (SystemUIApplication) getApplication();
final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
TaskDescription firstTask = recentTasksLoader.getFirstTask();
if (firstTask != null && mRecentsPanel.simulateClick(firstTask)) {
// recents panel will take care of calling show(false);
return;
}
mRecentsPanel.show(false);
}
finish();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
final SystemUIApplication app = (SystemUIApplication) getApplication();
final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
setContentView(R.layout.status_bar_recent_panel);
mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
mRecentsPanel.setRecentTasksLoader(recentTasksLoader);
recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
handleIntent(getIntent());
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
registerReceiver(mIntentReceiver, mIntentFilter);
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
final SystemUIApplication app = (SystemUIApplication) getApplication();
final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
recentTasksLoader.setRecentsPanel(null, mRecentsPanel);
unregisterReceiver(mIntentReceiver);
super.onDestroy();
}
@Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
}
private void handleIntent(Intent intent) {
super.onNewIntent(intent);
if (TOGGLE_RECENTS_INTENT.equals(intent.getAction())) {
if (mRecentsPanel != null && !mRecentsPanel.isShowing()) {
final SystemUIApplication app = (SystemUIApplication) getApplication();
final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
mRecentsPanel.show(true, recentTasksLoader.getLoadedTasks(),
recentTasksLoader.isFirstScreenful());
} else if ((mRecentsPanel != null && mRecentsPanel.isShowing())) {
dismissAndGoBack();
}
}
}
}

View File

@@ -76,6 +76,17 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView
}
}
public View findViewForTask(TaskDescription task) {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);
RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
if (holder.taskDescription == task) {
return v;
}
}
return null;
}
private void update() {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);

View File

@@ -29,20 +29,17 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -71,7 +68,7 @@ import com.android.systemui.statusbar.tablet.TabletStatusBar;
import java.util.ArrayList;
public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener {
StatusBarPanel, Animator.AnimatorListener {
static final String TAG = "RecentsPanelView";
static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
private Context mContext;
@@ -84,36 +81,22 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
private boolean mShowing;
private boolean mWaitingToShow;
private boolean mWaitingToShowAnimated;
private boolean mReadyToShow;
private int mNumItemsWaitingForThumbnailsAndIcons;
private Choreographer mChoreo;
OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener;
ImageView mPlaceholderThumbnail;
View mTransitionBg;
boolean mHideRecentsAfterThumbnailScaleUpStarted;
private RecentTasksLoader mRecentTasksLoader;
private ArrayList<TaskDescription> mRecentTaskDescriptions;
private Runnable mPreloadTasksRunnable;
private boolean mRecentTasksDirty = true;
private TaskDescriptionAdapter mListAdapter;
private int mThumbnailWidth;
private boolean mFitThumbnailToXY;
private int mRecentItemLayoutId;
private boolean mFirstScreenful = true;
private boolean mHighEndGfx;
public static interface OnRecentsPanelVisibilityChangedListener {
public void onRecentsPanelVisibilityChanged(boolean visible);
}
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(TaskDescription task);
}
private final class OnLongClickDelegate implements View.OnLongClickListener {
@@ -252,15 +235,6 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
}
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && !event.isCanceled()) {
show(false, false);
return true;
}
return super.onKeyUp(keyCode, event);
}
private boolean pointInside(int x, int y, View v) {
final int l = v.getLeft();
final int r = v.getRight();
@@ -280,22 +254,26 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
}
}
public void show(boolean show, boolean animate) {
public void show(boolean show) {
show(show, null, false);
}
public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
boolean firstScreenful) {
if (show) {
refreshRecentTasksList(null, true);
mWaitingToShow = true;
mWaitingToShowAnimated = animate;
refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
showIfReady();
} else {
show(show, animate, null, false);
showImpl(false);
}
}
private void showIfReady() {
// mWaitingToShow = there was a touch up on the recents button
// mReadyToShow = we've created views for the first screenful of items
if (mWaitingToShow && mReadyToShow) { // && mNumItemsWaitingForThumbnailsAndIcons <= 0
show(true, mWaitingToShowAnimated, null, false);
// 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);
}
}
@@ -308,79 +286,44 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
}
}
public void show(boolean show, boolean animate,
ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) {
private void showImpl(boolean show) {
sendCloseSystemWindows(mContext, BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
mShowing = show;
if (show) {
// Need to update list of recent apps before we set visibility so this view's
// content description is updated before it gets focus for TalkBack mode
refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
// 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);
// if there are no apps, either bring up a "No recent apps" message, or just
// quit early
boolean noApps = !mFirstScreenful && (mRecentTaskDescriptions.size() == 0);
if (mRecentsNoApps != null) {
mRecentsNoApps.setAlpha(1f);
mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE);
} else {
if (noApps) {
if (DEBUG) Log.v(TAG, "Nothing to show");
// Need to set recent tasks to dirty so that next time we load, we
// refresh the list of tasks
mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTasksDirty = true;
mWaitingToShow = false;
mReadyToShow = false;
return;
}
}
} else {
// Need to set recent tasks to dirty so that next time we load, we
// refresh the list of tasks
mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTasksDirty = true;
mWaitingToShow = false;
mReadyToShow = false;
}
if (animate) {
if (mShowing != show) {
mShowing = show;
if (show) {
setVisibility(View.VISIBLE);
}
mChoreo.startAnimation(show);
}
} else {
mShowing = show;
setVisibility(show ? View.VISIBLE : View.GONE);
mChoreo.jumpTo(show);
onAnimationEnd(null);
}
if (show) {
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
} else {
mWaitingToShow = false;
// call onAnimationEnd() and clearRecentTasksList() in onUiHidden()
if (mPopup != null) {
mPopup.dismiss();
}
}
}
public void dismiss() {
hide(true);
public void onUiHidden() {
if (!mShowing && mRecentTaskDescriptions != null) {
onAnimationEnd(null);
clearRecentTasksList();
}
}
public void hide(boolean animate) {
if (!animate) {
setVisibility(View.GONE);
}
if (mBar != null) {
// This will indirectly cause show(false, ...) to get called
mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
}
public void dismiss() {
((RecentsActivity) mContext).dismissAndGoHome();
}
public void dismissAndGoBack() {
((RecentsActivity) mContext).dismissAndGoBack();
}
public void onAnimationCancel(Animator animation) {
@@ -393,7 +336,6 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
createCustomAnimations(transitioner);
} else {
((ViewGroup)mRecentsContainer).setLayoutTransition(null);
clearRecentTasksList();
}
}
@@ -403,16 +345,6 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
public void onAnimationStart(Animator animation) {
}
/**
* We need to be aligned at the bottom. LinearLayout can't do this, so instead,
* let LinearLayout do all the hard work, and then shift everything down to the bottom.
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mChoreo.setPanelHeight(mRecentsContainer.getHeight());
}
@Override
public boolean dispatchHoverEvent(MotionEvent event) {
// Ignore hover events outside of this panel bounds since such events
@@ -449,18 +381,6 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
mRecentTasksLoader = loader;
}
public void setOnVisibilityChangedListener(OnRecentsPanelVisibilityChangedListener l) {
mVisibilityChangedListener = l;
}
public void setVisibility(int visibility) {
if (mVisibilityChangedListener != null) {
mVisibilityChangedListener.onRecentsPanelVisibilityChanged(visibility == VISIBLE);
}
super.setVisibility(visibility);
}
public void updateValuesFromResources() {
final Resources res = mContext.getResources();
mThumbnailWidth = Math.round(res.getDimension(R.dimen.status_bar_recents_thumbnail_width));
@@ -486,7 +406,6 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
mRecentsScrim = findViewById(R.id.recents_bg_protect);
mRecentsNoApps = findViewById(R.id.recents_no_apps);
mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
if (mRecentsScrim != null) {
mHighEndGfx = ActivityManager.isHighEndGfx();
@@ -497,18 +416,6 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
}
}
mPreloadTasksRunnable = new Runnable() {
public void run() {
// If we set our visibility to INVISIBLE here, we avoid an extra call to
// onLayout later when we become visible (because onLayout is always called
// when going from GONE)
if (!mShowing) {
setVisibility(INVISIBLE);
refreshRecentTasksList();
}
}
};
}
public void setMinSwipeAlpha(float minAlpha) {
@@ -602,44 +509,19 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
showIfReady();
}
// additional optimization when we have software system buttons - start loading the recent
// tasks on touch down
@Override
public boolean onTouch(View v, MotionEvent ev) {
if (!mShowing) {
int action = ev.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN) {
post(mPreloadTasksRunnable);
} else if (action == MotionEvent.ACTION_CANCEL) {
setVisibility(GONE);
clearRecentTasksList();
// Remove the preloader if we haven't called it yet
removeCallbacks(mPreloadTasksRunnable);
} else if (action == MotionEvent.ACTION_UP) {
// Remove the preloader if we haven't called it yet
removeCallbacks(mPreloadTasksRunnable);
if (!v.isPressed()) {
setVisibility(GONE);
clearRecentTasksList();
}
}
}
return false;
}
public void preloadRecentTasksList() {
if (!mShowing) {
mPreloadTasksRunnable.run();
}
}
public void clearRecentTasksList() {
// Clear memory used by screenshots
if (!mShowing && mRecentTaskDescriptions != null) {
mRecentTasksLoader.cancelLoadingThumbnailsAndIcons();
mRecentTaskDescriptions.clear();
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();
mRecentTasksDirty = true;
}
}
@@ -649,23 +531,15 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
private void refreshRecentTasksList(
ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) {
if (mRecentTasksDirty) {
if (recentTasksList != null) {
mFirstScreenful = true;
onTasksLoaded(recentTasksList);
} else {
mFirstScreenful = true;
mRecentTasksLoader.loadTasksInBackground();
}
mRecentTasksDirty = false;
if (mRecentTaskDescriptions == null && recentTasksList != null) {
onTasksLoaded(recentTasksList, firstScreenful);
} else {
mRecentTasksLoader.loadTasksInBackground();
}
}
public void onTasksLoaded(ArrayList<TaskDescription> tasks) {
if (!mFirstScreenful && tasks.size() == 0) {
return;
}
mNumItemsWaitingForThumbnailsAndIcons = mFirstScreenful
public void onTasksLoaded(ArrayList<TaskDescription> tasks, boolean firstScreenful) {
mNumItemsWaitingForThumbnailsAndIcons = firstScreenful
? tasks.size() : mRecentTaskDescriptions == null
? 0 : mRecentTaskDescriptions.size();
if (mRecentTaskDescriptions == null) {
@@ -675,19 +549,9 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
}
mListAdapter.notifyDataSetInvalidated();
updateUiElements(getResources().getConfiguration());
mReadyToShow = true;
mFirstScreenful = false;
showIfReady();
}
public ArrayList<TaskDescription> getRecentTasksList() {
return mRecentTaskDescriptions;
}
public boolean getFirstScreenful() {
return mFirstScreenful;
}
private void updateUiElements(Configuration config) {
final int items = mRecentTaskDescriptions.size();
@@ -706,8 +570,19 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
setContentDescription(recentAppsAccessibilityDescription);
}
public boolean simulateClick(TaskDescription task) {
if (mRecentsContainer instanceof RecentsScrollView){
RecentsScrollView scrollView
= (RecentsScrollView) mRecentsContainer;
View v = scrollView.findViewForTask(task);
if (v != null) {
handleOnClick(v);
return true;
}
}
return false;
}
boolean mThumbnailScaleUpStarted;
public void handleOnClick(View view) {
ViewHolder holder = (ViewHolder)view.getTag();
TaskDescription ad = holder.taskDescription;
@@ -725,59 +600,10 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
usingDrawingCache = true;
}
if (mPlaceholderThumbnail == null) {
mPlaceholderThumbnail =
(ImageView) findViewById(R.id.recents_transition_placeholder_icon);
}
if (mTransitionBg == null) {
mTransitionBg = (View) findViewById(R.id.recents_transition_background);
IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
if (!wm.hasSystemNavBar()) {
FrameLayout.LayoutParams lp =
(FrameLayout.LayoutParams) mTransitionBg.getLayoutParams();
int statusBarHeight = getResources().
getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
lp.setMargins(0, statusBarHeight, 0, 0);
mTransitionBg.setLayoutParams(lp);
}
} catch (RemoteException e) {
Log.w(TAG, "Failing checking whether status bar is visible", e);
}
}
final ImageView placeholderThumbnail = mPlaceholderThumbnail;
mHideRecentsAfterThumbnailScaleUpStarted = false;
placeholderThumbnail.setVisibility(VISIBLE);
if (!usingDrawingCache) {
placeholderThumbnail.setImageBitmap(bm);
} else {
Bitmap b2 = bm.copy(bm.getConfig(), true);
placeholderThumbnail.setImageBitmap(b2);
}
Rect r = new Rect();
holder.thumbnailViewImage.getGlobalVisibleRect(r);
placeholderThumbnail.setTranslationX(r.left);
placeholderThumbnail.setTranslationY(r.top);
show(false, true);
mThumbnailScaleUpStarted = false;
ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
holder.thumbnailViewImage, bm, 0, 0,
new ActivityOptions.OnAnimationStartedListener() {
@Override public void onAnimationStarted() {
mThumbnailScaleUpStarted = true;
if (!mHighEndGfx) {
mPlaceholderThumbnail.setVisibility(INVISIBLE);
}
if (mHideRecentsAfterThumbnailScaleUpStarted) {
hideWindow();
}
}
});
holder.thumbnailViewImage, bm, 0, 0, null);
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,
@@ -796,17 +622,6 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
}
}
public void hideWindow() {
if (!mThumbnailScaleUpStarted) {
mHideRecentsAfterThumbnailScaleUpStarted = true;
} else {
setVisibility(GONE);
mTransitionBg.setVisibility(INVISIBLE);
mPlaceholderThumbnail.setVisibility(INVISIBLE);
mHideRecentsAfterThumbnailScaleUpStarted = false;
}
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
handleOnClick(view);
}
@@ -825,7 +640,7 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
// mListAdapter.notifyDataSetChanged();
if (mRecentTaskDescriptions.size() == 0) {
hide(false);
dismissAndGoBack();
}
// Currently, either direction means the same thing, so ignore direction and remove
@@ -875,7 +690,7 @@ public class RecentsPanelView extends FrameLayout implements OnItemClickListener
if (viewHolder != null) {
final TaskDescription ad = viewHolder.taskDescription;
startApplicationDetailsActivity(ad.packageName);
mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
show(false);
} else {
throw new IllegalStateException("Oops, no tag on view " + selectedView);
}

View File

@@ -77,6 +77,17 @@ public class RecentsVerticalScrollView extends ScrollView
}
}
public View findViewForTask(TaskDescription task) {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);
RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) v.getTag();
if (holder.taskDescription == task) {
return v;
}
}
return null;
}
private void update() {
for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
View v = mLinearLayout.getChildAt(i);
@@ -146,7 +157,9 @@ public class RecentsVerticalScrollView extends ScrollView
appTitle.setContentDescription(" ");
appTitle.setOnTouchListener(noOpListener);
final View calloutLine = view.findViewById(R.id.recents_callout_line);
calloutLine.setOnTouchListener(noOpListener);
if (calloutLine != null) {
calloutLine.setOnTouchListener(noOpListener);
}
mLinearLayout.addView(view);
}

View File

@@ -1,3 +1,4 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
@@ -24,23 +25,31 @@ import com.android.internal.widget.SizeAdaptiveLayout;
import com.android.systemui.R;
import com.android.systemui.SearchPanelView;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.recent.RecentTasksLoader;
import com.android.systemui.recent.RecentsPanelView;
import com.android.systemui.recent.RecentsActivity;
import com.android.systemui.recent.TaskDescription;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
import com.android.systemui.statusbar.tablet.StatusBarPanel;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.KeyguardManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.TaskStackBuilder;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
@@ -52,6 +61,7 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
import android.view.Display;
@@ -73,12 +83,12 @@ import android.widget.TextView;
import java.util.ArrayList;
public abstract class BaseStatusBar extends SystemUI implements
CommandQueue.Callbacks, RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
CommandQueue.Callbacks {
static final String TAG = "StatusBar";
private static final boolean DEBUG = false;
public static final boolean MULTIUSER_DEBUG = false;
protected static final int MSG_OPEN_RECENTS_PANEL = 1020;
protected static final int MSG_TOGGLE_RECENTS_PANEL = 1020;
protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
protected static final int MSG_PRELOAD_RECENT_APPS = 1022;
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
@@ -111,10 +121,6 @@ public abstract class BaseStatusBar extends SystemUI implements
// Search panel
protected SearchPanelView mSearchPanelView;
// Recent apps
protected RecentsPanelView mRecentsPanel;
protected RecentTasksLoader mRecentTasksLoader;
protected PopupMenu mNotificationBlamePopup;
protected int mCurrentUserId = 0;
@@ -377,8 +383,7 @@ public abstract class BaseStatusBar extends SystemUI implements
@Override
public void toggleRecentApps() {
int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
int msg = MSG_TOGGLE_RECENTS_PANEL;
mHandler.removeMessages(msg);
mHandler.sendEmptyMessage(msg);
}
@@ -411,49 +416,15 @@ public abstract class BaseStatusBar extends SystemUI implements
mHandler.sendEmptyMessage(msg);
}
@Override
public void onRecentsPanelVisibilityChanged(boolean visible) {
}
protected abstract WindowManager.LayoutParams getRecentsLayoutParams(
LayoutParams layoutParams);
protected abstract WindowManager.LayoutParams getSearchLayoutParams(
LayoutParams layoutParams);
protected void updateRecentsPanel(int recentsResId) {
// Recents Panel
boolean visible = false;
ArrayList<TaskDescription> recentTasksList = null;
boolean firstScreenful = false;
if (mRecentsPanel != null) {
visible = mRecentsPanel.isShowing();
mWindowManager.removeView(mRecentsPanel);
if (visible) {
recentTasksList = mRecentsPanel.getRecentTasksList();
firstScreenful = mRecentsPanel.getFirstScreenful();
}
}
// Provide RecentsPanelView with a temporary parent to allow layout params to work.
LinearLayout tmpRoot = new LinearLayout(mContext);
mRecentsPanel = (RecentsPanelView) LayoutInflater.from(mContext).inflate(
recentsResId, tmpRoot, false);
mRecentsPanel.setRecentTasksLoader(mRecentTasksLoader);
mRecentTasksLoader.setRecentsPanel(mRecentsPanel);
mRecentsPanel.setOnTouchListener(
new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL, mRecentsPanel));
mRecentsPanel.setVisibility(View.GONE);
WindowManager.LayoutParams lp = getRecentsLayoutParams(mRecentsPanel.getLayoutParams());
mWindowManager.addView(mRecentsPanel, lp);
mRecentsPanel.setBar(this);
if (visible) {
mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
}
protected RecentTasksLoader getRecentTasksLoader() {
final SystemUIApplication app = (SystemUIApplication) ((Service) mContext).getApplication();
return app.getRecentTasksLoader();
}
protected void updateSearchPanel() {
@@ -494,28 +465,148 @@ public abstract class BaseStatusBar extends SystemUI implements
}
}
protected abstract View getStatusBarView();
protected void toggleRecentsActivity() {
try {
final RecentTasksLoader recentTasksLoader = getRecentTasksLoader();
TaskDescription firstTask = recentTasksLoader.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) {
mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
} else {
Bitmap first = firstTask.getThumbnail();
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.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
true);
}
DisplayMetrics dm = new DisplayMetrics();
mDisplay.getMetrics(dm);
// calculate it here, but consider moving it elsewhere
// first, determine which orientation you're in.
// todo: move the system_bar layouts to sw600dp ?
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);
} 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(labelTextSize);
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(
getStatusBarView(),
first, x, y,
null);
mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
UserHandle.USER_CURRENT));
}
return;
} catch (ActivityNotFoundException e) {
Log.e(TAG, "Failed to launch RecentAppsIntent", e);
}
}
protected class H extends Handler {
public void handleMessage(Message m) {
switch (m.what) {
case MSG_OPEN_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "opening recents panel");
if (mRecentsPanel != null) {
mRecentsPanel.show(true, false);
}
break;
case MSG_TOGGLE_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "toggle recents panel");
toggleRecentsActivity();
break;
case MSG_CLOSE_RECENTS_PANEL:
if (DEBUG) Slog.d(TAG, "closing recents panel");
if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
mRecentsPanel.show(false, false);
}
break;
if (DEBUG) Slog.d(TAG, "closing recents panel");
Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
intent.setPackage("com.android.systemui");
mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
break;
case MSG_PRELOAD_RECENT_APPS:
if (DEBUG) Slog.d(TAG, "preloading recents");
mRecentsPanel.preloadRecentTasksList();
{
// TODO:
// need to implement this
//final RecentsPanelView recentsPanel = getRecentsPanel();
//if (recentsPanel != null) {
//recentsPanel.preloadRecentTasksList();
//}
}
break;
case MSG_CANCEL_PRELOAD_RECENT_APPS:
if (DEBUG) Slog.d(TAG, "cancel preloading recents");
mRecentsPanel.clearRecentTasksList();
{
// TODO:
// need to implement this
//final RecentsPanelView recentsPanel = getRecentsPanel();
//if (recentsPanel != null) {
//recentsPanel.clearRecentTasksList();
//}
}
break;
case MSG_OPEN_SEARCH_PANEL:
if (DEBUG) Slog.d(TAG, "opening search panel");
@@ -559,8 +650,6 @@ public abstract class BaseStatusBar extends SystemUI implements
}
protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
int rowHeight =
mContext.getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
int minHeight =
mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight =
@@ -605,7 +694,6 @@ public abstract class BaseStatusBar extends SystemUI implements
// TODO(cwren) normalize variable names with those in updateNotification
View expandedOneU = null;
View expandedLarge = null;
Exception exception = null;
try {
expandedOneU = oneU.apply(mContext, adaptive, mOnClickHandler);
if (large != null) {

View File

@@ -445,9 +445,6 @@ public class PhoneStatusBar extends BaseStatusBar {
// if (wimaxRSSI != null) {
// mNetworkController.addWimaxIconView(wimaxRSSI);
// }
// Recents Panel
mRecentTasksLoader = new RecentTasksLoader(context);
updateRecentsPanel();
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -459,6 +456,11 @@ public class PhoneStatusBar extends BaseStatusBar {
return mStatusBarView;
}
@Override
protected View getStatusBarView() {
return mStatusBarView;
}
@Override
protected WindowManager.LayoutParams getRecentsLayoutParams(LayoutParams layoutParams) {
boolean opaque = false;
@@ -507,6 +509,7 @@ public class PhoneStatusBar extends BaseStatusBar {
return lp;
}
/*
protected void updateRecentsPanel() {
super.updateRecentsPanel(R.layout.status_bar_recent_panel);
// Make .03 alpha the minimum so you always see the item a bit-- slightly below
@@ -517,6 +520,7 @@ public class PhoneStatusBar extends BaseStatusBar {
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
}
}
*/
@Override
protected void updateSearchPanel() {
@@ -604,7 +608,7 @@ public class PhoneStatusBar extends BaseStatusBar {
mNavigationBarView.reorient();
mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPanel);
mNavigationBarView.getRecentsButton().setOnTouchListener(getRecentTasksLoader());
mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
updateSearchPanel();
}
@@ -785,7 +789,6 @@ public class PhoneStatusBar extends BaseStatusBar {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
updateRecentsPanel();
updateShowSearchHoldoff();
}

View File

@@ -84,8 +84,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
public class TabletStatusBar extends BaseStatusBar implements
InputMethodsPanel.OnHardKeyboardEnabledChangeListener,
RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
InputMethodsPanel.OnHardKeyboardEnabledChangeListener {
public static final boolean DEBUG = false;
public static final boolean DEBUG_COMPAT_HELP = false;
public static final String TAG = "TabletStatusBar";
@@ -305,10 +304,6 @@ public class TabletStatusBar extends BaseStatusBar implements
mWindowManager.addView(mNotificationPanel, lp);
// Recents Panel
mRecentTasksLoader = new RecentTasksLoader(context);
updateRecentsPanel();
// Search Panel
mStatusBarView.setBar(this);
mHomeButton.setOnTouchListener(mHomeSearchActionListener);
@@ -360,7 +355,7 @@ public class TabletStatusBar extends BaseStatusBar implements
mWindowManager.addView(mCompatModePanel, lp);
mRecentButton.setOnTouchListener(mRecentsPanel);
//mRecentButton.setOnTouchListener(mRecentsPanel); //TODO: plumb this
mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
mPile.removeAllViews();
@@ -393,7 +388,6 @@ public class TabletStatusBar extends BaseStatusBar implements
loadDimens();
mNotificationPanelParams.height = getNotificationPanelHeight();
mWindowManager.updateViewLayout(mNotificationPanel, mNotificationPanelParams);
mRecentsPanel.updateValuesFromResources();
mShowSearchHoldoff = mContext.getResources().getInteger(
R.integer.config_show_search_delay);
updateSearchPanel();
@@ -445,6 +439,7 @@ public class TabletStatusBar extends BaseStatusBar implements
}
}
@Override
public View getStatusBarView() {
return mStatusBarView;
}
@@ -656,11 +651,6 @@ public class TabletStatusBar extends BaseStatusBar implements
return lp;
}
protected void updateRecentsPanel() {
super.updateRecentsPanel(R.layout.system_bar_recent_panel);
mRecentsPanel.setStatusBarView(mStatusBarView);
}
@Override
protected void updateSearchPanel() {
super.updateSearchPanel();
@@ -1182,14 +1172,6 @@ public class TabletStatusBar extends BaseStatusBar implements
}
}
@Override
public void onRecentsPanelVisibilityChanged(boolean visible) {
boolean altBack = visible || mAltBackButtonEnabledForIme;
mCommandQueue.setNavigationIconHints(
altBack ? (mNavigationIconHints | StatusBarManager.NAVIGATION_HINT_BACK_ALT)
: (mNavigationIconHints & ~StatusBarManager.NAVIGATION_HINT_BACK_ALT));
}
@Override
public void setHardKeyboardStatus(boolean available, boolean enabled) {
if (DEBUG) {
@@ -1241,10 +1223,7 @@ public class TabletStatusBar extends BaseStatusBar implements
public void onClickRecentButton() {
if (DEBUG) Slog.d(TAG, "clicked recent apps; disabled=" + mDisabled);
if ((mDisabled & StatusBarManager.DISABLE_EXPAND) == 0) {
int msg = (mRecentsPanel.getVisibility() == View.VISIBLE)
? MSG_CLOSE_RECENTS_PANEL : MSG_OPEN_RECENTS_PANEL;
mHandler.removeMessages(msg);
mHandler.sendEmptyMessage(msg);
toggleRecentApps();
}
}
@@ -1523,14 +1502,6 @@ public class TabletStatusBar extends BaseStatusBar implements
flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
}
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
// If we're turning the screen off, we want to hide the
// recents panel with no animation
// TODO: hide other things, like the notification tray,
// with no animation as well
mRecentsPanel.show(false, false);
flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
animateCollapse(flags);
}
}

View File

@@ -148,6 +148,10 @@ public class TvStatusBar extends BaseStatusBar {
return mView;
}
public View getStatusBarView() {
return null;
}
protected int getStatusBarGravity() {
return 0;
}