summaryrefslogtreecommitdiffstats
path: root/core/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/com')
-rw-r--r--core/java/com/android/internal/app/AlertActivity.java18
-rw-r--r--core/java/com/android/internal/app/AlertController.java91
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java42
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl2
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl1
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java88
-rw-r--r--core/java/com/android/internal/app/ProcessStats.java7
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java214
-rw-r--r--core/java/com/android/internal/app/ShutdownActivity.java66
-rw-r--r--core/java/com/android/internal/app/ToolbarActionBar.java48
-rw-r--r--core/java/com/android/internal/app/WindowDecorActionBar.java30
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java8
-rw-r--r--core/java/com/android/internal/content/PackageMonitor.java5
-rw-r--r--core/java/com/android/internal/content/ReferrerIntent.aidl19
-rw-r--r--core/java/com/android/internal/content/ReferrerIntent.java51
-rw-r--r--core/java/com/android/internal/http/multipart/FilePart.java7
-rw-r--r--core/java/com/android/internal/http/multipart/MultipartEntity.java6
-rw-r--r--core/java/com/android/internal/http/multipart/Part.java6
-rw-r--r--core/java/com/android/internal/http/multipart/StringPart.java6
-rw-r--r--core/java/com/android/internal/inputmethod/InputMethodUtils.java310
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java13
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java159
-rw-r--r--core/java/com/android/internal/os/HandlerCaller.java4
-rw-r--r--core/java/com/android/internal/os/ProcessCpuTracker.java17
-rw-r--r--core/java/com/android/internal/policy/IKeyguardService.aidl51
-rw-r--r--core/java/com/android/internal/policy/IKeyguardServiceConstants.java41
-rw-r--r--core/java/com/android/internal/policy/IKeyguardStateCallback.aidl (renamed from core/java/com/android/internal/widget/ILockSettingsObserver.aidl)12
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl1
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl7
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java15
-rw-r--r--core/java/com/android/internal/util/FastPrintWriter.java8
-rw-r--r--core/java/com/android/internal/util/MemInfoReader.java53
-rw-r--r--core/java/com/android/internal/util/StateMachine.java15
-rw-r--r--core/java/com/android/internal/util/XmlUtils.java109
-rw-r--r--core/java/com/android/internal/view/BaseIWindow.java4
-rw-r--r--core/java/com/android/internal/view/RootViewSurfaceTaker.java16
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java13
-rw-r--r--core/java/com/android/internal/widget/AccountItemView.java102
-rw-r--r--core/java/com/android/internal/widget/AccountViewAdapter.java127
-rw-r--r--core/java/com/android/internal/widget/ActionBarContainer.java3
-rw-r--r--core/java/com/android/internal/widget/ActionBarContextView.java2
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java28
-rw-r--r--core/java/com/android/internal/widget/DecorToolbar.java9
-rw-r--r--core/java/com/android/internal/widget/ExploreByTouchHelper.java90
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl4
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java149
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtilsCache.java243
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java140
-rw-r--r--core/java/com/android/internal/widget/SubtitleView.java1
-rw-r--r--core/java/com/android/internal/widget/SwipeDismissLayout.java39
-rw-r--r--core/java/com/android/internal/widget/ToolbarWidgetWrapper.java35
-rw-r--r--core/java/com/android/server/BootReceiver.java2
-rw-r--r--core/java/com/android/server/backup/SystemBackupAgent.java14
53 files changed, 1823 insertions, 728 deletions
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index 7456def..5566aa6 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -17,9 +17,14 @@
package com.android.internal.app;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
+import android.text.TextUtils;
import android.view.KeyEvent;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
/**
* An activity that follows the visual style of an AlertDialog.
@@ -62,6 +67,19 @@ public abstract class AlertActivity extends Activity implements DialogInterface
}
}
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ event.setClassName(Dialog.class.getName());
+ event.setPackageName(getPackageName());
+
+ ViewGroup.LayoutParams params = getWindow().getAttributes();
+ boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
+ (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
+ event.setFullScreen(isFullScreen);
+
+ return false;
+ }
+
/**
* Sets up the alert, including applying the parameters to the alert model,
* and installing the alert's content.
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 0183e45..20d209f 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,7 +26,6 @@ import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
@@ -38,9 +37,12 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
@@ -449,11 +451,11 @@ public class AlertController {
}
private void setupView() {
- final LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
+ final ViewGroup contentPanel = (ViewGroup) mWindow.findViewById(R.id.contentPanel);
setupContent(contentPanel);
final boolean hasButtons = setupButtons();
- final LinearLayout topPanel = (LinearLayout) mWindow.findViewById(R.id.topPanel);
+ final ViewGroup topPanel = (ViewGroup) mWindow.findViewById(R.id.topPanel);
final TypedArray a = mContext.obtainStyledAttributes(
null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
final boolean hasTitle = setupTitle(topPanel);
@@ -521,13 +523,13 @@ public class AlertController {
a.recycle();
}
- private boolean setupTitle(LinearLayout topPanel) {
+ private boolean setupTitle(ViewGroup topPanel) {
boolean hasTitle = true;
if (mCustomTitleView != null) {
// Add the custom title view directly to the topPanel layout
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ LayoutParams lp = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
topPanel.addView(mCustomTitleView, 0, lp);
@@ -571,7 +573,7 @@ public class AlertController {
return hasTitle;
}
- private void setupContent(LinearLayout contentPanel) {
+ private void setupContent(ViewGroup contentPanel) {
mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
mScrollView.setFocusable(false);
@@ -588,14 +590,77 @@ public class AlertController {
mScrollView.removeView(mMessageView);
if (mListView != null) {
- contentPanel.removeView(mWindow.findViewById(R.id.scrollView));
- contentPanel.addView(mListView,
- new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
- contentPanel.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f));
+ final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
+ final int childIndex = scrollParent.indexOfChild(mScrollView);
+ scrollParent.removeViewAt(childIndex);
+ scrollParent.addView(mListView, childIndex,
+ new LayoutParams(MATCH_PARENT, MATCH_PARENT));
} else {
contentPanel.setVisibility(View.GONE);
}
}
+
+ // Set up scroll indicators (if present).
+ final View indicatorUp = mWindow.findViewById(R.id.scrollIndicatorUp);
+ final View indicatorDown = mWindow.findViewById(R.id.scrollIndicatorDown);
+ if (indicatorUp != null || indicatorDown != null) {
+ if (mMessage != null) {
+ // We're just showing the ScrollView, set up listener.
+ mScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
+ @Override
+ public void onScrollChange(View v, int scrollX, int scrollY,
+ int oldScrollX, int oldScrollY) {
+ manageScrollIndicators(v, indicatorUp, indicatorDown);
+ }
+ });
+ // Set up the indicators following layout.
+ mScrollView.post(new Runnable() {
+ @Override
+ public void run() {
+ manageScrollIndicators(mScrollView, indicatorUp, indicatorDown);
+ }
+ });
+
+ } else if (mListView != null) {
+ // We're just showing the AbsListView, set up listener.
+ mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ // That's cool, I guess?
+ }
+
+ @Override
+ public void onScroll(AbsListView v, int firstVisibleItem,
+ int visibleItemCount, int totalItemCount) {
+ manageScrollIndicators(v, indicatorUp, indicatorDown);
+ }
+ });
+ // Set up the indicators following layout.
+ mListView.post(new Runnable() {
+ @Override
+ public void run() {
+ manageScrollIndicators(mListView, indicatorUp, indicatorDown);
+ }
+ });
+ } else {
+ // We don't have any content to scroll, remove the indicators.
+ if (indicatorUp != null) {
+ contentPanel.removeView(indicatorUp);
+ }
+ if (indicatorDown != null) {
+ contentPanel.removeView(indicatorDown);
+ }
+ }
+ }
+ }
+
+ private static void manageScrollIndicators(View v, View upIndicator, View downIndicator) {
+ if (upIndicator != null) {
+ upIndicator.setVisibility(v.canScrollVertically(-1) ? View.VISIBLE : View.INVISIBLE);
+ }
+ if (downIndicator != null) {
+ downIndicator.setVisibility(v.canScrollVertically(1) ? View.VISIBLE : View.INVISIBLE);
+ }
}
private boolean setupButtons() {
@@ -890,10 +955,10 @@ public class AlertController {
if (mIcon != null) {
dialog.setIcon(mIcon);
}
- if (mIconId >= 0) {
+ if (mIconId != 0) {
dialog.setIcon(mIconId);
}
- if (mIconAttrId > 0) {
+ if (mIconAttrId != 0) {
dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5267811..64bd6b6 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -16,13 +16,21 @@
package com.android.internal.app;
+import android.app.Activity;
+import android.content.ComponentName;
import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
+import android.util.Slog;
public class ChooserActivity extends ResolverActivity {
+ private static final String TAG = "ChooserActivity";
+
private Bundle mReplacementExtras;
+ private IntentSender mChosenComponentSender;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -60,21 +68,45 @@ public class ChooserActivity extends ResolverActivity {
initialIntents[i] = in;
}
}
+ mChosenComponentSender = intent.getParcelableExtra(
+ Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER);
setSafeForwardingMode(true);
super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents,
null, false);
}
- public Intent getReplacementIntent(String packageName, Intent defIntent) {
+ @Override
+ public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
+ Intent result = defIntent;
if (mReplacementExtras != null) {
- final Bundle replExtras = mReplacementExtras.getBundle(packageName);
+ final Bundle replExtras = mReplacementExtras.getBundle(aInfo.packageName);
if (replExtras != null) {
- final Intent result = new Intent(defIntent);
+ result = new Intent(defIntent);
result.putExtras(replExtras);
- return result;
}
}
- return defIntent;
+ if (aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER)
+ || aInfo.name.equals(IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE)) {
+ result = Intent.createChooser(result,
+ getIntent().getCharSequenceExtra(Intent.EXTRA_TITLE));
+ }
+ return result;
+ }
+
+ @Override
+ public void onActivityStarted(Intent intent) {
+ if (mChosenComponentSender != null) {
+ final ComponentName target = intent.getComponent();
+ if (target != null) {
+ final Intent fillIn = new Intent().putExtra(Intent.EXTRA_CHOSEN_COMPONENT, target);
+ try {
+ mChosenComponentSender.sendIntent(this, Activity.RESULT_OK, fillIn, null, null);
+ } catch (IntentSender.SendIntentException e) {
+ Slog.e(TAG, "Unable to launch supplied IntentSender to report "
+ + "the chosen component: " + e);
+ }
+ }
+ }
}
private void modifyTargetIntent(Intent in) {
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index a52dd48..99bf9f3 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -36,7 +36,7 @@ interface IAppOpsService {
List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
void setMode(int code, int uid, String packageName, int mode);
- void resetAllModes();
+ void resetAllModes(int reqUserId, String reqPackageName);
int checkAudioOperation(int code, int usage, int uid, String packageName);
void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 55b3ecc..87b6ed7 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -77,6 +77,7 @@ interface IBatteryStats {
void noteScreenBrightness(int brightness);
void noteUserActivity(int uid, int event);
void noteInteractive(boolean interactive);
+ void noteConnectivityChanged(int type, String extra);
void noteMobileRadioPowerState(int powerState, long timestampNs);
void notePhoneOn();
void notePhoneOff();
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 6e2f84a..7c1308f 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -58,21 +58,22 @@ public class IntentForwarderActivity extends Activity {
Intent intentReceived = getIntent();
String className = intentReceived.getComponent().getClassName();
- final UserHandle userDest;
+ final int targetUserId;
final int userMessageId;
if (className.equals(FORWARD_INTENT_TO_USER_OWNER)) {
userMessageId = com.android.internal.R.string.forward_intent_to_owner;
- userDest = UserHandle.OWNER;
+ targetUserId = UserHandle.USER_OWNER;
} else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
userMessageId = com.android.internal.R.string.forward_intent_to_work;
- userDest = getManagedProfile();
+ targetUserId = getManagedProfile();
} else {
Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
userMessageId = -1;
- userDest = null;
+ targetUserId = UserHandle.USER_NULL;
}
- if (userDest == null) { // This covers the case where there is no managed profile.
+ if (targetUserId == UserHandle.USER_NULL) {
+ // This covers the case where there is no managed profile.
finish();
return;
}
@@ -83,31 +84,27 @@ public class IntentForwarderActivity extends Activity {
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
|Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
int callingUserId = getUserId();
- IPackageManager ipm = AppGlobals.getPackageManager();
- String resolvedType = newIntent.resolveTypeIfNeeded(getContentResolver());
- boolean canForward = false;
- Intent selector = newIntent.getSelector();
- if (selector == null) {
- selector = newIntent;
- }
- try {
- canForward = ipm.canForwardTo(selector, resolvedType, callingUserId,
- userDest.getIdentifier());
- } catch (RemoteException e) {
- Slog.e(TAG, "PackageManagerService is dead?");
- }
- if (canForward) {
- newIntent.setContentUserHint(callingUserId);
+
+ if (canForward(newIntent, targetUserId)) {
+ if (newIntent.getAction().equals(Intent.ACTION_CHOOSER)) {
+ Intent innerIntent = (Intent) newIntent.getParcelableExtra(Intent.EXTRA_INTENT);
+ innerIntent.setContentUserHint(callingUserId);
+ } else {
+ newIntent.setContentUserHint(callingUserId);
+ }
final android.content.pm.ResolveInfo ri = getPackageManager().resolveActivityAsUser(
- newIntent, MATCH_DEFAULT_ONLY, userDest.getIdentifier());
+ newIntent, MATCH_DEFAULT_ONLY, targetUserId);
- // Only show a disclosure if this is a normal (non-OS) app
- final boolean shouldShowDisclosure =
- !UserHandle.isSameApp(ri.activityInfo.applicationInfo.uid, Process.SYSTEM_UID);
+ // Don't show the disclosure if next activity is ResolverActivity or ChooserActivity
+ // as those will already have shown work / personal as neccesary etc.
+ final boolean shouldShowDisclosure = ri == null || ri.activityInfo == null ||
+ !"android".equals(ri.activityInfo.packageName) ||
+ !(ResolverActivity.class.getName().equals(ri.activityInfo.name)
+ || ChooserActivity.class.getName().equals(ri.activityInfo.name));
try {
- startActivityAsCaller(newIntent, null, userDest.getIdentifier());
+ startActivityAsCaller(newIntent, null, targetUserId);
} catch (RuntimeException e) {
int launchedFromUid = -1;
String launchedFromPackage = "?";
@@ -129,26 +126,55 @@ public class IntentForwarderActivity extends Activity {
}
} else {
Slog.wtf(TAG, "the intent: " + newIntent + "cannot be forwarded from user "
- + callingUserId + " to user " + userDest.getIdentifier());
+ + callingUserId + " to user " + targetUserId);
}
finish();
}
+ boolean canForward(Intent intent, int targetUserId) {
+ IPackageManager ipm = AppGlobals.getPackageManager();
+ if (intent.getAction().equals(Intent.ACTION_CHOOSER)) {
+ // The EXTRA_INITIAL_INTENTS may not be allowed to be forwarded.
+ if (intent.hasExtra(Intent.EXTRA_INITIAL_INTENTS)) {
+ Slog.wtf(TAG, "An chooser intent with extra initial intents cannot be forwarded to"
+ + " a different user");
+ return false;
+ }
+ if (intent.hasExtra(Intent.EXTRA_REPLACEMENT_EXTRAS)) {
+ Slog.wtf(TAG, "A chooser intent with replacement extras cannot be forwarded to a"
+ + " different user");
+ return false;
+ }
+ intent = (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ }
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ if (intent.getSelector() != null) {
+ intent = intent.getSelector();
+ }
+ try {
+ return ipm.canForwardTo(intent, resolvedType, getUserId(),
+ targetUserId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "PackageManagerService is dead?");
+ return false;
+ }
+ }
+
/**
- * Returns the managed profile for this device or null if there is no managed
- * profile.
+ * Returns the userId of the managed profile for this device or UserHandle.USER_NULL if there is
+ * no managed profile.
*
* TODO: Remove the assumption that there is only one managed profile
* on the device.
*/
- private UserHandle getManagedProfile() {
+ private int getManagedProfile() {
UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
List<UserInfo> relatedUsers = userManager.getProfiles(UserHandle.USER_OWNER);
for (UserInfo userInfo : relatedUsers) {
- if (userInfo.isManagedProfile()) return new UserHandle(userInfo.id);
+ if (userInfo.isManagedProfile()) return userInfo.id;
}
Slog.wtf(TAG, FORWARD_INTENT_TO_MANAGED_PROFILE
+ " has been called, but there is no managed profile");
- return null;
+ return UserHandle.USER_NULL;
}
}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index e3e5647..70fb510 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1079,7 +1079,9 @@ public final class ProcessStats implements Parcelable {
ProcessDataCollection totals = new ProcessDataCollection(screenStates,
memStates, procStates);
computeProcessData(proc, totals, now);
- if (totals.totalTime != 0 || totals.numPss != 0) {
+ double percentage = (double) totals.totalTime / (double) totalTime * 100;
+ // We don't print percentages < .01, so just drop those.
+ if (percentage >= 0.005 || totals.numPss != 0) {
if (prefix != null) {
pw.print(prefix);
}
@@ -2470,7 +2472,7 @@ public final class ProcessStats implements Parcelable {
totalMem.totalTime, totalPss, totalMem.sysMemSamples);
totalPss = printMemoryCategory(pw, " ", "Free ", totalMem.sysMemFreeWeight,
totalMem.totalTime, totalPss, totalMem.sysMemSamples);
- totalPss = printMemoryCategory(pw, " ", "Z-Ram ", totalMem.sysMemZRamWeight,
+ totalPss = printMemoryCategory(pw, " ", "Z-Ram ", totalMem.sysMemZRamWeight,
totalMem.totalTime, totalPss, totalMem.sysMemSamples);
pw.print(" TOTAL : ");
printSizeValue(pw, totalPss);
@@ -2746,6 +2748,7 @@ public final class ProcessStats implements Parcelable {
pw.print("total");
dumpAdjTimesCheckin(pw, ",", mMemFactorDurations, mMemFactor,
mStartTime, now);
+ pw.println();
if (mSysMemUsageTable != null) {
pw.print("sysmemusage");
for (int i=0; i<mSysMemUsageTableSize; i++) {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0062e2d..649a59f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -74,6 +74,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+
/**
* This activity is displayed when the system attempts to start an Intent for
* which there is more than one matching activity, allowing the user to decide
@@ -92,11 +95,14 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private ListView mListView;
private Button mAlwaysButton;
private Button mOnceButton;
+ private View mProfileView;
private int mIconDpi;
private int mIconSize;
private int mMaxColumns;
private int mLastSelected = ListView.INVALID_POSITION;
private boolean mResolvingHome = false;
+ private int mProfileSwitchMessageId = -1;
+ private Intent mIntent;
private UsageStatsManager mUsm;
private Map<String, UsageStats> mStats;
@@ -106,6 +112,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override public void onSomePackagesChanged() {
mAdapter.handlePackagesChanged();
+ if (mProfileView != null) {
+ bindProfileView();
+ }
}
};
@@ -197,6 +206,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
List<ResolveInfo> rList, boolean alwaysUseOption) {
setTheme(R.style.Theme_DeviceDefault_Resolver);
super.onCreate(savedInstanceState);
+
+ // Determine whether we should show that intent is forwarded
+ // from managed profile to owner or other way around.
+ setProfileSwitchMessageId(intent.getContentUserHint());
+
try {
mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
getActivityToken());
@@ -208,7 +222,6 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis());
- Log.d(TAG, "sinceTime=" + sinceTime);
mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
@@ -219,7 +232,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
mIconDpi = am.getLauncherLargeIconDensity();
mIconSize = am.getLauncherLargeIconSize();
- mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList,
+ mIntent = new Intent(intent);
+ mAdapter = new ResolveListAdapter(this, initialIntents, rList,
mLaunchedFromUid, alwaysUseOption);
final int layoutId;
@@ -234,12 +248,14 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
mAlwaysUseOption = alwaysUseOption;
- int count = mAdapter.mList.size();
if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
// Gulp!
finish();
return;
- } else if (count > 1) {
+ }
+
+ int count = mAdapter.mList.size();
+ if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
setContentView(layoutId);
mListView = (ListView) findViewById(R.id.resolver_list);
mListView.setAdapter(mAdapter);
@@ -269,12 +285,15 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
mListView = (ListView) findViewById(R.id.resolver_list);
mListView.setVisibility(View.GONE);
}
+ // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
+ // control of the system bars.
+ getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR);
final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
if (rdl != null) {
- rdl.setOnClickOutsideListener(new View.OnClickListener() {
+ rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
@Override
- public void onClick(View v) {
+ public void onDismissed() {
finish();
}
});
@@ -312,6 +331,56 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
mOnceButton.setEnabled(true);
}
+
+ mProfileView = findViewById(R.id.profile_button);
+ if (mProfileView != null) {
+ mProfileView.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final DisplayResolveInfo dri = mAdapter.getOtherProfile();
+ if (dri == null) {
+ return;
+ }
+
+ final Intent intent = intentForDisplayResolveInfo(dri);
+ onIntentSelected(dri.ri, intent, false);
+ finish();
+ }
+ });
+ bindProfileView();
+ }
+ }
+
+ void bindProfileView() {
+ final DisplayResolveInfo dri = mAdapter.getOtherProfile();
+ if (dri != null) {
+ mProfileView.setVisibility(View.VISIBLE);
+ final ImageView icon = (ImageView) mProfileView.findViewById(R.id.icon);
+ final TextView text = (TextView) mProfileView.findViewById(R.id.text1);
+ if (dri.displayIcon == null) {
+ new LoadIconTask().execute(dri);
+ }
+ icon.setImageDrawable(dri.displayIcon);
+ text.setText(dri.displayLabel);
+ } else {
+ mProfileView.setVisibility(View.GONE);
+ }
+ }
+
+ private void setProfileSwitchMessageId(int contentUserHint) {
+ if (contentUserHint != UserHandle.USER_CURRENT &&
+ contentUserHint != UserHandle.myUserId()) {
+ UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
+ UserInfo originUserInfo = userManager.getUserInfo(contentUserHint);
+ boolean originIsManaged = originUserInfo != null ? originUserInfo.isManagedProfile()
+ : false;
+ boolean targetIsManaged = userManager.isManagedProfile();
+ if (originIsManaged && !targetIsManaged) {
+ mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_owner;
+ } else if (!originIsManaged && targetIsManaged) {
+ mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_work;
+ }
+ }
}
/**
@@ -388,6 +457,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
mRegistered = true;
}
mAdapter.handlePackagesChanged();
+ if (mProfileView != null) {
+ bindProfileView();
+ }
}
@Override
@@ -523,7 +595,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
/**
* Replace me in subclasses!
*/
- public Intent getReplacementIntent(String packageName, Intent defIntent) {
+ public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
return defIntent;
}
@@ -636,12 +708,19 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
public void safelyStartActivity(Intent intent) {
+ // If needed, show that intent is forwarded
+ // from managed profile to owner or other way around.
+ if (mProfileSwitchMessageId != -1) {
+ Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
+ }
if (!mSafeForwardingMode) {
startActivity(intent);
+ onActivityStarted(intent);
return;
}
try {
startActivityAsCaller(intent, null, UserHandle.USER_NULL);
+ onActivityStarted(intent);
} catch (RuntimeException e) {
String launchedFromPackage;
try {
@@ -656,6 +735,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
+ public void onActivityStarted(Intent intent) {
+ // Do nothing
+ }
+
void showAppDetails(ResolveInfo ri) {
Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
@@ -663,6 +746,17 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
startActivity(in);
}
+ Intent intentForDisplayResolveInfo(DisplayResolveInfo dri) {
+ Intent intent = new Intent(dri.origIntent != null ? dri.origIntent :
+ getReplacementIntent(dri.ri.activityInfo, mIntent));
+ intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+ |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+ ActivityInfo ai = dri.ri.activityInfo;
+ intent.setComponent(new ComponentName(
+ ai.applicationInfo.packageName, ai.name));
+ return intent;
+ }
+
private final class DisplayResolveInfo {
ResolveInfo ri;
CharSequence displayLabel;
@@ -683,7 +777,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private final Intent[] mInitialIntents;
private final List<ResolveInfo> mBaseResolveList;
private ResolveInfo mLastChosen;
- private final Intent mIntent;
+ private DisplayResolveInfo mOtherProfile;
private final int mLaunchedFromUid;
private final LayoutInflater mInflater;
@@ -693,10 +787,8 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
private int mLastChosenPosition = -1;
private boolean mFilterLastUsed;
- public ResolveListAdapter(Context context, Intent intent,
- Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
- boolean filterLastUsed) {
- mIntent = new Intent(intent);
+ public ResolveListAdapter(Context context, Intent[] initialIntents,
+ List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
mInitialIntents = initialIntents;
mBaseResolveList = rList;
mLaunchedFromUid = launchedFromUid;
@@ -707,11 +799,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
public void handlePackagesChanged() {
- final int oldItemCount = getCount();
rebuildList();
notifyDataSetChanged();
- final int newItemCount = getCount();
- if (newItemCount == 0) {
+ if (getCount() == 0) {
// We no longer have any items... just finish the activity.
finish();
}
@@ -725,6 +815,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
return null;
}
+ public DisplayResolveInfo getOtherProfile() {
+ return mOtherProfile;
+ }
+
public int getFilteredPosition() {
if (mFilterLastUsed && mLastChosenPosition >= 0) {
return mLastChosenPosition;
@@ -801,7 +895,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
if (N > 1) {
Comparator<ResolveInfo> rComparator =
- new ResolverComparator(ResolverActivity.this);
+ new ResolverComparator(ResolverActivity.this, mIntent);
Collections.sort(currentResolveList, rComparator);
}
// First put the initial items at the top.
@@ -819,6 +913,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
+ UserManager userManager =
+ (UserManager) getSystemService(Context.USER_SERVICE);
+ if (userManager.isManagedProfile()) {
+ ri.noResourceId = true;
+ }
if (ii instanceof LabeledIntent) {
LabeledIntent li = (LabeledIntent)ii;
ri.resolvePackageName = li.getSourcePackage();
@@ -826,7 +925,7 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
ri.nonLocalizedLabel = li.getNonLocalizedLabel();
ri.icon = li.getIconResource();
}
- mList.add(new DisplayResolveInfo(ri,
+ addResolveInfo(new DisplayResolveInfo(ri,
ri.loadLabel(getPackageManager()), null, ii));
}
}
@@ -857,6 +956,13 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
// Process last group
processGroup(currentResolveList, start, (N-1), r0, r0Label);
}
+
+ // Layout doesn't handle both profile button and last chosen
+ // so disable last chosen if profile button is present.
+ if (mOtherProfile != null && mLastChosenPosition >= 0) {
+ mLastChosenPosition = -1;
+ mFilterLastUsed = false;
+ }
}
private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
@@ -864,14 +970,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
// Process labels from start to i
int num = end - start+1;
if (num == 1) {
- if (mLastChosen != null
- && mLastChosen.activityInfo.packageName.equals(
- ro.activityInfo.packageName)
- && mLastChosen.activityInfo.name.equals(ro.activityInfo.name)) {
- mLastChosenPosition = mList.size();
- }
// No duplicate labels. Use label for entry at start
- mList.add(new DisplayResolveInfo(ro, roLabel, null, null));
+ addResolveInfo(new DisplayResolveInfo(ro, roLabel, null, null));
+ updateLastChosenPosition(ro);
} else {
mShowExtended = true;
boolean usePkg = false;
@@ -899,40 +1000,45 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
for (int k = start; k <= end; k++) {
ResolveInfo add = rList.get(k);
- if (mLastChosen != null
- && mLastChosen.activityInfo.packageName.equals(
- add.activityInfo.packageName)
- && mLastChosen.activityInfo.name.equals(add.activityInfo.name)) {
- mLastChosenPosition = mList.size();
- }
if (usePkg) {
// Use application name for all entries from start to end-1
- mList.add(new DisplayResolveInfo(add, roLabel,
+ addResolveInfo(new DisplayResolveInfo(add, roLabel,
add.activityInfo.packageName, null));
} else {
// Use package name for all entries from start to end-1
- mList.add(new DisplayResolveInfo(add, roLabel,
+ addResolveInfo(new DisplayResolveInfo(add, roLabel,
add.activityInfo.applicationInfo.loadLabel(mPm), null));
}
+ updateLastChosenPosition(add);
}
}
}
+ private void updateLastChosenPosition(ResolveInfo info) {
+ if (mLastChosen != null
+ && mLastChosen.activityInfo.packageName.equals(info.activityInfo.packageName)
+ && mLastChosen.activityInfo.name.equals(info.activityInfo.name)) {
+ mLastChosenPosition = mList.size() - 1;
+ }
+ }
+
+ private void addResolveInfo(DisplayResolveInfo dri) {
+ if (dri.ri.targetUserId != UserHandle.USER_CURRENT && mOtherProfile == null) {
+ // So far we only support a single other profile at a time.
+ // The first one we see gets special treatment.
+ mOtherProfile = dri;
+ } else {
+ mList.add(dri);
+ }
+ }
+
public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
return (filtered ? getItem(position) : mList.get(position)).ri;
}
public Intent intentForPosition(int position, boolean filtered) {
DisplayResolveInfo dri = filtered ? getItem(position) : mList.get(position);
-
- Intent intent = new Intent(dri.origIntent != null ? dri.origIntent :
- getReplacementIntent(dri.ri.activityInfo.packageName, mIntent));
- intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
- |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
- ActivityInfo ai = dri.ri.activityInfo;
- intent.setComponent(new ComponentName(
- ai.applicationInfo.packageName, ai.name));
- return intent;
+ return intentForDisplayResolveInfo(dri);
}
public int getCount() {
@@ -1023,6 +1129,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
@Override
protected void onPostExecute(DisplayResolveInfo info) {
+ if (mProfileView != null && mAdapter.getOtherProfile() == info) {
+ bindProfileView();
+ }
mAdapter.notifyDataSetChanged();
}
}
@@ -1049,11 +1158,20 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
+ static final boolean isSpecificUriMatch(int match) {
+ match = match&IntentFilter.MATCH_CATEGORY_MASK;
+ return match >= IntentFilter.MATCH_CATEGORY_HOST
+ && match <= IntentFilter.MATCH_CATEGORY_PATH;
+ }
+
class ResolverComparator implements Comparator<ResolveInfo> {
private final Collator mCollator;
+ private final boolean mHttp;
- public ResolverComparator(Context context) {
+ public ResolverComparator(Context context, Intent intent) {
mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+ String scheme = intent.getScheme();
+ mHttp = "http".equals(scheme) || "https".equals(scheme);
}
@Override
@@ -1063,6 +1181,17 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
return 1;
}
+ if (mHttp) {
+ // Special case: we want filters that match URI paths/schemes to be
+ // ordered before others. This is for the case when opening URIs,
+ // to make native apps go above browsers.
+ final boolean lhsSpecific = isSpecificUriMatch(lhs.match);
+ final boolean rhsSpecific = isSpecificUriMatch(rhs.match);
+ if (lhsSpecific != rhsSpecific) {
+ return lhsSpecific ? -1 : 1;
+ }
+ }
+
if (mStats != null) {
final long timeDiff =
getPackageTimeSpent(rhs.activityInfo.packageName) -
@@ -1093,4 +1222,3 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic
}
}
}
-
diff --git a/core/java/com/android/internal/app/ShutdownActivity.java b/core/java/com/android/internal/app/ShutdownActivity.java
new file mode 100644
index 0000000..97521cf
--- /dev/null
+++ b/core/java/com/android/internal/app/ShutdownActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 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.internal.app;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+public class ShutdownActivity extends Activity {
+
+ private static final String TAG = "ShutdownActivity";
+ private boolean mReboot;
+ private boolean mConfirm;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Intent intent = getIntent();
+ mReboot = Intent.ACTION_REBOOT.equals(intent.getAction());
+ mConfirm = intent.getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false);
+ Slog.i(TAG, "onCreate(): confirm=" + mConfirm);
+
+ Thread thr = new Thread("ShutdownActivity") {
+ @Override
+ public void run() {
+ IPowerManager pm = IPowerManager.Stub.asInterface(
+ ServiceManager.getService(Context.POWER_SERVICE));
+ try {
+ if (mReboot) {
+ pm.reboot(mConfirm, null, false);
+ } else {
+ pm.shutdown(mConfirm, false);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ };
+ thr.start();
+ finish();
+ // Wait for us to tell the power manager to shutdown.
+ try {
+ thr.join();
+ } catch (InterruptedException e) {
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 4410f25..34b9dcb 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -40,7 +40,6 @@ import com.android.internal.widget.ToolbarWidgetWrapper;
import java.util.ArrayList;
public class ToolbarActionBar extends ActionBar {
- private Toolbar mToolbar;
private DecorToolbar mDecorToolbar;
private boolean mToolbarMenuPrepared;
private Window.Callback mWindowCallback;
@@ -66,7 +65,6 @@ public class ToolbarActionBar extends ActionBar {
};
public ToolbarActionBar(Toolbar toolbar, CharSequence title, Window.Callback windowCallback) {
- mToolbar = toolbar;
mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false);
mWindowCallback = new ToolbarCallbackWrapper(windowCallback);
mDecorToolbar.setWindowCallback(mWindowCallback);
@@ -91,8 +89,8 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setCustomView(int resId) {
- final LayoutInflater inflater = LayoutInflater.from(mToolbar.getContext());
- setCustomView(inflater.inflate(resId, mToolbar, false));
+ final LayoutInflater inflater = LayoutInflater.from(mDecorToolbar.getContext());
+ setCustomView(inflater.inflate(resId, mDecorToolbar.getViewGroup(), false));
}
@Override
@@ -132,17 +130,17 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setElevation(float elevation) {
- mToolbar.setElevation(elevation);
+ mDecorToolbar.getViewGroup().setElevation(elevation);
}
@Override
public float getElevation() {
- return mToolbar.getElevation();
+ return mDecorToolbar.getViewGroup().getElevation();
}
@Override
public Context getThemedContext() {
- return mToolbar.getContext();
+ return mDecorToolbar.getContext();
}
@Override
@@ -152,12 +150,12 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setHomeAsUpIndicator(Drawable indicator) {
- mToolbar.setNavigationIcon(indicator);
+ mDecorToolbar.setNavigationIcon(indicator);
}
@Override
public void setHomeAsUpIndicator(int resId) {
- mToolbar.setNavigationIcon(resId);
+ mDecorToolbar.setNavigationIcon(resId);
}
@Override
@@ -280,7 +278,7 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void setBackgroundDrawable(@Nullable Drawable d) {
- mToolbar.setBackground(d);
+ mDecorToolbar.setBackgroundDrawable(d);
}
@Override
@@ -290,12 +288,12 @@ public class ToolbarActionBar extends ActionBar {
@Override
public CharSequence getTitle() {
- return mToolbar.getTitle();
+ return mDecorToolbar.getTitle();
}
@Override
public CharSequence getSubtitle() {
- return mToolbar.getSubtitle();
+ return mDecorToolbar.getSubtitle();
}
@Override
@@ -389,44 +387,44 @@ public class ToolbarActionBar extends ActionBar {
@Override
public int getHeight() {
- return mToolbar.getHeight();
+ return mDecorToolbar.getHeight();
}
@Override
public void show() {
// TODO: Consider a better transition for this.
// Right now use no automatic transition so that the app can supply one if desired.
- mToolbar.setVisibility(View.VISIBLE);
+ mDecorToolbar.setVisibility(View.VISIBLE);
}
@Override
public void hide() {
// TODO: Consider a better transition for this.
// Right now use no automatic transition so that the app can supply one if desired.
- mToolbar.setVisibility(View.GONE);
+ mDecorToolbar.setVisibility(View.GONE);
}
@Override
public boolean isShowing() {
- return mToolbar.getVisibility() == View.VISIBLE;
+ return mDecorToolbar.getVisibility() == View.VISIBLE;
}
@Override
public boolean openOptionsMenu() {
- return mToolbar.showOverflowMenu();
+ return mDecorToolbar.showOverflowMenu();
}
@Override
public boolean invalidateOptionsMenu() {
- mToolbar.removeCallbacks(mMenuInvalidator);
- mToolbar.postOnAnimation(mMenuInvalidator);
+ mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
+ mDecorToolbar.getViewGroup().postOnAnimation(mMenuInvalidator);
return true;
}
@Override
public boolean collapseActionView() {
- if (mToolbar.hasExpandedActionView()) {
- mToolbar.collapseActionView();
+ if (mDecorToolbar.hasExpandedActionView()) {
+ mDecorToolbar.collapseActionView();
return true;
}
return false;
@@ -434,10 +432,10 @@ public class ToolbarActionBar extends ActionBar {
void populateOptionsMenu() {
if (!mMenuCallbackSet) {
- mToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback());
+ mDecorToolbar.setMenuCallbacks(new ActionMenuPresenterCallback(), new MenuBuilderCallback());
mMenuCallbackSet = true;
}
- final Menu menu = mToolbar.getMenu();
+ final Menu menu = mDecorToolbar.getMenu();
final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
if (mb != null) {
mb.stopDispatchingItemsChanged();
@@ -518,7 +516,7 @@ public class ToolbarActionBar extends ActionBar {
}
mClosingActionMenu = true;
- mToolbar.dismissPopupMenus();
+ mDecorToolbar.dismissPopupMenus();
if (mWindowCallback != null) {
mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
}
@@ -536,7 +534,7 @@ public class ToolbarActionBar extends ActionBar {
@Override
public void onMenuModeChange(MenuBuilder menu) {
if (mWindowCallback != null) {
- if (mToolbar.isOverflowMenuShowing()) {
+ if (mDecorToolbar.isOverflowMenuShowing()) {
mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
} else if (mWindowCallback.onPreparePanel(Window.FEATURE_OPTIONS_PANEL,
null, menu)) {
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 2377c22..061b535 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -496,7 +496,7 @@ public class WindowDecorActionBar extends ActionBar implements
mOverlayLayout.setHideOnContentScrollEnabled(false);
mContextView.killMode();
- ActionModeImpl mode = new ActionModeImpl(callback);
+ ActionModeImpl mode = new ActionModeImpl(mContextView.getContext(), callback);
if (mode.dispatchOnCreate()) {
mode.invalidate();
mContextView.initForMode(mode);
@@ -876,7 +876,7 @@ public class WindowDecorActionBar extends ActionBar implements
currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
outValue, true);
final int targetThemeRes = outValue.resourceId;
-
+
if (targetThemeRes != 0 && mContext.getThemeResId() != targetThemeRes) {
mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
} else {
@@ -885,7 +885,7 @@ public class WindowDecorActionBar extends ActionBar implements
}
return mThemedContext;
}
-
+
@Override
public boolean isTitleTruncated() {
return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
@@ -933,23 +933,26 @@ public class WindowDecorActionBar extends ActionBar implements
}
/**
- * @hide
+ * @hide
*/
public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
+ private final Context mActionModeContext;
+ private final MenuBuilder mMenu;
+
private ActionMode.Callback mCallback;
- private MenuBuilder mMenu;
private WeakReference<View> mCustomView;
-
- public ActionModeImpl(ActionMode.Callback callback) {
+
+ public ActionModeImpl(Context context, ActionMode.Callback callback) {
+ mActionModeContext = context;
mCallback = callback;
- mMenu = new MenuBuilder(getThemedContext())
+ mMenu = new MenuBuilder(context)
.setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
mMenu.setCallback(this);
}
@Override
public MenuInflater getMenuInflater() {
- return new MenuInflater(getThemedContext());
+ return new MenuInflater(mActionModeContext);
}
@Override
@@ -990,6 +993,13 @@ public class WindowDecorActionBar extends ActionBar implements
@Override
public void invalidate() {
+ if (mActionMode != this) {
+ // Not the active action mode - no-op. It's possible we are
+ // currently deferring onDestroy, so the app doesn't yet know we
+ // are going away and is trying to use us. That's also a no-op.
+ return;
+ }
+
mMenu.stopDispatchingItemsChanged();
try {
mCallback.onPrepareActionMode(this, mMenu);
@@ -1042,7 +1052,7 @@ public class WindowDecorActionBar extends ActionBar implements
public CharSequence getSubtitle() {
return mContextView.getSubtitle();
}
-
+
@Override
public void setTitleOptionalHint(boolean titleOptional) {
super.setTitleOptionalHint(titleOptional);
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index d8dffe0..044383e 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -35,6 +35,8 @@ import android.util.Log;
import com.android.org.bouncycastle.util.encoders.Base64;
+import libcore.io.IoUtils;
+
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -559,11 +561,7 @@ public class LocalTransport extends BackupTransport {
// Full restore handling
private void resetFullRestoreState() {
- try {
- mCurFullRestoreStream.close();
- } catch (IOException e) {
- Log.w(TAG, "Unable to close full restore input stream");
- }
+ IoUtils.closeQuietly(mCurFullRestoreStream);
mCurFullRestoreStream = null;
mFullRestoreSocketStream = null;
mFullRestoreBuffer = null;
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 9df8ad5..eff44bd 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -24,6 +24,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
+import android.util.Slog;
import com.android.internal.os.BackgroundThread;
import java.util.HashSet;
@@ -279,8 +280,8 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL);
if (mChangeUserId == UserHandle.USER_NULL) {
- throw new IllegalArgumentException(
- "Intent broadcast does not contain user handle: " + intent);
+ Slog.w("PackageMonitor", "Intent broadcast does not contain user handle: " + intent);
+ return;
}
onBeginPackageChanges();
diff --git a/core/java/com/android/internal/content/ReferrerIntent.aidl b/core/java/com/android/internal/content/ReferrerIntent.aidl
new file mode 100644
index 0000000..7cf6774
--- /dev/null
+++ b/core/java/com/android/internal/content/ReferrerIntent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2014, 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.internal.content;
+
+parcelable ReferrerIntent;
diff --git a/core/java/com/android/internal/content/ReferrerIntent.java b/core/java/com/android/internal/content/ReferrerIntent.java
new file mode 100644
index 0000000..8d9a1cf
--- /dev/null
+++ b/core/java/com/android/internal/content/ReferrerIntent.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 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.internal.content;
+
+import android.content.Intent;
+import android.os.Parcel;
+
+/**
+ * Subclass of Intent that also contains referrer (as a package name) information.
+ */
+public class ReferrerIntent extends Intent {
+ public final String mReferrer;
+
+ public ReferrerIntent(Intent baseIntent, String referrer) {
+ super(baseIntent);
+ mReferrer = referrer;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ super.writeToParcel(dest, parcelableFlags);
+ dest.writeString(mReferrer);
+ }
+
+ ReferrerIntent(Parcel in) {
+ readFromParcel(in);
+ mReferrer = in.readString();
+ }
+
+ public static final Creator<ReferrerIntent> CREATOR = new Creator<ReferrerIntent>() {
+ public ReferrerIntent createFromParcel(Parcel source) {
+ return new ReferrerIntent(source);
+ }
+ public ReferrerIntent[] newArray(int size) {
+ return new ReferrerIntent[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/http/multipart/FilePart.java b/core/java/com/android/internal/http/multipart/FilePart.java
index bfcda00..45e4be6 100644
--- a/core/java/com/android/internal/http/multipart/FilePart.java
+++ b/core/java/com/android/internal/http/multipart/FilePart.java
@@ -51,9 +51,14 @@ import org.apache.commons.logging.LogFactory;
* @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*
- * @since 2.0
+ * @since 2.0
*
+ * @deprecated Please use {@link java.net.URLConnection} and friends instead.
+ * The Apache HTTP client is no longer maintained and may be removed in a future
+ * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
*/
+@Deprecated
public class FilePart extends PartBase {
/** Default content encoding of file attachments. */
diff --git a/core/java/com/android/internal/http/multipart/MultipartEntity.java b/core/java/com/android/internal/http/multipart/MultipartEntity.java
index 2c5e7f6..5319251 100644
--- a/core/java/com/android/internal/http/multipart/MultipartEntity.java
+++ b/core/java/com/android/internal/http/multipart/MultipartEntity.java
@@ -80,7 +80,13 @@ import org.apache.commons.logging.LogFactory;
* </pre>
*
* @since 3.0
+ *
+ * @deprecated Please use {@link java.net.URLConnection} and friends instead.
+ * The Apache HTTP client is no longer maintained and may be removed in a future
+ * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
*/
+@Deprecated
public class MultipartEntity extends AbstractHttpEntity {
private static final Log log = LogFactory.getLog(MultipartEntity.class);
diff --git a/core/java/com/android/internal/http/multipart/Part.java b/core/java/com/android/internal/http/multipart/Part.java
index cb1b546..1d66dc6 100644
--- a/core/java/com/android/internal/http/multipart/Part.java
+++ b/core/java/com/android/internal/http/multipart/Part.java
@@ -48,7 +48,13 @@ import org.apache.commons.logging.LogFactory;
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*
* @since 2.0
+ *
+ * @deprecated Please use {@link java.net.URLConnection} and friends instead.
+ * The Apache HTTP client is no longer maintained and may be removed in a future
+ * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
*/
+@Deprecated
public abstract class Part {
/** Log object for this class. */
diff --git a/core/java/com/android/internal/http/multipart/StringPart.java b/core/java/com/android/internal/http/multipart/StringPart.java
index c98257e..73d0f90 100644
--- a/core/java/com/android/internal/http/multipart/StringPart.java
+++ b/core/java/com/android/internal/http/multipart/StringPart.java
@@ -46,7 +46,13 @@ import org.apache.commons.logging.LogFactory;
* @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
*
* @since 2.0
+ *
+ * @deprecated Please use {@link java.net.URLConnection} and friends instead.
+ * The Apache HTTP client is no longer maintained and may be removed in a future
+ * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
*/
+@Deprecated
public class StringPart extends PartBase {
/** Log object for this class. */
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index ac915d1..183527c 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -16,6 +16,8 @@
package com.android.internal.inputmethod;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -34,7 +36,9 @@ import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.TextServicesManager;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
@@ -115,8 +119,8 @@ public class InputMethodUtils {
}
/**
- * @deprecated Use {@link Locale} returned from
- * {@link #getFallbackLocaleForDefaultIme(ArrayList)} instead.
+ * @deprecated Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean,
+ * Locale, boolean, String)} instead.
*/
@Deprecated
public static boolean isSystemImeThatHasEnglishKeyboardSubtype(InputMethodInfo imi) {
@@ -126,25 +130,60 @@ public class InputMethodUtils {
return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage(), SUBTYPE_MODE_KEYBOARD);
}
+ private static boolean isSystemImeThatHasSubtypeOf(final InputMethodInfo imi,
+ final Context context, final boolean checkDefaultAttribute,
+ @Nullable final Locale requiredLocale, final boolean checkCountry,
+ final String requiredSubtypeMode) {
+ if (!isSystemIme(imi)) {
+ return false;
+ }
+ if (checkDefaultAttribute && !imi.isDefault(context)) {
+ return false;
+ }
+ if (!containsSubtypeOf(imi, requiredLocale, checkCountry, requiredSubtypeMode)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Nullable
public static Locale getFallbackLocaleForDefaultIme(final ArrayList<InputMethodInfo> imis,
final Context context) {
+ // At first, find the fallback locale from the IMEs that are declared as "default" in the
+ // current locale. Note that IME developers can declare an IME as "default" only for
+ // some particular locales but "not default" for other locales.
for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (isSystemIme(imi) && imi.isDefault(context) &&
- containsSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_KEYBOARD)) {
+ if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
+ true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
+ return fallbackLocale;
+ }
+ }
+ }
+ // If no fallback locale is found in the above condition, find fallback locales regardless
+ // of the "default" attribute as a last resort.
+ for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
+ for (int i = 0; i < imis.size(); ++i) {
+ if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
+ false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
return fallbackLocale;
}
}
}
+ Slog.w(TAG, "Found no fallback locale. imis=" + Arrays.toString(imis.toArray()));
return null;
}
- private static boolean isSystemAuxilialyImeThatHasAutomaticSubtype(InputMethodInfo imi) {
+ private static boolean isSystemAuxilialyImeThatHasAutomaticSubtype(final InputMethodInfo imi,
+ final Context context, final boolean checkDefaultAttribute) {
if (!isSystemIme(imi)) {
return false;
}
+ if (checkDefaultAttribute && !imi.isDefault(context)) {
+ return false;
+ }
if (!imi.isAuxiliaryIme()) {
return false;
}
@@ -166,98 +205,184 @@ public class InputMethodUtils {
}
}
- public static ArrayList<InputMethodInfo> getDefaultEnabledImes(
- Context context, boolean isSystemReady, ArrayList<InputMethodInfo> imis) {
- // OK to store null in fallbackLocale because isImeThatHasSubtypeOf() is null-tolerant.
- final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
+ private static final class InputMethodListBuilder {
+ // Note: We use LinkedHashSet instead of android.util.ArraySet because the enumeration
+ // order can have non-trivial effect in the call sites.
+ @NonNull
+ private final LinkedHashSet<InputMethodInfo> mInputMethodSet = new LinkedHashSet<>();
- if (!isSystemReady) {
- final ArrayList<InputMethodInfo> retval = new ArrayList<>();
+ public InputMethodListBuilder fillImes(final ArrayList<InputMethodInfo> imis,
+ final Context context, final boolean checkDefaultAttribute,
+ @Nullable final Locale locale, final boolean checkCountry,
+ final String requiredSubtypeMode) {
for (int i = 0; i < imis.size(); ++i) {
final InputMethodInfo imi = imis.get(i);
- // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
- if (isSystemIme(imi) && imi.isDefault(context) &&
- isImeThatHasSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_KEYBOARD)) {
- retval.add(imi);
+ if (isSystemImeThatHasSubtypeOf(imi, context, checkDefaultAttribute, locale,
+ checkCountry, requiredSubtypeMode)) {
+ mInputMethodSet.add(imi);
}
}
- return retval;
+ return this;
}
- // OK to store null in fallbackLocale because isImeThatHasSubtypeOf() is null-tolerant.
- final Locale systemLocale = getSystemLocaleFromContext(context);
- // TODO: Use LinkedHashSet to simplify the code.
- final ArrayList<InputMethodInfo> retval = new ArrayList<>();
- boolean systemLocaleKeyboardImeFound = false;
-
- // First, try to find IMEs with taking the system locale country into consideration.
- for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (!isSystemIme(imi) || !imi.isDefault(context)) {
- continue;
- }
- final boolean isSystemLocaleKeyboardIme = isImeThatHasSubtypeOf(imi, systemLocale,
- false /* ignoreCountry */, SUBTYPE_MODE_KEYBOARD);
- // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
- // TODO: Use LinkedHashSet to simplify the code.
- if (isSystemLocaleKeyboardIme ||
- isImeThatHasSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_ANY)) {
- retval.add(imi);
+ // TODO: The behavior of InputMethodSubtype#overridesImplicitlyEnabledSubtype() should be
+ // documented more clearly.
+ public InputMethodListBuilder fillAuxiliaryImes(final ArrayList<InputMethodInfo> imis,
+ final Context context) {
+ // If one or more auxiliary input methods are available, OK to stop populating the list.
+ for (final InputMethodInfo imi : mInputMethodSet) {
+ if (imi.isAuxiliaryIme()) {
+ return this;
+ }
}
- systemLocaleKeyboardImeFound |= isSystemLocaleKeyboardIme;
- }
-
- // System locale country doesn't match any IMEs, try to find IMEs in a country-agnostic
- // way.
- if (!systemLocaleKeyboardImeFound) {
+ boolean added = false;
for (int i = 0; i < imis.size(); ++i) {
final InputMethodInfo imi = imis.get(i);
- if (!isSystemIme(imi) || !imi.isDefault(context)) {
- continue;
- }
- if (isImeThatHasSubtypeOf(imi, fallbackLocale, false /* ignoreCountry */,
- SUBTYPE_MODE_KEYBOARD)) {
- // IMEs that have fallback locale are already added in the previous loop. We
- // don't need to add them again here.
- // TODO: Use LinkedHashSet to simplify the code.
- continue;
+ if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
+ true /* checkDefaultAttribute */)) {
+ mInputMethodSet.add(imi);
+ added = true;
}
- if (isImeThatHasSubtypeOf(imi, systemLocale, true /* ignoreCountry */,
- SUBTYPE_MODE_ANY)) {
- retval.add(imi);
+ }
+ if (added) {
+ return this;
+ }
+ for (int i = 0; i < imis.size(); ++i) {
+ final InputMethodInfo imi = imis.get(i);
+ if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
+ false /* checkDefaultAttribute */)) {
+ mInputMethodSet.add(imi);
}
}
+ return this;
}
- // If one or more auxiliary input methods are available, OK to stop populating the list.
- for (int i = 0; i < retval.size(); ++i) {
- if (retval.get(i).isAuxiliaryIme()) {
- return retval;
- }
+ public boolean isEmpty() {
+ return mInputMethodSet.isEmpty();
}
- for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi)) {
- retval.add(imi);
- }
+
+ @NonNull
+ public ArrayList<InputMethodInfo> build() {
+ return new ArrayList<>(mInputMethodSet);
}
- return retval;
}
- public static boolean isImeThatHasSubtypeOf(final InputMethodInfo imi,
- final Locale locale, final boolean ignoreCountry, final String mode) {
- if (locale == null) {
- return false;
- }
- return containsSubtypeOf(imi, locale, ignoreCountry, mode);
+ private static InputMethodListBuilder getMinimumKeyboardSetWithoutSystemLocale(
+ final ArrayList<InputMethodInfo> imis, final Context context,
+ @Nullable final Locale fallbackLocale) {
+ // Before the system becomes ready, we pick up at least one keyboard in the following order.
+ // The first user (device owner) falls into this category.
+ // 1. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
+ // 2. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
+ // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
+ // 4. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: false
+ // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
+
+ final InputMethodListBuilder builder = new InputMethodListBuilder();
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ Slog.w(TAG, "No software keyboard is found. imis=" + Arrays.toString(imis.toArray())
+ + " fallbackLocale=" + fallbackLocale);
+ return builder;
+ }
+
+ private static InputMethodListBuilder getMinimumKeyboardSetWithSystemLocale(
+ final ArrayList<InputMethodInfo> imis, final Context context,
+ @Nullable final Locale systemLocale, @Nullable final Locale fallbackLocale) {
+ // Once the system becomes ready, we pick up at least one keyboard in the following order.
+ // Secondary users fall into this category in general.
+ // 1. checkDefaultAttribute: true, locale: systemLocale, checkCountry: true
+ // 2. checkDefaultAttribute: true, locale: systemLocale, checkCountry: false
+ // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
+ // 4. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
+ // 5. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
+ // 6. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: false
+ // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
+
+ final InputMethodListBuilder builder = new InputMethodListBuilder();
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ Slog.w(TAG, "No software keyboard is found. imis=" + Arrays.toString(imis.toArray())
+ + " systemLocale=" + systemLocale + " fallbackLocale=" + fallbackLocale);
+ return builder;
+ }
+
+ public static ArrayList<InputMethodInfo> getDefaultEnabledImes(final Context context,
+ final boolean isSystemReady, final ArrayList<InputMethodInfo> imis) {
+ final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
+ if (!isSystemReady) {
+ // When the system is not ready, the system locale is not stable and reliable. Hence
+ // we will pick up IMEs that support software keyboard based on the fallback locale.
+ // Also pick up suitable IMEs regardless of the software keyboard support.
+ // (e.g. Voice IMEs)
+ return getMinimumKeyboardSetWithoutSystemLocale(imis, context, fallbackLocale)
+ .fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_ANY)
+ .build();
+ }
+
+ // When the system is ready, we will primarily rely on the system locale, but also keep
+ // relying on the fallback locale as a last resort.
+ // Also pick up suitable IMEs regardless of the software keyboard support (e.g. Voice IMEs),
+ // then pick up suitable auxiliary IMEs when necessary (e.g. Voice IMEs with "automatic"
+ // subtype)
+ final Locale systemLocale = getSystemLocaleFromContext(context);
+ return getMinimumKeyboardSetWithSystemLocale(imis, context, systemLocale, fallbackLocale)
+ .fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ true /* checkCountry */, SUBTYPE_MODE_ANY)
+ .fillAuxiliaryImes(imis, context)
+ .build();
}
/**
- * @deprecated Use {@link #isSystemIme(InputMethodInfo)} and
- * {@link InputMethodInfo#isDefault(Context)} and
- * {@link #isImeThatHasSubtypeOf(InputMethodInfo, Locale, boolean, String))} instead.
+ * @deprecated Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean,
+ * Locale, boolean, String)} instead.
*/
@Deprecated
public static boolean isValidSystemDefaultIme(
@@ -285,22 +410,25 @@ public class InputMethodUtils {
}
public static boolean containsSubtypeOf(final InputMethodInfo imi,
- final Locale locale, final boolean ignoreCountry, final String mode) {
+ @Nullable final Locale locale, final boolean checkCountry, final String mode) {
+ if (locale == null) {
+ return false;
+ }
final int N = imi.getSubtypeCount();
for (int i = 0; i < N; ++i) {
final InputMethodSubtype subtype = imi.getSubtypeAt(i);
- if (ignoreCountry) {
- final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
- subtype.getLocale()));
- if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
- continue;
- }
- } else {
+ if (checkCountry) {
// TODO: Use {@link Locale#toLanguageTag()} and
// {@link Locale#forLanguageTag(languageTag)} instead.
if (!TextUtils.equals(subtype.getLocale(), locale.toString())) {
continue;
}
+ } else {
+ final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
+ subtype.getLocale()));
+ if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
+ continue;
+ }
}
if (mode == SUBTYPE_MODE_ANY || TextUtils.isEmpty(mode) ||
mode.equalsIgnoreCase(subtype.getMode())) {
@@ -465,19 +593,9 @@ public class InputMethodUtils {
return applicableSubtypes;
}
- private static List<InputMethodSubtype> getEnabledInputMethodSubtypeList(
- Context context, InputMethodInfo imi, List<InputMethodSubtype> enabledSubtypes,
- boolean allowsImplicitlySelectedSubtypes) {
- if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
- enabledSubtypes = InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
- context.getResources(), imi);
- }
- return InputMethodSubtype.sort(context, 0, imi, enabledSubtypes);
- }
-
/**
* Returns the language component of a given locale string.
- * TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}
+ * TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(String)}
*/
public static String getLanguageFromLocaleString(String locale) {
final int idx = locale.indexOf('_');
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 3d016be..921f1fe 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -24,7 +24,9 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
+import android.net.IpPrefix;
import android.net.LinkAddress;
+import android.net.Network;
import android.net.RouteInfo;
import android.os.Parcel;
import android.os.Parcelable;
@@ -99,6 +101,7 @@ public class VpnConfig implements Parcelable {
public boolean allowBypass;
public boolean allowIPv4;
public boolean allowIPv6;
+ public Network[] underlyingNetworks;
public void updateAllowedFamilies(InetAddress address) {
if (address instanceof Inet4Address) {
@@ -115,9 +118,7 @@ public class VpnConfig implements Parcelable {
String[] routes = routesStr.trim().split(" ");
for (String route : routes) {
//each route is ip/prefix
- String[] split = route.split("/");
- RouteInfo info = new RouteInfo(new LinkAddress
- (InetAddress.parseNumericAddress(split[0]), Integer.parseInt(split[1])), null);
+ RouteInfo info = new RouteInfo(new IpPrefix(route), null);
this.routes.add(info);
updateAllowedFamilies(info.getDestination().getAddress());
}
@@ -130,9 +131,7 @@ public class VpnConfig implements Parcelable {
String[] addresses = addressesStr.trim().split(" ");
for (String address : addresses) {
//each address is ip/prefix
- String[] split = address.split("/");
- LinkAddress addr = new LinkAddress(InetAddress.parseNumericAddress(split[0]),
- Integer.parseInt(split[1]));
+ LinkAddress addr = new LinkAddress(address);
this.addresses.add(addr);
updateAllowedFamilies(addr.getAddress());
}
@@ -162,6 +161,7 @@ public class VpnConfig implements Parcelable {
out.writeInt(allowBypass ? 1 : 0);
out.writeInt(allowIPv4 ? 1 : 0);
out.writeInt(allowIPv6 ? 1 : 0);
+ out.writeTypedArray(underlyingNetworks, flags);
}
public static final Parcelable.Creator<VpnConfig> CREATOR =
@@ -186,6 +186,7 @@ public class VpnConfig implements Parcelable {
config.allowBypass = in.readInt() != 0;
config.allowIPv4 = in.readInt() != 0;
config.allowIPv6 = in.readInt() != 0;
+ config.underlyingNetworks = in.createTypedArray(Network.CREATOR);
return config;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index c00d209..20bb95e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -94,7 +94,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 114 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 116 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -374,6 +374,10 @@ public final class BatteryStatsImpl extends BatteryStats {
private int mPhoneServiceStateRaw = -1;
private int mPhoneSimStateRaw = -1;
+ private int mNumConnectivityChange;
+ private int mLoadedNumConnectivityChange;
+ private int mUnpluggedNumConnectivityChange;
+
/*
* Holds a SamplingTimer associated with each kernel wakelock name being tracked.
*/
@@ -2540,6 +2544,22 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PROC_START, name, uid);
}
+ public void noteProcessCrashLocked(String name, int uid) {
+ uid = mapUid(uid);
+ if (isOnBattery()) {
+ Uid u = getUidStatsLocked(uid);
+ u.getProcessStatsLocked(name).incNumCrashesLocked();
+ }
+ }
+
+ public void noteProcessAnrLocked(String name, int uid) {
+ uid = mapUid(uid);
+ if (isOnBattery()) {
+ Uid u = getUidStatsLocked(uid);
+ u.getProcessStatsLocked(name).incNumAnrsLocked();
+ }
+ }
+
public void noteProcessStateLocked(String name, int uid, int state) {
uid = mapUid(uid);
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3109,6 +3129,14 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public void noteConnectivityChangedLocked(int type, String extra) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_CONNECTIVITY_CHANGED,
+ extra, type);
+ mNumConnectivityChange++;
+ }
+
public void noteMobileRadioPowerState(int powerState, long timestampNs) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
@@ -3965,6 +3993,16 @@ public final class BatteryStatsImpl extends BatteryStats {
return mLowPowerModeEnabledTimer.getCountLocked(which);
}
+ @Override public int getNumConnectivityChange(int which) {
+ int val = mNumConnectivityChange;
+ if (which == STATS_CURRENT) {
+ val -= mLoadedNumConnectivityChange;
+ } else if (which == STATS_SINCE_UNPLUGGED) {
+ val -= mUnpluggedNumConnectivityChange;
+ }
+ return val;
+ }
+
@Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@@ -5374,6 +5412,16 @@ public final class BatteryStatsImpl extends BatteryStats {
int mStarts;
/**
+ * Number of times the process has crashed.
+ */
+ int mNumCrashes;
+
+ /**
+ * Number of times the process has had an ANR.
+ */
+ int mNumAnrs;
+
+ /**
* The amount of user time loaded from a previous save.
*/
long mLoadedUserTime;
@@ -5394,24 +5442,14 @@ public final class BatteryStatsImpl extends BatteryStats {
int mLoadedStarts;
/**
- * The amount of user time loaded from the previous run.
- */
- long mLastUserTime;
-
- /**
- * The amount of system time loaded from the previous run.
- */
- long mLastSystemTime;
-
- /**
- * The amount of foreground time loaded from the previous run
+ * Number of times the process has crashed from a previous save.
*/
- long mLastForegroundTime;
+ int mLoadedNumCrashes;
/**
- * The number of times the process has started from the previous run.
+ * Number of times the process has had an ANR from a previous save.
*/
- int mLastStarts;
+ int mLoadedNumAnrs;
/**
* The amount of user time when last unplugged.
@@ -5434,6 +5472,16 @@ public final class BatteryStatsImpl extends BatteryStats {
int mUnpluggedStarts;
/**
+ * Number of times the process has crashed before unplugged.
+ */
+ int mUnpluggedNumCrashes;
+
+ /**
+ * Number of times the process has had an ANR before unplugged.
+ */
+ int mUnpluggedNumAnrs;
+
+ /**
* Current process state.
*/
int mProcessState = PROCESS_STATE_NONE;
@@ -5453,6 +5501,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedSystemTime = mSystemTime;
mUnpluggedForegroundTime = mForegroundTime;
mUnpluggedStarts = mStarts;
+ mUnpluggedNumCrashes = mNumCrashes;
+ mUnpluggedNumAnrs = mNumAnrs;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -5460,13 +5510,11 @@ public final class BatteryStatsImpl extends BatteryStats {
void reset() {
mUserTime = mSystemTime = mForegroundTime = 0;
- mStarts = 0;
+ mStarts = mNumCrashes = mNumAnrs = 0;
mLoadedUserTime = mLoadedSystemTime = mLoadedForegroundTime = 0;
- mLoadedStarts = 0;
- mLastUserTime = mLastSystemTime = mLastForegroundTime = 0;
- mLastStarts = 0;
+ mLoadedStarts = mLoadedNumCrashes = mLoadedNumAnrs = 0;
mUnpluggedUserTime = mUnpluggedSystemTime = mUnpluggedForegroundTime = 0;
- mUnpluggedStarts = 0;
+ mUnpluggedStarts = mUnpluggedNumCrashes = mUnpluggedNumAnrs = 0;
for (int i = 0; i < mSpeedBins.length; i++) {
SamplingCounter c = mSpeedBins[i];
if (c != null) {
@@ -5565,14 +5613,20 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(mSystemTime);
out.writeLong(mForegroundTime);
out.writeInt(mStarts);
+ out.writeInt(mNumCrashes);
+ out.writeInt(mNumAnrs);
out.writeLong(mLoadedUserTime);
out.writeLong(mLoadedSystemTime);
out.writeLong(mLoadedForegroundTime);
out.writeInt(mLoadedStarts);
+ out.writeInt(mLoadedNumCrashes);
+ out.writeInt(mLoadedNumAnrs);
out.writeLong(mUnpluggedUserTime);
out.writeLong(mUnpluggedSystemTime);
out.writeLong(mUnpluggedForegroundTime);
out.writeInt(mUnpluggedStarts);
+ out.writeInt(mUnpluggedNumCrashes);
+ out.writeInt(mUnpluggedNumAnrs);
out.writeInt(mSpeedBins.length);
for (int i = 0; i < mSpeedBins.length; i++) {
@@ -5593,18 +5647,20 @@ public final class BatteryStatsImpl extends BatteryStats {
mSystemTime = in.readLong();
mForegroundTime = in.readLong();
mStarts = in.readInt();
+ mNumCrashes = in.readInt();
+ mNumAnrs = in.readInt();
mLoadedUserTime = in.readLong();
mLoadedSystemTime = in.readLong();
mLoadedForegroundTime = in.readLong();
mLoadedStarts = in.readInt();
- mLastUserTime = 0;
- mLastSystemTime = 0;
- mLastForegroundTime = 0;
- mLastStarts = 0;
+ mLoadedNumCrashes = in.readInt();
+ mLoadedNumAnrs = in.readInt();
mUnpluggedUserTime = in.readLong();
mUnpluggedSystemTime = in.readLong();
mUnpluggedForegroundTime = in.readLong();
mUnpluggedStarts = in.readInt();
+ mUnpluggedNumCrashes = in.readInt();
+ mUnpluggedNumAnrs = in.readInt();
int bins = in.readInt();
int steps = getCpuSpeedSteps();
@@ -5635,6 +5691,14 @@ public final class BatteryStatsImpl extends BatteryStats {
mStarts++;
}
+ public void incNumCrashesLocked() {
+ mNumCrashes++;
+ }
+
+ public void incNumAnrsLocked() {
+ mNumAnrs++;
+ }
+
@Override
public boolean isActive() {
return mActive;
@@ -5684,6 +5748,28 @@ public final class BatteryStatsImpl extends BatteryStats {
return val;
}
+ @Override
+ public int getNumCrashes(int which) {
+ int val = mNumCrashes;
+ if (which == STATS_CURRENT) {
+ val -= mLoadedNumCrashes;
+ } else if (which == STATS_SINCE_UNPLUGGED) {
+ val -= mUnpluggedNumCrashes;
+ }
+ return val;
+ }
+
+ @Override
+ public int getNumAnrs(int which) {
+ int val = mNumAnrs;
+ if (which == STATS_CURRENT) {
+ val -= mLoadedNumAnrs;
+ } else if (which == STATS_SINCE_UNPLUGGED) {
+ val -= mUnpluggedNumAnrs;
+ }
+ return val;
+ }
+
/* Called by ActivityManagerService when CPU times are updated. */
public void addSpeedStepTimes(long[] values) {
for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
@@ -6647,6 +6733,7 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i].reset(false);
}
+ mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset()) {
@@ -6868,6 +6955,17 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ private void recordShutdownLocked(final long elapsedRealtimeMs, final long uptimeMs) {
+ if (mRecordingHistory) {
+ mHistoryCur.currentTime = System.currentTimeMillis();
+ mLastRecordedClockTime = mHistoryCur.currentTime;
+ mLastRecordedClockRealtime = elapsedRealtimeMs;
+ addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_SHUTDOWN,
+ mHistoryCur);
+ mHistoryCur.currentTime = 0;
+ }
+ }
+
// This should probably be exposed in the API, though it's not critical
private static final int BATTERY_PLUGGED_NONE = 0;
@@ -7540,6 +7638,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public void shutdownLocked() {
+ recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
writeSyncLocked();
mShuttingDown = true;
}
@@ -7861,6 +7960,7 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
}
+ mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
mFlashlightOn = false;
mFlashlightOnTimer.readSummaryFromParcelLocked(in);
@@ -8022,6 +8122,8 @@ public final class BatteryStatsImpl extends BatteryStats {
p.mSystemTime = p.mLoadedSystemTime = in.readLong();
p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
p.mStarts = p.mLoadedStarts = in.readInt();
+ p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
+ p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
int NSB = in.readInt();
if (NSB > 100) {
Slog.w(TAG, "File corrupt: too many speed bins " + NSB);
@@ -8143,6 +8245,7 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
+ out.writeInt(mNumConnectivityChange);
mFlashlightOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
out.writeInt(mKernelWakelockStats.size());
@@ -8326,6 +8429,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(ps.mSystemTime);
out.writeLong(ps.mForegroundTime);
out.writeInt(ps.mStarts);
+ out.writeInt(ps.mNumCrashes);
+ out.writeInt(ps.mNumAnrs);
final int N = ps.mSpeedBins.length;
out.writeInt(N);
for (int i=0; i<N; i++) {
@@ -8444,6 +8549,9 @@ public final class BatteryStatsImpl extends BatteryStats {
mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
null, mOnBatteryTimeBase, in);
}
+ mNumConnectivityChange = in.readInt();
+ mLoadedNumConnectivityChange = in.readInt();
+ mUnpluggedNumConnectivityChange = in.readInt();
mAudioOnNesting = 0;
mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
mVideoOnNesting = 0;
@@ -8588,6 +8696,9 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
}
+ out.writeInt(mNumConnectivityChange);
+ out.writeInt(mLoadedNumConnectivityChange);
+ out.writeInt(mUnpluggedNumConnectivityChange);
mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
out.writeInt(mDischargeUnplugLevel);
out.writeInt(mDischargePlugLevel);
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 17685fd..99286cb 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -49,6 +49,10 @@ public class HandlerCaller {
mCallback = callback;
}
+ public Handler getHandler() {
+ return mH;
+ }
+
public void executeOrSendMessage(Message msg) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index 86f580d..b5338df 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -23,8 +23,11 @@ import android.os.Process;
import android.os.StrictMode;
import android.os.SystemClock;
import android.util.Slog;
+
import com.android.internal.util.FastPrintWriter;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
@@ -325,7 +328,12 @@ public class ProcessCpuTracker {
mBaseIdleTime = idletime;
}
- mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
+ final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
+ } finally {
+ StrictMode.setThreadPolicy(savedPolicy);
+ }
final float[] loadAverages = mLoadAverageData;
if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
@@ -847,12 +855,7 @@ public class ProcessCpuTracker {
} catch (java.io.FileNotFoundException e) {
} catch (java.io.IOException e) {
} finally {
- if (is != null) {
- try {
- is.close();
- } catch (java.io.IOException e) {
- }
- }
+ IoUtils.closeQuietly(is);
StrictMode.setThreadPolicy(savedPolicy);
}
return null;
diff --git a/core/java/com/android/internal/policy/IKeyguardService.aidl b/core/java/com/android/internal/policy/IKeyguardService.aidl
index 64f3bea..f93b1a1 100644
--- a/core/java/com/android/internal/policy/IKeyguardService.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardService.aidl
@@ -15,47 +15,34 @@
*/
package com.android.internal.policy;
-import android.view.MotionEvent;
-
import com.android.internal.policy.IKeyguardShowCallback;
+import com.android.internal.policy.IKeyguardStateCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import android.os.Bundle;
-interface IKeyguardService {
- boolean isShowing();
- boolean isSecure();
- boolean isShowingAndNotOccluded();
- boolean isInputRestricted();
- boolean isDismissable();
- oneway void verifyUnlock(IKeyguardExitCallback callback);
- oneway void keyguardDone(boolean authenticated, boolean wakeup);
-
+oneway interface IKeyguardService {
/**
* Sets the Keyguard as occluded when a window dismisses the Keyguard with flag
* FLAG_SHOW_ON_LOCK_SCREEN.
*
* @param isOccluded Whether the Keyguard is occluded by another window.
- * @return See IKeyguardServiceConstants.KEYGUARD_SERVICE_SET_OCCLUDED_*. This is needed because
- * PhoneWindowManager needs to set these flags immediately and can't wait for the
- * Keyguard thread to pick it up. In the hidden case, PhoneWindowManager is solely
- * responsible to make sure that the flags are unset.
*/
- int setOccluded(boolean isOccluded);
-
- oneway void dismiss();
- oneway void onDreamingStarted();
- oneway void onDreamingStopped();
- oneway void onScreenTurnedOff(int reason);
- oneway void onScreenTurnedOn(IKeyguardShowCallback callback);
- oneway void setKeyguardEnabled(boolean enabled);
- oneway void onSystemReady();
- oneway void doKeyguardTimeout(in Bundle options);
- oneway void setCurrentUser(int userId);
- oneway void showAssistant();
- oneway void dispatch(in MotionEvent event);
- oneway void launchCamera();
- oneway void onBootCompleted();
+ void setOccluded(boolean isOccluded);
+
+ void addStateMonitorCallback(IKeyguardStateCallback callback);
+ void verifyUnlock(IKeyguardExitCallback callback);
+ void keyguardDone(boolean authenticated, boolean wakeup);
+ void dismiss();
+ void onDreamingStarted();
+ void onDreamingStopped();
+ void onScreenTurnedOff(int reason);
+ void onScreenTurnedOn(IKeyguardShowCallback callback);
+ void setKeyguardEnabled(boolean enabled);
+ void onSystemReady();
+ void doKeyguardTimeout(in Bundle options);
+ void setCurrentUser(int userId);
+ void onBootCompleted();
/**
* Notifies that the activity behind has now been drawn and it's safe to remove the wallpaper
@@ -64,11 +51,11 @@ interface IKeyguardService {
* @param startTime the start time of the animation in uptime milliseconds
* @param fadeoutDuration the duration of the exit animation, in milliseconds
*/
- oneway void startKeyguardExitAnimation(long startTime, long fadeoutDuration);
+ void startKeyguardExitAnimation(long startTime, long fadeoutDuration);
/**
* Notifies the Keyguard that the activity that was starting has now been drawn and it's safe
* to start the keyguard dismiss sequence.
*/
- oneway void onActivityDrawn();
+ void onActivityDrawn();
}
diff --git a/core/java/com/android/internal/policy/IKeyguardServiceConstants.java b/core/java/com/android/internal/policy/IKeyguardServiceConstants.java
deleted file mode 100644
index b88174a..0000000
--- a/core/java/com/android/internal/policy/IKeyguardServiceConstants.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2014 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.internal.policy;
-
-/**
- * @hide
- */
-public class IKeyguardServiceConstants {
-
- /**
- * Constant for {@link com.android.internal.policy.IKeyguardService#setHidden(boolean)}:
- * Don't change the keyguard window flags.
- */
- public static final int KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_NONE = 0;
-
- /**
- * Constant for {@link com.android.internal.policy.IKeyguardService#setHidden(boolean)}:
- * Set the keyguard window flags to FLAG_SHOW_WALLPAPER and PRIVATE_FLAG_KEYGUARD.
- */
- public static final int KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_SET_FLAGS = 1;
-
- /**
- * Constant for {@link com.android.internal.policy.IKeyguardService#setHidden(boolean)}:
- * Unset the keyguard window flags to FLAG_SHOW_WALLPAPER and PRIVATE_FLAG_KEYGUARD.
- */
- public static final int KEYGUARD_SERVICE_SET_OCCLUDED_RESULT_UNSET_FLAGS = 2;
-}
diff --git a/core/java/com/android/internal/widget/ILockSettingsObserver.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
index 6c354d8..db3b40b 100644
--- a/core/java/com/android/internal/widget/ILockSettingsObserver.aidl
+++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.internal.policy;
-package com.android.internal.widget;
-
-/** {@hide} */
-oneway interface ILockSettingsObserver {
- void onLockSettingChanged(in String key, in int userId);
-}
+interface IKeyguardStateCallback {
+ void onShowingStateChanged(boolean showing);
+ void onSimSecureStateChanged(boolean simSecure);
+ void onInputRestrictedStateChanged(boolean inputRestricted);
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 57472f8..a3c0db4 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -42,5 +42,6 @@ oneway interface IStatusBar
void toggleRecentApps();
void preloadRecentApps();
void cancelPreloadRecentApps();
+ void showScreenPinningRequest();
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 8794d31..40c009f 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -40,9 +40,12 @@ interface IStatusBarService
// You need the STATUS_BAR_SERVICE permission
void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
out int[] switches, out List<IBinder> binders);
- void onPanelRevealed();
+ void onPanelRevealed(boolean clearNotificationEffects);
void onPanelHidden();
+ // Mark current notifications as "seen" and stop ringing, vibrating, blinking.
+ void clearNotificationEffects();
void onNotificationClick(String key);
+ void onNotificationActionClick(String key, int actionIndex);
void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId);
@@ -50,7 +53,7 @@ interface IStatusBarService
void onNotificationVisibilityChanged(
in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys);
void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
- void setSystemUiVisibility(int vis, int mask);
+ void setSystemUiVisibility(int vis, int mask, String cause);
void setWindowState(int window, int state);
void showRecentApps(boolean triggeredFromAltTab);
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 8e786da..f908fcb 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -128,6 +128,20 @@ public class ArrayUtils
}
/**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(int[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(long[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
* Checks that value is present as at least one of the elements of the array.
* @param array the array to check in
* @param value the value to check for
@@ -157,6 +171,7 @@ public class ArrayUtils
* Test if all {@code check} items are contained in {@code array}.
*/
public static <T> boolean containsAll(T[] array, T[] check) {
+ if (check == null) return true;
for (T checkItem : check) {
if (!contains(array, checkItem)) {
return false;
diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java
index c70a243..c74fea0 100644
--- a/core/java/com/android/internal/util/FastPrintWriter.java
+++ b/core/java/com/android/internal/util/FastPrintWriter.java
@@ -15,7 +15,7 @@ import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
public class FastPrintWriter extends PrintWriter {
- private static Writer sDummyWriter = new Writer() {
+ private static class DummyWriter extends Writer {
@Override
public void close() throws IOException {
UnsupportedOperationException ex
@@ -100,7 +100,7 @@ public class FastPrintWriter extends PrintWriter {
* if {@code out} is {@code null}.
*/
public FastPrintWriter(OutputStream out, boolean autoFlush, int bufferLen) {
- super(sDummyWriter, autoFlush);
+ super(new DummyWriter(), autoFlush);
if (out == null) {
throw new NullPointerException("out is null");
}
@@ -169,7 +169,7 @@ public class FastPrintWriter extends PrintWriter {
* if {@code wr} is {@code null}.
*/
public FastPrintWriter(Writer wr, boolean autoFlush, int bufferLen) {
- super(sDummyWriter, autoFlush);
+ super(new DummyWriter(), autoFlush);
if (wr == null) {
throw new NullPointerException("wr is null");
}
@@ -212,7 +212,7 @@ public class FastPrintWriter extends PrintWriter {
* if {@code pr} is {@code null}.
*/
public FastPrintWriter(Printer pr, int bufferLen) {
- super(sDummyWriter, true);
+ super(new DummyWriter(), true);
if (pr == null) {
throw new NullPointerException("pr is null");
}
diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java
index 5f240f7..b71fa06 100644
--- a/core/java/com/android/internal/util/MemInfoReader.java
+++ b/core/java/com/android/internal/util/MemInfoReader.java
@@ -34,40 +34,65 @@ public final class MemInfoReader {
}
}
+ /**
+ * Total amount of RAM available to the kernel.
+ */
public long getTotalSize() {
return mInfos[Debug.MEMINFO_TOTAL] * 1024;
}
+ /**
+ * Amount of RAM that is not being used for anything.
+ */
public long getFreeSize() {
return mInfos[Debug.MEMINFO_FREE] * 1024;
}
+ /**
+ * Amount of RAM that the kernel is being used for caches, not counting caches
+ * that are mapped in to processes.
+ */
public long getCachedSize() {
- return mInfos[Debug.MEMINFO_CACHED] * 1024;
+ return getCachedSizeKb() * 1024;
}
+ /**
+ * Amount of RAM that is in use by the kernel for actual allocations.
+ */
+ public long getKernelUsedSize() {
+ return getKernelUsedSizeKb() * 1024;
+ }
+
+ /**
+ * Total amount of RAM available to the kernel.
+ */
public long getTotalSizeKb() {
return mInfos[Debug.MEMINFO_TOTAL];
}
+ /**
+ * Amount of RAM that is not being used for anything.
+ */
public long getFreeSizeKb() {
return mInfos[Debug.MEMINFO_FREE];
}
+ /**
+ * Amount of RAM that the kernel is being used for caches, not counting caches
+ * that are mapped in to processes.
+ */
public long getCachedSizeKb() {
- return mInfos[Debug.MEMINFO_CACHED];
- }
-
- public long getBuffersSizeKb() {
- return mInfos[Debug.MEMINFO_BUFFERS];
+ return mInfos[Debug.MEMINFO_BUFFERS]
+ + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED];
}
- public long getShmemSizeKb() {
- return mInfos[Debug.MEMINFO_SHMEM];
- }
-
- public long getSlabSizeKb() {
- return mInfos[Debug.MEMINFO_SLAB];
+ /**
+ * Amount of RAM that is in use by the kernel for actual allocations.
+ */
+ public long getKernelUsedSizeKb() {
+ return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB]
+ + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES]
+ + mInfos[Debug.MEMINFO_KERNEL_STACK];
}
public long getSwapTotalSizeKb() {
@@ -81,4 +106,8 @@ public final class MemInfoReader {
public long getZramTotalSizeKb() {
return mInfos[Debug.MEMINFO_ZRAM_TOTAL];
}
+
+ public long[] getRawInfo() {
+ return mInfos;
+ }
}
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index d26f79e..916f19d 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -25,6 +25,7 @@ import android.util.Log;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -1940,15 +1941,27 @@ public class StateMachine {
* @param args
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ // Cannot just invoke pw.println(this.toString()) because if the
+ // resulting string is to long it won't be displayed.
pw.println(getName() + ":");
pw.println(" total records=" + getLogRecCount());
for (int i = 0; i < getLogRecSize(); i++) {
- pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString());
+ pw.println(" rec[" + i + "]: " + getLogRec(i).toString());
pw.flush();
}
pw.println("curState=" + getCurrentState().getName());
}
+ @Override
+ public String toString() {
+ StringWriter sr = new StringWriter();
+ PrintWriter pr = new PrintWriter(sr);
+ dump(null, pr, null);
+ pr.flush();
+ pr.close();
+ return sr.toString();
+ }
+
/**
* Log with debug and add to the LogRecords.
*
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index e9baaa8..2bd607c 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -520,7 +520,7 @@ public class XmlUtils {
* Flatten a String[] into an XmlSerializer. The list can later be read back
* with readThisStringArrayXml().
*
- * @param val The long array to be flattened.
+ * @param val The String array to be flattened.
* @param name Name attribute to include with this array's tag, or null for
* none.
* @param out XmlSerializer to write the array into.
@@ -556,6 +556,45 @@ public class XmlUtils {
}
/**
+ * Flatten a boolean[] into an XmlSerializer. The list can later be read back
+ * with readThisBooleanArrayXml().
+ *
+ * @param val The boolean array to be flattened.
+ * @param name Name attribute to include with this array's tag, or null for
+ * none.
+ * @param out XmlSerializer to write the array into.
+ *
+ * @see #writeMapXml
+ * @see #writeValueXml
+ * @see #readThisIntArrayXml
+ */
+ public static final void writeBooleanArrayXml(boolean[] val, String name, XmlSerializer out)
+ throws XmlPullParserException, java.io.IOException {
+
+ if (val == null) {
+ out.startTag(null, "null");
+ out.endTag(null, "null");
+ return;
+ }
+
+ out.startTag(null, "boolean-array");
+ if (name != null) {
+ out.attribute(null, "name", name);
+ }
+
+ final int N = val.length;
+ out.attribute(null, "num", Integer.toString(N));
+
+ for (int i=0; i<N; i++) {
+ out.startTag(null, "item");
+ out.attribute(null, "value", Boolean.toString(val[i]));
+ out.endTag(null, "item");
+ }
+
+ out.endTag(null, "boolean-array");
+ }
+
+ /**
* Flatten an object's value into an XmlSerializer. The value can later
* be read back with readThisValueXml().
*
@@ -636,6 +675,9 @@ public class XmlUtils {
} else if (v instanceof String[]) {
writeStringArrayXml((String[])v, name, out);
return;
+ } else if (v instanceof boolean[]) {
+ writeBooleanArrayXml((boolean[])v, name, out);
+ return;
} else if (v instanceof Map) {
writeMapXml((Map)v, name, out);
return;
@@ -1169,6 +1211,66 @@ public class XmlUtils {
}
/**
+ * Read a boolean[] object from an XmlPullParser. The XML data could
+ * previously have been generated by writeBooleanArrayXml(). The XmlPullParser
+ * must be positioned <em>after</em> the tag that begins the list.
+ *
+ * @param parser The XmlPullParser from which to read the list data.
+ * @param endTag Name of the tag that will end the list, usually "string-array".
+ * @param name An array of one string, used to return the name attribute
+ * of the list's tag.
+ *
+ * @return Returns a newly generated boolean[].
+ *
+ * @see #readListXml
+ */
+ public static final boolean[] readThisBooleanArrayXml(XmlPullParser parser, String endTag,
+ String[] name) throws XmlPullParserException, java.io.IOException {
+
+ int num;
+ try {
+ num = Integer.parseInt(parser.getAttributeValue(null, "num"));
+ } catch (NullPointerException e) {
+ throw new XmlPullParserException("Need num attribute in string-array");
+ } catch (NumberFormatException e) {
+ throw new XmlPullParserException("Not a number in num attribute in string-array");
+ }
+ parser.next();
+
+ boolean[] array = new boolean[num];
+ int i = 0;
+
+ int eventType = parser.getEventType();
+ do {
+ if (eventType == parser.START_TAG) {
+ if (parser.getName().equals("item")) {
+ try {
+ array[i] = Boolean.valueOf(parser.getAttributeValue(null, "value"));
+ } catch (NullPointerException e) {
+ throw new XmlPullParserException("Need value attribute in item");
+ } catch (NumberFormatException e) {
+ throw new XmlPullParserException("Not a number in value attribute in item");
+ }
+ } else {
+ throw new XmlPullParserException("Expected item tag at: " + parser.getName());
+ }
+ } else if (eventType == parser.END_TAG) {
+ if (parser.getName().equals(endTag)) {
+ return array;
+ } else if (parser.getName().equals("item")) {
+ i++;
+ } else {
+ throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
+ parser.getName());
+ }
+ }
+ eventType = parser.next();
+ } while (eventType != parser.END_DOCUMENT);
+
+ throw new XmlPullParserException("Document ended before " + endTag + " end tag");
+ }
+
+ /**
* Read a flattened object from an XmlPullParser. The XML data could
* previously have been written with writeMapXml(), writeListXml(), or
* writeValueXml(). The XmlPullParser must be positioned <em>at</em> the
@@ -1259,6 +1361,11 @@ public class XmlUtils {
name[0] = valueName;
//System.out.println("Returning value for " + valueName + ": " + res);
return res;
+ } else if (tagName.equals("boolean-array")) {
+ res = readThisBooleanArrayXml(parser, "boolean-array", name);
+ name[0] = valueName;
+ //System.out.println("Returning value for " + valueName + ": " + res);
+ return res;
} else if (tagName.equals("map")) {
parser.next();
res = readThisMapXml(parser, "map", name);
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 50a7a5e..993ab58 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -102,4 +102,8 @@ public class BaseIWindow extends IWindow.Stub {
@Override
public void doneAnimating() {
}
+
+ @Override
+ public void dispatchWindowShown() {
+ }
}
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index 9c1b558..433ec73 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2010 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.internal.view;
import android.view.InputQueue;
@@ -10,4 +25,5 @@ public interface RootViewSurfaceTaker {
void setSurfaceFormat(int format);
void setSurfaceKeepScreenOn(boolean keepOn);
InputQueue.Callback willYouTakeTheInputQueue();
+ void onRootViewScrollYChanged(int scrollY);
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 40f58e9..99bb1ac 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -54,6 +54,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
private final boolean mOverflowOnly;
private final int mPopupMaxWidth;
private final int mPopupStyleAttr;
+ private final int mPopupStyleRes;
private View mAnchorView;
private ListPopupWindow mPopup;
@@ -73,21 +74,27 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
private int mDropDownGravity = Gravity.NO_GRAVITY;
public MenuPopupHelper(Context context, MenuBuilder menu) {
- this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle);
+ this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0);
}
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
- this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle);
+ this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle, 0);
}
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
boolean overflowOnly, int popupStyleAttr) {
+ this(context, menu, anchorView, overflowOnly, popupStyleAttr, 0);
+ }
+
+ public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
+ boolean overflowOnly, int popupStyleAttr, int popupStyleRes) {
mContext = context;
mInflater = LayoutInflater.from(context);
mMenu = menu;
mAdapter = new MenuAdapter(mMenu);
mOverflowOnly = overflowOnly;
mPopupStyleAttr = popupStyleAttr;
+ mPopupStyleRes = popupStyleRes;
final Resources res = context.getResources();
mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
@@ -122,7 +129,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
}
public boolean tryShow() {
- mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr);
+ mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
mPopup.setOnDismissListener(this);
mPopup.setOnItemClickListener(this);
mPopup.setAdapter(mAdapter);
diff --git a/core/java/com/android/internal/widget/AccountItemView.java b/core/java/com/android/internal/widget/AccountItemView.java
new file mode 100644
index 0000000..a521428
--- /dev/null
+++ b/core/java/com/android/internal/widget/AccountItemView.java
@@ -0,0 +1,102 @@
+/*
+* Copyright (C) 2011-2014 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.internal.widget;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.widget.AccountViewAdapter.AccountElements;
+
+
+/**
+ * An LinearLayout view, to show Accounts elements.
+ */
+public class AccountItemView extends LinearLayout {
+
+ private ImageView mAccountIcon;
+ private TextView mAccountName;
+ private TextView mAccountNumber;
+
+ /**
+ * Constructor.
+ */
+ public AccountItemView(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Constructor.
+ */
+ public AccountItemView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ LayoutInflater inflator = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View view = inflator.inflate(R.layout.simple_account_item, null);
+ addView(view);
+ initViewItem(view);
+ }
+
+ private void initViewItem(View view) {
+ mAccountIcon = (ImageView)view.findViewById(android.R.id.icon);
+ mAccountName = (TextView)view.findViewById(android.R.id.title);
+ mAccountNumber = (TextView)view.findViewById(android.R.id.summary);
+ }
+
+ public void setViewItem(AccountElements element) {
+ Drawable drawable = element.getDrawable();
+ if (drawable != null) {
+ setAccountIcon(drawable);
+ } else {
+ setAccountIcon(element.getIcon());
+ }
+ setAccountName(element.getName());
+ setAccountNumber(element.getNumber());
+ }
+
+ public void setAccountIcon(int resId) {
+ mAccountIcon.setImageResource(resId);
+ }
+
+ public void setAccountIcon(Drawable drawable) {
+ mAccountIcon.setBackgroundDrawable(drawable);
+ }
+
+ public void setAccountName(String name) {
+ setText(mAccountName, name);
+ }
+
+ public void setAccountNumber(String number) {
+ setText(mAccountNumber, number);
+ }
+
+ private void setText(TextView view, String text) {
+ if (TextUtils.isEmpty(text)) {
+ view.setVisibility(View.GONE);
+ } else {
+ view.setText(text);
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/AccountViewAdapter.java b/core/java/com/android/internal/widget/AccountViewAdapter.java
new file mode 100644
index 0000000..8a7a9a6
--- /dev/null
+++ b/core/java/com/android/internal/widget/AccountViewAdapter.java
@@ -0,0 +1,127 @@
+/*
+* Copyright (C) 2011-2014 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.internal.widget;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import java.util.List;
+
+public class AccountViewAdapter extends BaseAdapter {
+
+ private List<AccountElements> mData;
+ private Context mContext;
+
+ /**
+ * Constructor
+ *
+ * @param context The context where the View associated with this Adapter is running
+ * @param data A list with AccountElements data type. The list contains the data of each
+ * account and the each member of AccountElements will correspond to one item view.
+ */
+ public AccountViewAdapter(Context context, final List<AccountElements> data) {
+ mContext = context;
+ mData = data;
+ }
+
+ @Override
+ public int getCount() {
+ return mData.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mData.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public void updateData(final List<AccountElements> data) {
+ mData = data;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ AccountItemView view;
+ if (convertView == null) {
+ view = new AccountItemView(mContext);
+ } else {
+ view = (AccountItemView) convertView;
+ }
+ AccountElements elements = (AccountElements) getItem(position);
+ view.setViewItem(elements);
+ return view;
+ }
+
+ public static class AccountElements {
+ private int mIcon;
+ private Drawable mDrawable;
+ private String mName;
+ private String mNumber;
+
+ /**
+ * Constructor
+ * A structure with basic element of an Account, icon, name and number
+ *
+ * @param icon Account icon id
+ * @param name Account name
+ * @param num Account number
+ */
+ public AccountElements(int icon, String name, String number) {
+ this(icon, null, name, number);
+ }
+
+ /**
+ * Constructor
+ * A structure with basic element of an Account, drawable, name and number
+ *
+ * @param drawable Account drawable
+ * @param name Account name
+ * @param num Account number
+ */
+ public AccountElements(Drawable drawable, String name, String number) {
+ this(0, drawable, name, number);
+ }
+
+ private AccountElements(int icon, Drawable drawable, String name, String number) {
+ mIcon = icon;
+ mDrawable = drawable;
+ mName = name;
+ mNumber = number;
+ }
+
+ public int getIcon() {
+ return mIcon;
+ }
+ public String getName() {
+ return mName;
+ }
+ public String getNumber() {
+ return mNumber;
+ }
+ public Drawable getDrawable() {
+ return mDrawable;
+ }
+ }
+}
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 847a47d..7937a95 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -23,6 +23,7 @@ import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Outline;
import android.graphics.PixelFormat;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ActionMode;
@@ -31,6 +32,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import java.util.List;
+
/**
* This class acts as a container for the action bar view and action mode context views.
* It applies special styles as needed to help handle animated transitions between them.
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 062a9b1..7c671e8 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -241,7 +241,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi
if (!mSplitActionBar) {
menu.addMenuPresenter(mActionMenuPresenter, mPopupContext);
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
- mMenuView.setBackgroundDrawable(null);
+ mMenuView.setBackground(null);
addView(mMenuView, layoutParams);
} else {
// Allow full screen width in split mode.
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 91e5330..654d08b 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -19,8 +19,6 @@ package com.android.internal.widget;
import android.animation.LayoutTransition;
import android.app.ActionBar;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@@ -29,9 +27,7 @@ import android.os.Parcelable;
import android.text.Layout;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.TypedValue;
import android.view.CollapsibleActionView;
-import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -111,10 +107,10 @@ public class ActionBarView extends AbsActionBarView implements DecorToolbar {
private int mProgressBarPadding;
private int mItemPadding;
- private int mTitleStyleRes;
- private int mSubtitleStyleRes;
- private int mProgressStyle;
- private int mIndeterminateProgressStyle;
+ private final int mTitleStyleRes;
+ private final int mSubtitleStyleRes;
+ private final int mProgressStyle;
+ private final int mIndeterminateProgressStyle;
private boolean mUserTitle;
private boolean mIncludeTabs;
@@ -1345,6 +1341,22 @@ public class ActionBarView extends AbsActionBarView implements DecorToolbar {
updateHomeAccessibility(mUpGoerFive.isEnabled());
}
+ @Override
+ public void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+ MenuBuilder.Callback menuBuilderCallback) {
+ if (mActionMenuPresenter != null) {
+ mActionMenuPresenter.setCallback(presenterCallback);
+ }
+ if (mOptionsMenu != null) {
+ mOptionsMenu.setCallback(menuBuilderCallback);
+ }
+ }
+
+ @Override
+ public Menu getMenu() {
+ return mOptionsMenu;
+ }
+
static class SavedState extends BaseSavedState {
int expandedMenuItemId;
boolean isOverflowOpen;
diff --git a/core/java/com/android/internal/widget/DecorToolbar.java b/core/java/com/android/internal/widget/DecorToolbar.java
index f89f0b7..fb413b5 100644
--- a/core/java/com/android/internal/widget/DecorToolbar.java
+++ b/core/java/com/android/internal/widget/DecorToolbar.java
@@ -27,6 +27,8 @@ import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.SpinnerAdapter;
+
+import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPresenter;
/**
@@ -93,4 +95,11 @@ public interface DecorToolbar {
void setDefaultNavigationIcon(Drawable icon);
void saveHierarchyState(SparseArray<Parcelable> toolbarStates);
void restoreHierarchyState(SparseArray<Parcelable> toolbarStates);
+ void setBackgroundDrawable(Drawable d);
+ int getHeight();
+ void setVisibility(int visible);
+ int getVisibility();
+ void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+ MenuBuilder.Callback menuBuilderCallback);
+ Menu getMenu();
}
diff --git a/core/java/com/android/internal/widget/ExploreByTouchHelper.java b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
index 11c4ca1..0e046cb 100644
--- a/core/java/com/android/internal/widget/ExploreByTouchHelper.java
+++ b/core/java/com/android/internal/widget/ExploreByTouchHelper.java
@@ -19,6 +19,7 @@ package com.android.internal.widget;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
+import android.util.IntArray;
import android.view.accessibility.*;
import android.view.MotionEvent;
import android.view.View;
@@ -26,11 +27,9 @@ import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.AccessibilityNodeProvider;
-import java.util.LinkedList;
-import java.util.List;
-
/**
* ExploreByTouchHelper is a utility class for implementing accessibility
* support in custom {@link android.view.View}s that represent a collection of View-like
@@ -54,14 +53,20 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
/** Default class name used for virtual views. */
private static final String DEFAULT_CLASS_NAME = View.class.getName();
- // Temporary, reusable data structures.
- private final Rect mTempScreenRect = new Rect();
- private final Rect mTempParentRect = new Rect();
- private final Rect mTempVisibleRect = new Rect();
- private final int[] mTempGlobalRect = new int[2];
+ /** Default bounds used to determine if the client didn't set any. */
+ private static final Rect INVALID_PARENT_BOUNDS = new Rect(
+ Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
+
+ // Lazily-created temporary data structures used when creating nodes.
+ private Rect mTempScreenRect;
+ private Rect mTempParentRect;
+ private int[] mTempGlobalRect;
+
+ /** Lazily-created temporary data structure used to compute visibility. */
+ private Rect mTempVisibleRect;
- /** View's context **/
- private Context mContext;
+ /** Lazily-created temporary data structure used to obtain child IDs. */
+ private IntArray mTempArray;
/** System accessibility manager, used to check state and send events. */
private final AccessibilityManager mManager;
@@ -69,6 +74,9 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
/** View whose internal structure is exposed through this helper. */
private final View mView;
+ /** Context of the host view. **/
+ private final Context mContext;
+
/** Node provider that handles creating nodes and performing actions. */
private ExploreByTouchNodeProvider mNodeProvider;
@@ -328,11 +336,17 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
onInitializeAccessibilityNodeInfo(mView, node);
// Add the virtual descendants.
- final LinkedList<Integer> virtualViewIds = new LinkedList<Integer>();
+ if (mTempArray == null) {
+ mTempArray = new IntArray();
+ } else {
+ mTempArray.clear();
+ }
+ final IntArray virtualViewIds = mTempArray;
getVisibleVirtualViews(virtualViewIds);
- for (Integer childVirtualViewId : virtualViewIds) {
- node.addChild(mView, childVirtualViewId);
+ final int N = virtualViewIds.size();
+ for (int i = 0; i < N; i++) {
+ node.addChild(mView, virtualViewIds.get(i));
}
return node;
@@ -367,11 +381,17 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
* @return An {@link AccessibilityNodeInfo} for the specified item.
*/
private AccessibilityNodeInfo createNodeForChild(int virtualViewId) {
+ ensureTempRects();
+ final Rect tempParentRect = mTempParentRect;
+ final int[] tempGlobalRect = mTempGlobalRect;
+ final Rect tempScreenRect = mTempScreenRect;
+
final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain();
// Ensure the client has good defaults.
node.setEnabled(true);
node.setClassName(DEFAULT_CLASS_NAME);
+ node.setBoundsInParent(INVALID_PARENT_BOUNDS);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
@@ -382,8 +402,8 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
+ "populateNodeForVirtualViewId()");
}
- node.getBoundsInParent(mTempParentRect);
- if (mTempParentRect.isEmpty()) {
+ node.getBoundsInParent(tempParentRect);
+ if (tempParentRect.equals(INVALID_PARENT_BOUNDS)) {
throw new RuntimeException("Callbacks must set parent bounds in "
+ "populateNodeForVirtualViewId()");
}
@@ -406,29 +426,35 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
// Manage internal accessibility focus state.
if (mFocusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
- node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ node.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
} else {
node.setAccessibilityFocused(false);
- node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ node.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
}
// Set the visibility based on the parent bound.
- if (intersectVisibleToUser(mTempParentRect)) {
+ if (intersectVisibleToUser(tempParentRect)) {
node.setVisibleToUser(true);
- node.setBoundsInParent(mTempParentRect);
+ node.setBoundsInParent(tempParentRect);
}
// Calculate screen-relative bound.
- mView.getLocationOnScreen(mTempGlobalRect);
- final int offsetX = mTempGlobalRect[0];
- final int offsetY = mTempGlobalRect[1];
- mTempScreenRect.set(mTempParentRect);
- mTempScreenRect.offset(offsetX, offsetY);
- node.setBoundsInScreen(mTempScreenRect);
+ mView.getLocationOnScreen(tempGlobalRect);
+ final int offsetX = tempGlobalRect[0];
+ final int offsetY = tempGlobalRect[1];
+ tempScreenRect.set(tempParentRect);
+ tempScreenRect.offset(offsetX, offsetY);
+ node.setBoundsInScreen(tempScreenRect);
return node;
}
+ private void ensureTempRects() {
+ mTempGlobalRect = new int[2];
+ mTempParentRect = new Rect();
+ mTempScreenRect = new Rect();
+ }
+
private boolean performAction(int virtualViewId, int action, Bundle arguments) {
switch (virtualViewId) {
case View.NO_ID:
@@ -446,13 +472,13 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
switch (action) {
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
- return manageFocusForChild(virtualViewId, action, arguments);
+ return manageFocusForChild(virtualViewId, action);
default:
return onPerformActionForVirtualView(virtualViewId, action, arguments);
}
}
- private boolean manageFocusForChild(int virtualViewId, int action, Bundle arguments) {
+ private boolean manageFocusForChild(int virtualViewId, int action) {
switch (action) {
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
return requestAccessibilityFocus(virtualViewId);
@@ -498,12 +524,16 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
}
// If no portion of the parent is visible, this view is not visible.
- if (!mView.getLocalVisibleRect(mTempVisibleRect)) {
+ if (mTempVisibleRect == null) {
+ mTempVisibleRect = new Rect();
+ }
+ final Rect tempVisibleRect = mTempVisibleRect;
+ if (!mView.getLocalVisibleRect(tempVisibleRect)) {
return false;
}
// Check if the view intersects the visible portion of the parent.
- return localRect.intersect(mTempVisibleRect);
+ return localRect.intersect(tempVisibleRect);
}
/**
@@ -583,7 +613,7 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate {
*
* @param virtualViewIds The list to populate with visible items
*/
- protected abstract void getVisibleVirtualViews(List<Integer> virtualViewIds);
+ protected abstract void getVisibleVirtualViews(IntArray virtualViewIds);
/**
* Populates an {@link AccessibilityEvent} with information about the
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index c70841b..9501f92 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -16,8 +16,6 @@
package com.android.internal.widget;
-import com.android.internal.widget.ILockSettingsObserver;
-
/** {@hide} */
interface ILockSettings {
void setBoolean(in String key, in boolean value, in int userId);
@@ -34,6 +32,4 @@ interface ILockSettings {
boolean havePattern(int userId);
boolean havePassword(int userId);
void removeUser(int userId);
- void registerObserver(in ILockSettingsObserver observer);
- void unregisterObserver(in ILockSettingsObserver observer);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3326e42..0afc651 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -194,9 +194,6 @@ public class LockPatternUtils {
return trust;
}
- /**
- * @param contentResolver Used to look up and save settings.
- */
public LockPatternUtils(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -210,8 +207,9 @@ public class LockPatternUtils {
private ILockSettings getLockSettings() {
if (mLockSettingsService == null) {
- mLockSettingsService = LockPatternUtilsCache.getInstance(
- ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings")));
+ ILockSettings service = ILockSettings.Stub.asInterface(
+ ServiceManager.getService("lock_settings"));
+ mLockSettingsService = service;
}
return mLockSettingsService;
}
@@ -386,8 +384,16 @@ public class LockPatternUtils {
* @return Whether a saved pattern exists.
*/
public boolean savedPatternExists() {
+ return savedPatternExists(getCurrentOrCallingUserId());
+ }
+
+ /**
+ * Check to see if the user has stored a lock pattern.
+ * @return Whether a saved pattern exists.
+ */
+ public boolean savedPatternExists(int userId) {
try {
- return getLockSettings().havePattern(getCurrentOrCallingUserId());
+ return getLockSettings().havePattern(userId);
} catch (RemoteException re) {
return false;
}
@@ -398,8 +404,16 @@ public class LockPatternUtils {
* @return Whether a saved pattern exists.
*/
public boolean savedPasswordExists() {
+ return savedPasswordExists(getCurrentOrCallingUserId());
+ }
+
+ /**
+ * Check to see if the user has stored a lock pattern.
+ * @return Whether a saved pattern exists.
+ */
+ public boolean savedPasswordExists(int userId) {
try {
- return getLockSettings().havePassword(getCurrentOrCallingUserId());
+ return getLockSettings().havePassword(userId);
} catch (RemoteException re) {
return false;
}
@@ -476,17 +490,23 @@ public class LockPatternUtils {
return activePasswordQuality;
}
+ public void clearLock(boolean isFallback) {
+ clearLock(isFallback, getCurrentOrCallingUserId());
+ }
+
/**
* Clear any lock pattern or password.
*/
- public void clearLock(boolean isFallback) {
- if(!isFallback) deleteGallery();
- saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- setLockPatternEnabled(false);
- saveLockPattern(null);
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
- setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
- onAfterChangingPassword();
+ public void clearLock(boolean isFallback, int userHandle) {
+ if(!isFallback) deleteGallery(userHandle);
+ saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, isFallback,
+ userHandle);
+ setLockPatternEnabled(false, userHandle);
+ saveLockPattern(null, isFallback, userHandle);
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
+ setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+ userHandle);
+ onAfterChangingPassword(userHandle);
}
/**
@@ -533,11 +553,11 @@ public class LockPatternUtils {
/**
* Calls back SetupFaceLock to delete the gallery file when the lock type is changed
*/
- void deleteGallery() {
- if(usingBiometricWeak()) {
+ void deleteGallery(int userId) {
+ if(usingBiometricWeak(userId)) {
Intent intent = new Intent().setAction("com.android.facelock.DELETE_GALLERY");
intent.putExtra("deleteGallery", true);
- mContext.sendBroadcast(intent);
+ mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
}
}
@@ -552,11 +572,20 @@ public class LockPatternUtils {
/**
* Save a lock pattern.
* @param pattern The new pattern to save.
- * @param isFallback Specifies if this is a fallback to biometric weak
*/
public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback) {
+ this.saveLockPattern(pattern, isFallback, getCurrentOrCallingUserId());
+ }
+
+ /**
+ * Save a lock pattern.
+ * @param pattern The new pattern to save.
+ * @param isFallback Specifies if this is a fallback to biometric weak
+ * @param userId the user whose pattern is to be saved.
+ */
+ public void saveLockPattern(List<LockPatternView.Cell> pattern, boolean isFallback,
+ int userId) {
try {
- int userId = getCurrentOrCallingUserId();
getLockSettings().setLockPattern(patternToString(pattern), userId);
DevicePolicyManager dpm = getDevicePolicyManager();
if (pattern != null) {
@@ -572,17 +601,17 @@ public class LockPatternUtils {
}
}
- setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
+ setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
if (!isFallback) {
- deleteGallery();
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ deleteGallery(userId);
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
pattern.size(), 0, 0, 0, 0, 0, 0, userId);
} else {
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK);
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK, userId);
setLong(PASSWORD_TYPE_ALTERNATE_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
- finishBiometricWeak();
+ DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
+ finishBiometricWeak(userId);
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
0, 0, 0, 0, 0, 0, 0, userId);
}
@@ -590,7 +619,7 @@ public class LockPatternUtils {
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0,
0, 0, 0, 0, 0, userId);
}
- onAfterChangingPassword();
+ onAfterChangingPassword(userId);
} catch (RemoteException re) {
Log.e(TAG, "Couldn't save lock pattern " + re);
}
@@ -808,7 +837,7 @@ public class LockPatternUtils {
}
if (!isFallback) {
- deleteGallery();
+ deleteGallery(userHandle);
setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int letters = 0;
@@ -848,7 +877,7 @@ public class LockPatternUtils {
userHandle);
setLong(PASSWORD_TYPE_ALTERNATE_KEY, Math.max(quality, computedQuality),
userHandle);
- finishBiometricWeak();
+ finishBiometricWeak(userHandle);
dpm.setActivePasswordState(DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK,
0, 0, 0, 0, 0, 0, 0, userHandle);
}
@@ -856,7 +885,7 @@ public class LockPatternUtils {
// password hashes have the same length for simplicity of implementation.
String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
if (passwordHistory == null) {
- passwordHistory = new String();
+ passwordHistory = "";
}
int passwordHistoryLength = getRequestedPasswordHistoryLength();
if (passwordHistoryLength == 0) {
@@ -883,7 +912,7 @@ public class LockPatternUtils {
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
userHandle);
}
- onAfterChangingPassword();
+ onAfterChangingPassword(userHandle);
} catch (RemoteException re) {
// Cant do much
Log.e(TAG, "Unable to save lock password " + re);
@@ -957,8 +986,15 @@ public class LockPatternUtils {
* @return true if the lockscreen method is set to biometric weak
*/
public boolean usingBiometricWeak() {
- int quality =
- (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
+ return usingBiometricWeak(getCurrentOrCallingUserId());
+ }
+
+ /**
+ * @return true if the lockscreen method is set to biometric weak
+ */
+ public boolean usingBiometricWeak(int userId) {
+ int quality = (int) getLong(
+ PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
return quality == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
}
@@ -1094,15 +1130,22 @@ public class LockPatternUtils {
* @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
*/
public boolean isLockPatternEnabled() {
+ return isLockPatternEnabled(getCurrentOrCallingUserId());
+ }
+
+ /**
+ * @return Whether the lock pattern is enabled, or if it is set as a backup for biometric weak
+ */
+ public boolean isLockPatternEnabled(int userId) {
final boolean backupEnabled =
getLong(PASSWORD_TYPE_ALTERNATE_KEY,
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)
+ DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId)
== DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
- return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false)
- && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)
- == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING ||
- (usingBiometricWeak() && backupEnabled));
+ return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, false, userId)
+ && (getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
+ userId) == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
+ || (usingBiometricWeak(userId) && backupEnabled));
}
/**
@@ -1158,7 +1201,14 @@ public class LockPatternUtils {
* Set whether the lock pattern is enabled.
*/
public void setLockPatternEnabled(boolean enabled) {
- setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled);
+ setLockPatternEnabled(enabled, getCurrentOrCallingUserId());
+ }
+
+ /**
+ * Set whether the lock pattern is enabled.
+ */
+ public void setLockPatternEnabled(boolean enabled, int userHandle) {
+ setBoolean(Settings.Secure.LOCK_PATTERN_ENABLED, enabled, userHandle);
}
/**
@@ -1483,15 +1533,20 @@ public class LockPatternUtils {
}
public boolean isSecure() {
- long mode = getKeyguardStoredPasswordQuality();
+ return isSecure(getCurrentOrCallingUserId());
+ }
+
+ public boolean isSecure(int userId) {
+ long mode = getKeyguardStoredPasswordQuality(userId);
final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
|| mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
- final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
- || isPassword && savedPasswordExists();
+ final boolean secure =
+ isPattern && isLockPatternEnabled(userId) && savedPatternExists(userId)
+ || isPassword && savedPasswordExists(userId);
return secure;
}
@@ -1547,15 +1602,15 @@ public class LockPatternUtils {
return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
}
- private void finishBiometricWeak() {
- setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true);
+ private void finishBiometricWeak(int userId) {
+ setBoolean(BIOMETRIC_WEAK_EVER_CHOSEN_KEY, true, userId);
// Launch intent to show final screen, this also
// moves the temporary gallery to the actual gallery
Intent intent = new Intent();
intent.setClassName("com.android.facelock",
"com.android.facelock.SetupEndScreen");
- mContext.startActivity(intent);
+ mContext.startActivityAsUser(intent, new UserHandle(userId));
}
public void setPowerButtonInstantlyLocks(boolean enabled) {
@@ -1649,8 +1704,8 @@ public class LockPatternUtils {
getTrustManager().reportRequireCredentialEntry(userId);
}
- private void onAfterChangingPassword() {
- getTrustManager().reportEnabledTrustAgentsChanged(getCurrentOrCallingUserId());
+ private void onAfterChangingPassword(int userHandle) {
+ getTrustManager().reportEnabledTrustAgentsChanged(userHandle);
}
public boolean isCredentialRequiredToDecrypt(boolean defaultValue) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtilsCache.java b/core/java/com/android/internal/widget/LockPatternUtilsCache.java
deleted file mode 100644
index 624f67c..0000000
--- a/core/java/com/android/internal/widget/LockPatternUtilsCache.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2014 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.internal.widget;
-
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.ArrayMap;
-
-/**
- * A decorator for {@link ILockSettings} that caches the key-value responses in memory.
- *
- * Specifically, the return values of {@link #getString(String, String, int)},
- * {@link #getLong(String, long, int)} and {@link #getBoolean(String, boolean, int)} are cached.
- */
-public class LockPatternUtilsCache implements ILockSettings {
-
- private static final String HAS_LOCK_PATTERN_CACHE_KEY
- = "LockPatternUtils.Cache.HasLockPatternCacheKey";
- private static final String HAS_LOCK_PASSWORD_CACHE_KEY
- = "LockPatternUtils.Cache.HasLockPasswordCacheKey";
-
- private static LockPatternUtilsCache sInstance;
-
- private final ILockSettings mService;
-
- /** Only access when holding {@code mCache} lock. */
- private final ArrayMap<CacheKey, Object> mCache = new ArrayMap<>();
-
- /** Only access when holding {@link #mCache} lock. */
- private final CacheKey mCacheKey = new CacheKey();
-
-
- public static synchronized LockPatternUtilsCache getInstance(ILockSettings service) {
- if (sInstance == null) {
- sInstance = new LockPatternUtilsCache(service);
- }
- return sInstance;
- }
-
- // ILockSettings
-
- private LockPatternUtilsCache(ILockSettings service) {
- mService = service;
- try {
- service.registerObserver(mObserver);
- } catch (RemoteException e) {
- // Not safe to do caching without the observer. System process has probably died
- // anyway, so crashing here is fine.
- throw new RuntimeException(e);
- }
- }
-
- public void setBoolean(String key, boolean value, int userId) throws RemoteException {
- invalidateCache(key, userId);
- mService.setBoolean(key, value, userId);
- putCache(key, userId, value);
- }
-
- public void setLong(String key, long value, int userId) throws RemoteException {
- invalidateCache(key, userId);
- mService.setLong(key, value, userId);
- putCache(key, userId, value);
- }
-
- public void setString(String key, String value, int userId) throws RemoteException {
- invalidateCache(key, userId);
- mService.setString(key, value, userId);
- putCache(key, userId, value);
- }
-
- public long getLong(String key, long defaultValue, int userId) throws RemoteException {
- Object value = peekCache(key, userId);
- if (value instanceof Long) {
- return (long) value;
- }
- long result = mService.getLong(key, defaultValue, userId);
- putCache(key, userId, result);
- return result;
- }
-
- public String getString(String key, String defaultValue, int userId) throws RemoteException {
- Object value = peekCache(key, userId);
- if (value instanceof String) {
- return (String) value;
- }
- String result = mService.getString(key, defaultValue, userId);
- putCache(key, userId, result);
- return result;
- }
-
- public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
- Object value = peekCache(key, userId);
- if (value instanceof Boolean) {
- return (boolean) value;
- }
- boolean result = mService.getBoolean(key, defaultValue, userId);
- putCache(key, userId, result);
- return result;
- }
-
- @Override
- public void setLockPattern(String pattern, int userId) throws RemoteException {
- invalidateCache(HAS_LOCK_PATTERN_CACHE_KEY, userId);
- mService.setLockPattern(pattern, userId);
- putCache(HAS_LOCK_PATTERN_CACHE_KEY, userId, pattern != null);
- }
-
- @Override
- public boolean checkPattern(String pattern, int userId) throws RemoteException {
- return mService.checkPattern(pattern, userId);
- }
-
- @Override
- public void setLockPassword(String password, int userId) throws RemoteException {
- invalidateCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId);
- mService.setLockPassword(password, userId);
- putCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId, password != null);
- }
-
- @Override
- public boolean checkPassword(String password, int userId) throws RemoteException {
- return mService.checkPassword(password, userId);
- }
-
- @Override
- public boolean checkVoldPassword(int userId) throws RemoteException {
- return mService.checkVoldPassword(userId);
- }
-
- @Override
- public boolean havePattern(int userId) throws RemoteException {
- Object value = peekCache(HAS_LOCK_PATTERN_CACHE_KEY, userId);
- if (value instanceof Boolean) {
- return (boolean) value;
- }
- boolean result = mService.havePattern(userId);
- putCache(HAS_LOCK_PATTERN_CACHE_KEY, userId, result);
- return result;
- }
-
- @Override
- public boolean havePassword(int userId) throws RemoteException {
- Object value = peekCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId);
- if (value instanceof Boolean) {
- return (boolean) value;
- }
- boolean result = mService.havePassword(userId);
- putCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId, result);
- return result;
- }
-
- @Override
- public void removeUser(int userId) throws RemoteException {
- mService.removeUser(userId);
- }
-
- @Override
- public void registerObserver(ILockSettingsObserver observer) throws RemoteException {
- mService.registerObserver(observer);
- }
-
- @Override
- public void unregisterObserver(ILockSettingsObserver observer) throws RemoteException {
- mService.unregisterObserver(observer);
- }
-
- @Override
- public IBinder asBinder() {
- return mService.asBinder();
- }
-
- // Caching
-
- private Object peekCache(String key, int userId) {
- synchronized (mCache) {
- // Safe to reuse mCacheKey, because it is not stored in the map.
- return mCache.get(mCacheKey.set(key, userId));
- }
- }
-
- private void putCache(String key, int userId, Object value) {
- synchronized (mCache) {
- // Create a new key, because this will be stored in the map.
- mCache.put(new CacheKey().set(key, userId), value);
- }
- }
-
- private void invalidateCache(String key, int userId) {
- synchronized (mCache) {
- // Safe to reuse mCacheKey, because it is not stored in the map.
- mCache.remove(mCacheKey.set(key, userId));
- }
- }
-
- private final ILockSettingsObserver mObserver = new ILockSettingsObserver.Stub() {
- @Override
- public void onLockSettingChanged(String key, int userId) throws RemoteException {
- invalidateCache(key, userId);
- }
- };
-
- private static final class CacheKey {
- String key;
- int userId;
-
- public CacheKey set(String key, int userId) {
- this.key = key;
- this.userId = userId;
- return this;
- }
-
- public CacheKey copy() {
- return new CacheKey().set(key, userId);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof CacheKey))
- return false;
- CacheKey o = (CacheKey) obj;
- return userId == o.userId && key.equals(o.key);
- }
-
- @Override
- public int hashCode() {
- return key.hashCode() ^ userId;
- }
- }
-}
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 375822f..4e48454 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -20,6 +20,7 @@ package com.android.internal.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -31,6 +32,8 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
import android.widget.AbsListView;
import android.widget.OverScroller;
@@ -63,18 +66,22 @@ public class ResolverDrawerLayout extends ViewGroup {
private float mCollapseOffset;
private int mCollapsibleHeight;
+ private int mUncollapsibleHeight;
private int mTopOffset;
private boolean mIsDragging;
private boolean mOpenOnClick;
private boolean mOpenOnLayout;
+ private boolean mDismissOnScrollerFinished;
private final int mTouchSlop;
private final float mMinFlingVelocity;
private final OverScroller mScroller;
private final VelocityTracker mVelocityTracker;
- private OnClickListener mClickOutsideListener;
+ private OnDismissedListener mOnDismissedListener;
+ private RunOnDismissedListener mRunOnDismissedListener;
+
private float mInitialTouchX;
private float mInitialTouchY;
private float mLastTouchY;
@@ -143,8 +150,8 @@ public class ResolverDrawerLayout extends ViewGroup {
return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
}
- public void setOnClickOutsideListener(OnClickListener listener) {
- mClickOutsideListener = listener;
+ public void setOnDismissedListener(OnDismissedListener listener) {
+ mOnDismissedListener = listener;
}
@Override
@@ -194,7 +201,7 @@ public class ResolverDrawerLayout extends ViewGroup {
}
if (mIsDragging) {
- mScroller.abortAnimation();
+ abortAnimation();
}
return mIsDragging || mOpenOnClick;
}
@@ -213,12 +220,10 @@ public class ResolverDrawerLayout extends ViewGroup {
mInitialTouchX = x;
mInitialTouchY = mLastTouchY = y;
mActivePointerId = ev.getPointerId(0);
- if (findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
- mClickOutsideListener != null) {
- mIsDragging = handled = true;
- }
- handled |= mCollapsibleHeight > 0;
- mScroller.abortAnimation();
+ final boolean hitView = findChildUnder(mInitialTouchX, mInitialTouchY) != null;
+ handled = (!hitView && mOnDismissedListener != null) || mCollapsibleHeight > 0;
+ mIsDragging = hitView && handled;
+ abortAnimation();
}
break;
@@ -264,11 +269,12 @@ public class ResolverDrawerLayout extends ViewGroup {
break;
case MotionEvent.ACTION_UP: {
+ final boolean wasDragging = mIsDragging;
mIsDragging = false;
- if (!mIsDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
+ if (!wasDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null &&
findChildUnder(ev.getX(), ev.getY()) == null) {
- if (mClickOutsideListener != null) {
- mClickOutsideListener.onClick(this);
+ if (mOnDismissedListener != null) {
+ dispatchOnDismissed();
resetTouch();
return true;
}
@@ -281,7 +287,13 @@ public class ResolverDrawerLayout extends ViewGroup {
mVelocityTracker.computeCurrentVelocity(1000);
final float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
if (Math.abs(yvel) > mMinFlingVelocity) {
- smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ if (mOnDismissedListener != null
+ && yvel > 0 && mCollapseOffset > mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel);
+ mDismissOnScrollerFinished = true;
+ } else {
+ smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel);
+ }
} else {
smoothScrollTo(
mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0);
@@ -327,17 +339,27 @@ public class ResolverDrawerLayout extends ViewGroup {
@Override
public void computeScroll() {
super.computeScroll();
- if (!mScroller.isFinished()) {
- final boolean keepGoing = mScroller.computeScrollOffset();
+ if (mScroller.computeScrollOffset()) {
+ final boolean keepGoing = !mScroller.isFinished();
performDrag(mScroller.getCurrY() - mCollapseOffset);
if (keepGoing) {
postInvalidateOnAnimation();
+ } else if (mDismissOnScrollerFinished && mOnDismissedListener != null) {
+ mRunOnDismissedListener = new RunOnDismissedListener();
+ post(mRunOnDismissedListener);
}
}
}
+ private void abortAnimation() {
+ mScroller.abortAnimation();
+ mRunOnDismissedListener = null;
+ mDismissOnScrollerFinished = false;
+ }
+
private float performDrag(float dy) {
- final float newPos = Math.max(0, Math.min(mCollapseOffset + dy, mCollapsibleHeight));
+ final float newPos = Math.max(0, Math.min(mCollapseOffset + dy,
+ mCollapsibleHeight + mUncollapsibleHeight));
if (newPos != mCollapseOffset) {
dy = newPos - mCollapseOffset;
final int childCount = getChildCount();
@@ -348,19 +370,32 @@ public class ResolverDrawerLayout extends ViewGroup {
child.offsetTopAndBottom((int) dy);
}
}
+ final boolean isCollapsedOld = mCollapseOffset != 0;
mCollapseOffset = newPos;
mTopOffset += dy;
+ final boolean isCollapsedNew = newPos != 0;
+ if (isCollapsedOld != isCollapsedNew) {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
postInvalidateOnAnimation();
return dy;
}
return 0;
}
- private void smoothScrollTo(int yOffset, float velocity) {
- if (getMaxCollapsedHeight() == 0) {
- return;
+ void dispatchOnDismissed() {
+ if (mOnDismissedListener != null) {
+ mOnDismissedListener.onDismissed();
}
- mScroller.abortAnimation();
+ if (mRunOnDismissedListener != null) {
+ removeCallbacks(mRunOnDismissedListener);
+ mRunOnDismissedListener = null;
+ }
+ }
+
+ private void smoothScrollTo(int yOffset, float velocity) {
+ abortAnimation();
final int sy = (int) mCollapseOffset;
int dy = yOffset - sy;
if (dy == 0) {
@@ -490,6 +525,7 @@ public class ResolverDrawerLayout extends ViewGroup {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnTouchModeChangeListener(mTouchModeChangeListener);
+ abortAnimation();
}
@Override
@@ -544,6 +580,50 @@ public class ResolverDrawerLayout extends ViewGroup {
}
@Override
+ public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
+ if (super.onNestedPrePerformAccessibilityAction(target, action, args)) {
+ return true;
+ }
+
+ if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && mCollapseOffset != 0) {
+ smoothScrollTo(0, 0);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ event.setClassName(ResolverDrawerLayout.class.getName());
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setClassName(ResolverDrawerLayout.class.getName());
+ if (isEnabled()) {
+ if (mCollapseOffset != 0) {
+ info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ info.setScrollable(true);
+ }
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (super.performAccessibilityAction(action, arguments)) {
+ return true;
+ }
+
+ if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD && mCollapseOffset != 0) {
+ smoothScrollTo(0, 0);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int sourceWidth = MeasureSpec.getSize(widthMeasureSpec);
int widthSize = sourceWidth;
@@ -585,9 +665,16 @@ public class ResolverDrawerLayout extends ViewGroup {
mCollapsibleHeight = Math.max(0,
heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
+ mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
if (isLaidOut()) {
+ final boolean isCollapsedOld = mCollapseOffset != 0;
mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
+ final boolean isCollapsedNew = mCollapseOffset != 0;
+ if (isCollapsedOld != isCollapsedNew) {
+ notifyViewAccessibilityStateChangedIfNeeded(
+ AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+ }
} else {
// Start out collapsed at first unless we restored state for otherwise
mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
@@ -734,4 +821,15 @@ public class ResolverDrawerLayout extends ViewGroup {
}
};
}
+
+ public interface OnDismissedListener {
+ public void onDismissed();
+ }
+
+ private class RunOnDismissedListener implements Runnable {
+ @Override
+ public void run() {
+ dispatchOnDismissed();
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/SubtitleView.java b/core/java/com/android/internal/widget/SubtitleView.java
index 2f987e9..a206e7f 100644
--- a/core/java/com/android/internal/widget/SubtitleView.java
+++ b/core/java/com/android/internal/widget/SubtitleView.java
@@ -148,6 +148,7 @@ public class SubtitleView extends View {
mHasMeasurements = false;
requestLayout();
+ invalidate();
}
public void setForegroundColor(int color) {
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 97b1634..d617c05 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -17,6 +17,7 @@
package com.android.internal.widget;
import android.animation.TimeInterpolator;
+import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
@@ -25,6 +26,7 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
@@ -75,6 +77,19 @@ public class SwipeDismissLayout extends FrameLayout {
private OnDismissedListener mDismissedListener;
private OnSwipeProgressChangedListener mProgressListener;
+ private ViewTreeObserver.OnEnterAnimationCompleteListener mOnEnterAnimationCompleteListener =
+ new ViewTreeObserver.OnEnterAnimationCompleteListener() {
+ @Override
+ public void onEnterAnimationComplete() {
+ // SwipeDismissLayout assumes that the host Activity is translucent
+ // and temporarily disables translucency when it is fully visible.
+ // As soon as the user starts swiping, we will re-enable
+ // translucency.
+ if (getContext() instanceof Activity) {
+ ((Activity) getContext()).convertFromTranslucent();
+ }
+ }
+ };
private float mLastX;
@@ -113,6 +128,24 @@ public class SwipeDismissLayout extends FrameLayout {
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (getContext() instanceof Activity) {
+ getViewTreeObserver().addOnEnterAnimationCompleteListener(
+ mOnEnterAnimationCompleteListener);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (getContext() instanceof Activity) {
+ getViewTreeObserver().removeOnEnterAnimationCompleteListener(
+ mOnEnterAnimationCompleteListener);
+ }
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// offset because the view is translated during swipe
ev.offsetLocation(mTranslationX, 0);
@@ -197,6 +230,9 @@ public class SwipeDismissLayout extends FrameLayout {
mLastX = ev.getRawX();
updateSwiping(ev);
if (mSwiping) {
+ if (getContext() instanceof Activity) {
+ ((Activity) getContext()).convertToTranslucent(null, null);
+ }
setProgress(ev.getRawX() - mDownX);
break;
}
@@ -218,6 +254,9 @@ public class SwipeDismissLayout extends FrameLayout {
}
protected void cancel() {
+ if (getContext() instanceof Activity) {
+ ((Activity) getContext()).convertFromTranslucent();
+ }
if (mProgressListener != null) {
mProgressListener.onSwipeCancelled(this);
}
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index 324a6c9..8d1f73a 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -97,6 +97,7 @@ public class ToolbarWidgetWrapper implements DecorToolbar {
mTitle = toolbar.getTitle();
mSubtitle = toolbar.getSubtitle();
mTitleSet = mTitle != null;
+ mNavIcon = mToolbar.getNavigationIcon();
final TypedArray a = toolbar.getContext().obtainStyledAttributes(null,
R.styleable.ActionBar, R.attr.actionBarStyle, 0);
mDefaultNavigationIcon = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator);
@@ -120,7 +121,7 @@ public class ToolbarWidgetWrapper implements DecorToolbar {
if (icon != null) {
setIcon(icon);
}
- if (mDefaultNavigationIcon != null) {
+ if (mNavIcon == null && mDefaultNavigationIcon != null) {
setNavigationIcon(mDefaultNavigationIcon);
}
setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, 0));
@@ -657,4 +658,36 @@ public class ToolbarWidgetWrapper implements DecorToolbar {
mToolbar.restoreHierarchyState(toolbarStates);
}
+ @Override
+ public void setBackgroundDrawable(Drawable d) {
+ //noinspection deprecation
+ mToolbar.setBackgroundDrawable(d);
+ }
+
+ @Override
+ public int getHeight() {
+ return mToolbar.getHeight();
+ }
+
+ @Override
+ public void setVisibility(int visible) {
+ mToolbar.setVisibility(visible);
+ }
+
+ @Override
+ public int getVisibility() {
+ return mToolbar.getVisibility();
+ }
+
+ @Override
+ public void setMenuCallbacks(MenuPresenter.Callback presenterCallback,
+ MenuBuilder.Callback menuBuilderCallback) {
+ mToolbar.setMenuCallbacks(presenterCallback, menuBuilderCallback);
+ }
+
+ @Override
+ public Menu getMenu() {
+ return mToolbar.getMenu();
+ }
+
}
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index d39bf07..155f5d3 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -142,6 +142,8 @@ public class BootReceiver extends BroadcastReceiver {
"SYSTEM_LAST_KMSG");
addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
-LOG_SIZE, "SYSTEM_RECOVERY_LOG");
+ addFileToDropBox(db, prefs, headers, "/cache/recovery/last_kmsg",
+ -LOG_SIZE, "SYSTEM_RECOVERY_KMSG");
addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
-LOG_SIZE, "APANIC_CONSOLE");
addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 26e2e2a..35a1a5a 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -17,12 +17,14 @@
package com.android.server.backup;
+import android.app.ActivityManagerNative;
import android.app.IWallpaperManager;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupAgentHelper;
import android.app.backup.FullBackup;
import android.app.backup.FullBackupDataOutput;
+import android.app.backup.RecentsBackupHelper;
import android.app.backup.WallpaperBackupHelper;
import android.content.Context;
import android.os.Environment;
@@ -83,6 +85,8 @@ public class SystemBackupAgent extends BackupAgentHelper {
}
}
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
+ addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
+
super.onBackup(oldState, data, newState);
}
@@ -113,6 +117,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
new String[] { WALLPAPER_IMAGE },
new String[] { WALLPAPER_IMAGE_KEY} ));
+ addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
try {
super.onRestore(data, appVersionCode, newState);
@@ -182,4 +187,13 @@ public class SystemBackupAgent extends BackupAgentHelper {
}
}
}
+
+ @Override
+ public void onRestoreFinished() {
+ try {
+ ActivityManagerNative.getDefault().systemBackupRestored();
+ } catch (RemoteException e) {
+ // Not possible since this code is running in the system process.
+ }
+ }
}