diff options
-rw-r--r-- | api/current.txt | 17 | ||||
-rw-r--r-- | api/system-current.txt | 17 | ||||
-rw-r--r-- | core/java/android/content/ContentProviderOperation.java | 54 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 2 | ||||
-rw-r--r-- | core/java/android/net/NetworkFactory.java | 10 | ||||
-rw-r--r-- | core/java/com/android/internal/app/ResolverActivity.java | 82 | ||||
-rw-r--r-- | core/java/com/android/internal/app/ResolverComparator.java | 215 | ||||
-rw-r--r-- | media/java/android/media/browse/MediaBrowser.java | 36 | ||||
-rw-r--r-- | media/java/android/service/media/MediaBrowserService.java | 50 | ||||
-rw-r--r-- | media/jni/android_media_ImageWriter.cpp | 3 | ||||
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java | 6 | ||||
-rw-r--r-- | services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java | 93 |
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(); |