summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt17
-rw-r--r--api/system-current.txt17
-rw-r--r--core/java/android/content/ContentProviderOperation.java54
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/net/NetworkFactory.java10
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java82
-rw-r--r--core/java/com/android/internal/app/ResolverComparator.java215
-rw-r--r--media/java/android/media/browse/MediaBrowser.java36
-rw-r--r--media/java/android/service/media/MediaBrowserService.java50
-rw-r--r--media/jni/android_media_ImageWriter.cpp3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java93
12 files changed, 450 insertions, 135 deletions
diff --git a/api/current.txt b/api/current.txt
index fb60f1c..9f59a20 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7721,6 +7721,7 @@ package android.content {
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
method public final T getSystemService(java.lang.Class<T>);
+ method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -17210,7 +17211,7 @@ package android.media.browse {
method public void connect();
method public void disconnect();
method public android.os.Bundle getExtras();
- method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
+ method public void getItem(java.lang.String, android.media.browse.MediaBrowser.ItemCallback);
method public java.lang.String getRoot();
method public android.content.ComponentName getServiceComponent();
method public android.media.session.MediaSession.Token getSessionToken();
@@ -17226,6 +17227,12 @@ package android.media.browse {
method public void onConnectionSuspended();
}
+ public static abstract class MediaBrowser.ItemCallback {
+ ctor public MediaBrowser.ItemCallback();
+ method public void onError(java.lang.String);
+ method public void onItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+ }
+
public static class MediaBrowser.MediaItem implements android.os.Parcelable {
ctor public MediaBrowser.MediaItem(android.media.MediaDescription, int);
method public int describeContents();
@@ -17240,12 +17247,6 @@ package android.media.browse {
field public static final int FLAG_PLAYABLE = 2; // 0x2
}
- public static abstract class MediaBrowser.MediaItemCallback {
- ctor public MediaBrowser.MediaItemCallback();
- method public void onError();
- method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
- }
-
public static abstract class MediaBrowser.SubscriptionCallback {
ctor public MediaBrowser.SubscriptionCallback();
method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -28787,12 +28788,12 @@ package android.service.media {
public abstract class MediaBrowserService extends android.app.Service {
ctor public MediaBrowserService();
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public android.media.session.MediaSession.Token getSessionToken();
method public void notifyChildrenChanged(java.lang.String);
method public android.os.IBinder onBind(android.content.Intent);
method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+ method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public void setSessionToken(android.media.session.MediaSession.Token);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 04649b2..a37a1b4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7944,6 +7944,7 @@ package android.content {
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
method public final T getSystemService(java.lang.Class<T>);
+ method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -18522,7 +18523,7 @@ package android.media.browse {
method public void connect();
method public void disconnect();
method public android.os.Bundle getExtras();
- method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
+ method public void getItem(java.lang.String, android.media.browse.MediaBrowser.ItemCallback);
method public java.lang.String getRoot();
method public android.content.ComponentName getServiceComponent();
method public android.media.session.MediaSession.Token getSessionToken();
@@ -18538,6 +18539,12 @@ package android.media.browse {
method public void onConnectionSuspended();
}
+ public static abstract class MediaBrowser.ItemCallback {
+ ctor public MediaBrowser.ItemCallback();
+ method public void onError(java.lang.String);
+ method public void onItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+ }
+
public static class MediaBrowser.MediaItem implements android.os.Parcelable {
ctor public MediaBrowser.MediaItem(android.media.MediaDescription, int);
method public int describeContents();
@@ -18552,12 +18559,6 @@ package android.media.browse {
field public static final int FLAG_PLAYABLE = 2; // 0x2
}
- public static abstract class MediaBrowser.MediaItemCallback {
- ctor public MediaBrowser.MediaItemCallback();
- method public void onError();
- method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
- }
-
public static abstract class MediaBrowser.SubscriptionCallback {
ctor public MediaBrowser.SubscriptionCallback();
method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -30822,12 +30823,12 @@ package android.service.media {
public abstract class MediaBrowserService extends android.app.Service {
ctor public MediaBrowserService();
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public android.media.session.MediaSession.Token getSessionToken();
method public void notifyChildrenChanged(java.lang.String);
method public android.os.IBinder onBind(android.content.Intent);
method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+ method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public void setSessionToken(android.media.session.MediaSession.Token);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 49ac062..fd1e24a 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -28,6 +28,11 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
+/**
+ * Represents a single operation to be performed as part of a batch of operations.
+ *
+ * @see ContentProvider#applyBatch(ArrayList)
+ */
public class ContentProviderOperation implements Parcelable {
/** @hide exposed for unit tests */
public final static int TYPE_INSERT = 1;
@@ -195,10 +200,19 @@ public class ContentProviderOperation implements Parcelable {
return new Builder(TYPE_ASSERT, uri);
}
+ /**
+ * Gets the Uri for the target of the operation.
+ */
public Uri getUri() {
return mUri;
}
+ /**
+ * Returns true if the operation allows yielding the database to other transactions
+ * if the database is contended.
+ *
+ * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
+ */
public boolean isYieldAllowed() {
return mYieldAllowed;
}
@@ -208,26 +222,58 @@ public class ContentProviderOperation implements Parcelable {
return mType;
}
+ /**
+ * Returns true if the operation represents an insertion.
+ *
+ * @see #newInsert
+ */
public boolean isInsert() {
return mType == TYPE_INSERT;
}
+ /**
+ * Returns true if the operation represents a deletion.
+ *
+ * @see #newDelete
+ */
public boolean isDelete() {
return mType == TYPE_DELETE;
}
+ /**
+ * Returns true if the operation represents an update.
+ *
+ * @see #newUpdate
+ */
public boolean isUpdate() {
return mType == TYPE_UPDATE;
}
+ /**
+ * Returns true if the operation represents an assert query.
+ *
+ * @see #newAssertQuery
+ */
public boolean isAssertQuery() {
return mType == TYPE_ASSERT;
}
+ /**
+ * Returns true if the operation represents an insertion, deletion, or update.
+ *
+ * @see #isInsert
+ * @see #isDelete
+ * @see #isUpdate
+ */
public boolean isWriteOperation() {
return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
}
+ /**
+ * Returns true if the operation represents an assert query.
+ *
+ * @see #isAssertQuery
+ */
public boolean isReadOperation() {
return mType == TYPE_ASSERT;
}
@@ -617,7 +663,7 @@ public class ContentProviderOperation implements Parcelable {
}
/**
- * If set then if the number of rows affected by this operation do not match
+ * If set then if the number of rows affected by this operation does not match
* this count {@link OperationApplicationException} will be throw.
* This can only be used with builders of type update, delete, or assert.
* @return this builder, to allow for chaining.
@@ -631,6 +677,12 @@ public class ContentProviderOperation implements Parcelable {
return this;
}
+ /**
+ * If set to true then the operation allows yielding the database to other transactions
+ * if the database is contended.
+ * @return this builder, to allow for chaining.
+ * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
+ */
public Builder withYieldAllowed(boolean yieldAllowed) {
mYieldAllowed = yieldAllowed;
return this;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a434c7b..33f38fb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2443,8 +2443,6 @@ public abstract class Context {
*
* @param serviceClass The class of the desired service.
* @return The service name or null if the class is not a supported system service.
- *
- * @hide
*/
public abstract String getSystemServiceName(Class<?> serviceClass);
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index e47220b..71fda1c 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -24,6 +24,7 @@ import android.os.Messenger;
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Protocol;
/**
@@ -176,9 +177,9 @@ public class NetworkFactory extends Handler {
private void handleRemoveRequest(NetworkRequest request) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
- if (n != null && n.requested) {
+ if (n != null) {
mNetworkRequests.remove(request.requestId);
- releaseNetworkFor(n.request);
+ if (n.requested) releaseNetworkFor(n.request);
}
}
@@ -273,6 +274,11 @@ public class NetworkFactory extends Handler {
sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap)));
}
+ @VisibleForTesting
+ protected int getRequestCount() {
+ return mNetworkRequests.size();
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, s);
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba4af89..39c86f9 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -18,8 +18,6 @@ package com.android.internal.app;
import android.app.Activity;
import android.app.ActivityThread;
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
import android.os.AsyncTask;
import android.provider.Settings;
import android.text.TextUtils;
@@ -64,14 +62,11 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.widget.ResolverDrawerLayout;
-import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -100,10 +95,7 @@ public class ResolverActivity extends Activity {
private boolean mResolvingHome = false;
private int mProfileSwitchMessageId = -1;
private final ArrayList<Intent> mIntents = new ArrayList<>();
-
- private UsageStatsManager mUsm;
- private Map<String, UsageStats> mStats;
- private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
+ private ResolverComparator mResolverComparator;
private boolean mRegistered;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -222,10 +214,6 @@ public class ResolverActivity extends Activity {
}
mPm = getPackageManager();
- mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
-
- final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
- mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis());
mPackageMonitor.register(this, getMainLooper(), false);
mRegistered = true;
@@ -236,6 +224,10 @@ public class ResolverActivity extends Activity {
// Add our initial intent as the first item, regardless of what else has already been added.
mIntents.add(0, new Intent(intent));
+ final String referrerPackage = getReferrerPackageName();
+
+ mResolverComparator = new ResolverComparator(this, getTargetIntent(), referrerPackage);
+
configureContentView(mIntents, initialIntents, rList, alwaysUseOption);
// Prevent the Resolver window from becoming the top fullscreen window and thus from taking
@@ -265,7 +257,6 @@ public class ResolverActivity extends Activity {
// Try to initialize the title icon if we have a view for it and a title to match
final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon);
if (titleIcon != null) {
- final String referrerPackage = getReferrerPackageName();
ApplicationInfo ai = null;
try {
if (!TextUtils.isEmpty(referrerPackage)) {
@@ -1175,8 +1166,8 @@ public class ResolverActivity extends Activity {
}
}
if (N > 1) {
- Collections.sort(currentResolveList,
- new ResolverComparator(ResolverActivity.this, getTargetIntent()));
+ mResolverComparator.compute(currentResolveList);
+ Collections.sort(currentResolveList, mResolverComparator);
}
// First put the initial items at the top.
if (mInitialIntents != null) {
@@ -1651,63 +1642,4 @@ public class ResolverActivity extends Activity {
&& match <= IntentFilter.MATCH_CATEGORY_PATH;
}
- class ResolverComparator implements Comparator<ResolvedComponentInfo> {
- private final Collator mCollator;
- private final boolean mHttp;
-
- 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
- public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) {
- final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
- final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
-
- // We want to put the one targeted to another user at the end of the dialog.
- if (lhs.targetUserId != UserHandle.USER_CURRENT) {
- 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) -
- getPackageTimeSpent(lhs.activityInfo.packageName);
-
- if (timeDiff != 0) {
- return timeDiff > 0 ? 1 : -1;
- }
- }
-
- CharSequence sa = lhs.loadLabel(mPm);
- if (sa == null) sa = lhs.activityInfo.name;
- CharSequence sb = rhs.loadLabel(mPm);
- if (sb == null) sb = rhs.activityInfo.name;
-
- return mCollator.compare(sa.toString(), sb.toString());
- }
-
- private long getPackageTimeSpent(String packageName) {
- if (mStats != null) {
- final UsageStats stats = mStats.get(packageName);
- if (stats != null) {
- return stats.getTotalTimeInForeground();
- }
- }
- return 0;
- }
- }
}
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
new file mode 100644
index 0000000..42668f1
--- /dev/null
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 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.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Ranks and compares packages based on usage stats.
+ */
+class ResolverComparator implements Comparator<ResolvedComponentInfo> {
+ private static final String TAG = "ResolverComparator";
+
+ private static final boolean DEBUG = true;
+
+ // Two weeks
+ private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
+
+ private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12;
+
+ private static final float RECENCY_MULTIPLIER = 3.f;
+
+ private final Collator mCollator;
+ private final boolean mHttp;
+ private final PackageManager mPm;
+ private final UsageStatsManager mUsm;
+ private final Map<String, UsageStats> mStats;
+ private final long mCurrentTime;
+ private final long mSinceTime;
+ private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>();
+ private final String mReferrerPackage;
+
+ public ResolverComparator(Context context, Intent intent, String referrerPackage) {
+ mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+ String scheme = intent.getScheme();
+ mHttp = "http".equals(scheme) || "https".equals(scheme);
+ mReferrerPackage = referrerPackage;
+
+ mPm = context.getPackageManager();
+ mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
+
+ mCurrentTime = System.currentTimeMillis();
+ mSinceTime = mCurrentTime - USAGE_STATS_PERIOD;
+ mStats = mUsm.queryAndAggregateUsageStats(mSinceTime, mCurrentTime);
+ }
+
+ public void compute(List<ResolvedComponentInfo> targets) {
+ mScoredTargets.clear();
+
+ final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
+
+ long mostRecentlyUsedTime = recentSinceTime + 1;
+ long mostTimeSpent = 1;
+ int mostLaunched = 1;
+
+ for (ResolvedComponentInfo target : targets) {
+ final ScoredTarget scoredTarget
+ = new ScoredTarget(target.getResolveInfoAt(0).activityInfo);
+ mScoredTargets.put(target.name, scoredTarget);
+ final UsageStats pkStats = mStats.get(target.name.getPackageName());
+ if (pkStats != null) {
+ // Only count recency for apps that weren't the caller
+ // since the caller is always the most recent.
+ // Persistent processes muck this up, so omit them too.
+ if (!target.name.getPackageName().equals(mReferrerPackage)
+ && !isPersistentProcess(target)) {
+ final long lastTimeUsed = pkStats.getLastTimeUsed();
+ scoredTarget.lastTimeUsed = lastTimeUsed;
+ if (lastTimeUsed > mostRecentlyUsedTime) {
+ mostRecentlyUsedTime = lastTimeUsed;
+ }
+ }
+ final long timeSpent = pkStats.getTotalTimeInForeground();
+ scoredTarget.timeSpent = timeSpent;
+ if (timeSpent > mostTimeSpent) {
+ mostTimeSpent = timeSpent;
+ }
+ final int launched = pkStats.mLaunchCount;
+ scoredTarget.launchCount = launched;
+ if (launched > mostLaunched) {
+ mostLaunched = launched;
+ }
+ }
+ }
+
+
+ if (DEBUG) {
+ Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime
+ + " mostTimeSpent: " + mostTimeSpent
+ + " recentSinceTime: " + recentSinceTime
+ + " mostLaunched: " + mostLaunched);
+ }
+
+ for (ScoredTarget target : mScoredTargets.values()) {
+ final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0)
+ / (mostRecentlyUsedTime - recentSinceTime);
+ final float recencyScore = recency * recency * RECENCY_MULTIPLIER;
+ final float usageTimeScore = (float) target.timeSpent / mostTimeSpent;
+ final float launchCountScore = (float) target.launchCount / mostLaunched;
+
+ target.score = recencyScore + usageTimeScore + launchCountScore;
+ if (DEBUG) {
+ Log.d(TAG, "Scores: recencyScore: " + recencyScore
+ + " usageTimeScore: " + usageTimeScore
+ + " launchCountScore: " + launchCountScore
+ + " - " + target);
+ }
+ }
+ }
+
+ static boolean isPersistentProcess(ResolvedComponentInfo rci) {
+ if (rci != null && rci.getCount() > 0) {
+ return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
+ ApplicationInfo.FLAG_PERSISTENT) != 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) {
+ final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
+ final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
+
+ // We want to put the one targeted to another user at the end of the dialog.
+ if (lhs.targetUserId != UserHandle.USER_CURRENT) {
+ 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 = ResolverActivity.isSpecificUriMatch(lhs.match);
+ final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match);
+ if (lhsSpecific != rhsSpecific) {
+ return lhsSpecific ? -1 : 1;
+ }
+ }
+
+ if (mStats != null) {
+ final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName(
+ lhs.activityInfo.packageName, lhs.activityInfo.name));
+ final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName(
+ rhs.activityInfo.packageName, rhs.activityInfo.name));
+ final float diff = rhsTarget.score - lhsTarget.score;
+
+ if (diff != 0) {
+ return diff > 0 ? 1 : -1;
+ }
+ }
+
+ CharSequence sa = lhs.loadLabel(mPm);
+ if (sa == null) sa = lhs.activityInfo.name;
+ CharSequence sb = rhs.loadLabel(mPm);
+ if (sb == null) sb = rhs.activityInfo.name;
+
+ return mCollator.compare(sa.toString().trim(), sb.toString().trim());
+ }
+
+ static class ScoredTarget {
+ public final ComponentInfo componentInfo;
+ public float score;
+ public long lastTimeUsed;
+ public long timeSpent;
+ public long launchCount;
+
+ public ScoredTarget(ComponentInfo ci) {
+ componentInfo = ci;
+ }
+
+ @Override
+ public String toString() {
+ return "ScoredTarget{" + componentInfo
+ + " score: " + score
+ + " lastTimeUsed: " + lastTimeUsed
+ + " timeSpent: " + timeSpent
+ + " launchCount: " + launchCount
+ + "}";
+ }
+ }
+}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index ef8d169..ba867e1 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -375,7 +375,7 @@ public final class MediaBrowser {
* @param mediaId The id of the item to retrieve.
* @param cb The callback to receive the result on.
*/
- public void getMediaItem(@NonNull String mediaId, @NonNull final MediaItemCallback cb) {
+ public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
if (TextUtils.isEmpty(mediaId)) {
throw new IllegalArgumentException("mediaId is empty.");
}
@@ -387,7 +387,7 @@ public final class MediaBrowser {
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
return;
@@ -397,15 +397,15 @@ public final class MediaBrowser {
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode != 0 || resultData == null
|| !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
- cb.onError();
+ cb.onError(mediaId);
return;
}
Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
if (!(item instanceof MediaItem)) {
- cb.onError();
+ cb.onError(mediaId);
+ return;
}
- cb.onMediaItemLoaded((MediaItem) resultData.getParcelable(
- MediaBrowserService.KEY_MEDIA_ITEM));
+ cb.onItemLoaded((MediaItem)item);
}
};
try {
@@ -415,7 +415,7 @@ public final class MediaBrowser {
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
}
@@ -728,6 +728,9 @@ public final class MediaBrowser {
public static abstract class SubscriptionCallback {
/**
* Called when the list of children is loaded or updated.
+ *
+ * @param parentId The media id of the parent media item.
+ * @param children The children which were loaded.
*/
public void onChildrenLoaded(@NonNull String parentId,
@NonNull List<MediaItem> children) {
@@ -739,29 +742,32 @@ public final class MediaBrowser {
* If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
* called, because some errors may heal themselves.
* </p>
+ *
+ * @param parentId The media id of the parent media item whose children could
+ * not be loaded.
*/
- public void onError(@NonNull String id) {
+ public void onError(@NonNull String parentId) {
}
}
/**
- * Callback for receiving the result of {@link #getMediaItem}.
+ * Callback for receiving the result of {@link #getItem}.
*/
- public static abstract class MediaItemCallback {
-
+ public static abstract class ItemCallback {
/**
* Called when the item has been returned by the browser service.
*
* @param item The item that was returned or null if it doesn't exist.
*/
- public void onMediaItemLoaded(MediaItem item) {
+ public void onItemLoaded(MediaItem item) {
}
/**
- * Called when the id doesn't exist or there was an error retrieving the
- * item.
+ * Called when the item doesn't exist or there was an error retrieving it.
+ *
+ * @param itemId The media id of the media item which could not be loaded.
*/
- public void onError() {
+ public void onError(@NonNull String itemId) {
}
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 41156cb..1bb99ff 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -76,7 +76,7 @@ public abstract class MediaBrowserService extends Service {
public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
/**
- * A key for passing the MediaItem to the ResultReceiver in getMediaItem.
+ * A key for passing the MediaItem to the ResultReceiver in getItem.
*
* @hide
*/
@@ -109,6 +109,7 @@ public abstract class MediaBrowserService extends Service {
* be thrown.
*
* @see MediaBrowserService#onLoadChildren
+ * @see MediaBrowserService#onGetMediaItem
*/
public class Result<T> {
private Object mDebug;
@@ -279,20 +280,7 @@ public abstract class MediaBrowserService extends Service {
mHandler.post(new Runnable() {
@Override
public void run() {
- final Result<MediaBrowser.MediaItem> result
- = new Result<MediaBrowser.MediaItem>(mediaId) {
- @Override
- void onResultSent(MediaBrowser.MediaItem item) {
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_MEDIA_ITEM, item);
- receiver.send(0, bundle);
- }
- };
- try {
- MediaBrowserService.this.getMediaItem(mediaId, result);
- } catch (UnsupportedOperationException e) {
- receiver.send(-1, null);
- }
+ performLoadItem(mediaId, receiver);
}
});
}
@@ -357,8 +345,7 @@ public abstract class MediaBrowserService extends Service {
@NonNull Result<List<MediaBrowser.MediaItem>> result);
/**
- * Called to get a specific media item. The mediaId should be the same id
- * that would be returned for this item when it is in a list of child items.
+ * Called to get information about a specific media item.
* <p>
* Implementations must call {@link Result#sendResult result.sendResult}. If
* loading the item will be an expensive operation {@link Result#detach
@@ -366,17 +353,15 @@ public abstract class MediaBrowserService extends Service {
* then {@link Result#sendResult result.sendResult} called when the item has
* been loaded.
* <p>
- * The default implementation throws an exception.
+ * The default implementation sends a null result.
*
- * @param mediaId The id for the specific
+ * @param itemId The id for the specific
* {@link android.media.browse.MediaBrowser.MediaItem}.
* @param result The Result to send the item to, or null if the id is
* invalid.
- * @throws UnsupportedOperationException
*/
- public void getMediaItem(String mediaId, Result<MediaBrowser.MediaItem> result)
- throws UnsupportedOperationException {
- throw new UnsupportedOperationException("getMediaItem is not supported.");
+ public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
+ result.sendResult(null);
}
/**
@@ -515,6 +500,25 @@ public abstract class MediaBrowserService extends Service {
}
}
+ private void performLoadItem(String itemId, final ResultReceiver receiver) {
+ final Result<MediaBrowser.MediaItem> result =
+ new Result<MediaBrowser.MediaItem>(itemId) {
+ @Override
+ void onResultSent(MediaBrowser.MediaItem item) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_MEDIA_ITEM, item);
+ receiver.send(0, bundle);
+ }
+ };
+
+ MediaBrowserService.this.onLoadItem(itemId, result);
+
+ if (!result.isDone()) {
+ throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
+ + " before returning for id=" + itemId);
+ }
+ }
+
/**
* Contains information that the browser service needs to send to the client
* when first connected.
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 294cd84..634ba64 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -293,7 +293,8 @@ static jlong ImageWriter_init(JNIEnv* env, jobject thiz, jobject weakThiz, jobje
res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
if (res != OK) {
ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
- __FUNCTION__, GRALLOC_USAGE_SW_WRITE_OFTEN, format, strerror(-res), res);
+ __FUNCTION__, static_cast<unsigned int>(GRALLOC_USAGE_SW_WRITE_OFTEN),
+ format, strerror(-res), res);
jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
return 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 8c03350..03d0482 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -340,6 +340,12 @@ public abstract class ExpandableView extends FrameLayout {
outRect.top += getTranslationY() + getClipTopAmount();
}
+ @Override
+ public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
+ super.getBoundsOnScreen(outRect, clipToParent);
+ outRect.bottom = (int) (outRect.top + getActualHeight());
+ }
+
public int getContentHeight() {
return mActualHeight - getBottomDecorHeight();
}
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 6684be4..bb0a36f 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -48,6 +48,7 @@ import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
@@ -55,6 +56,7 @@ import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.os.ConditionVariable;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.INetworkManagementService;
import android.test.AndroidTestCase;
@@ -68,6 +70,7 @@ import org.mockito.ArgumentCaptor;
import java.net.InetAddress;
import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Tests for {@link ConnectivityService}.
@@ -224,6 +227,31 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
}
+ private static class MockNetworkFactory extends NetworkFactory {
+ final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
+
+ public MockNetworkFactory(Looper looper, Context context, String logTag,
+ NetworkCapabilities filter) {
+ super(looper, context, logTag, filter);
+ }
+
+ public int getMyRequestCount() {
+ return getRequestCount();
+ }
+
+ protected void startNetwork() {
+ mNetworkStarted.set(true);
+ }
+
+ protected void stopNetwork() {
+ mNetworkStarted.set(false);
+ }
+
+ public boolean getMyStartRequested() {
+ return mNetworkStarted.get();
+ }
+ }
+
private class WrappedConnectivityService extends ConnectivityService {
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
@@ -447,6 +475,71 @@ public class ConnectivityServiceTest extends AndroidTestCase {
verifyNoNetwork();
}
+ @LargeTest
+ public void testNetworkFactoryRequests() throws Exception {
+ NetworkCapabilities filter = new NetworkCapabilities();
+ filter.addCapability(NET_CAPABILITY_INTERNET);
+ final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
+ handlerThread.start();
+ MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "testFactory", filter);
+ testFactory.setScoreFilter(40);
+ testFactory.register();
+ try {
+ Thread.sleep(500);
+ } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(true, testFactory.getMyStartRequested());
+
+ // now bring in a higher scored network
+ MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ testAgent.connect(true);
+ cv.block();
+ // part of the bringup makes another network request and then releases it
+ // wait for the release
+ try { Thread.sleep(500); } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // bring in a bunch of requests..
+ ConnectivityManager.NetworkCallback[] networkCallbacks =
+ new ConnectivityManager.NetworkCallback[10];
+ for (int i = 0; i< networkCallbacks.length; i++) {
+ networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ mCm.requestNetwork(builder.build(), networkCallbacks[i]);
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e) {}
+ assertEquals(11, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // remove the requests
+ for (int i = 0; i < networkCallbacks.length; i++) {
+ mCm.unregisterNetworkCallback(networkCallbacks[i]);
+ }
+ try {
+ Thread.sleep(500);
+ } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // drop the higher scored network
+ cv = waitForConnectivityBroadcasts(1);
+ testAgent.disconnect();
+ cv.block();
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(true, testFactory.getMyStartRequested());
+
+ testFactory.unregister();
+ handlerThread.quit();
+ }
+
+
// @Override
// public void tearDown() throws Exception {
// super.tearDown();