diff options
Diffstat (limited to 'core')
163 files changed, 1411 insertions, 909 deletions
diff --git a/core/java/android/annotation/PrivateApi.java b/core/java/android/annotation/PrivateApi.java new file mode 100644 index 0000000..985eafe --- /dev/null +++ b/core/java/android/annotation/PrivateApi.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2008 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 android.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Indicates an API is exposed for use by bundled applications. + * <p> + * These APIs are not guaranteed to remain consistent release-to-release, + * and are not for use by apps linking against the SDK. + * @hide + */ +@Retention(RetentionPolicy.SOURCE) +public @interface PrivateApi { +} diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b103e71..9a3478e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -157,7 +157,7 @@ public final class ActivityThread { private static final int LOG_ON_PAUSE_CALLED = 30021; private static final int LOG_ON_RESUME_CALLED = 30022; - static ContextImpl mSystemContext = null; + private ContextImpl mSystemContext; static IPackageManager sPackageManager; @@ -1700,7 +1700,7 @@ public final class ActivityThread { ? mBoundApplication.processName : null) + ")"); packageInfo = - new LoadedApk(this, aInfo, compatInfo, this, baseLoader, + new LoadedApk(this, aInfo, compatInfo, baseLoader, securityViolation, includeCode && (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0); if (includeCode) { @@ -1753,26 +1753,15 @@ public final class ActivityThread { public ContextImpl getSystemContext() { synchronized (this) { if (mSystemContext == null) { - ContextImpl context = - ContextImpl.createSystemContext(this); - LoadedApk info = new LoadedApk(this, "android", context, null, - CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO); - context.init(info, null, this); - context.getResources().updateConfiguration(mResourcesManager.getConfiguration(), - mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY)); - mSystemContext = context; - //Slog.i(TAG, "Created system resources " + context.getResources() - // + ": " + context.getResources().getConfiguration()); + mSystemContext = ContextImpl.createSystemContext(this); } + return mSystemContext; } - return mSystemContext; } public void installSystemApplicationInfo(ApplicationInfo info) { synchronized (this) { - ContextImpl context = getSystemContext(); - context.init(new LoadedApk(this, "android", context, info, - CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO), null, this); + getSystemContext().installSystemApplicationInfo(info); // give ourselves a default profiler mProfiler = new Profiler(); @@ -2258,8 +2247,7 @@ public final class ActivityThread { private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { - ContextImpl appContext = new ContextImpl(); - appContext.init(r.packageInfo, r.token, this); + ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token); appContext.setOuterContext(activity); // For debugging purposes, if the activity's package name contains the value of @@ -2544,8 +2532,7 @@ public final class ActivityThread { agent = (BackupAgent) cl.loadClass(classname).newInstance(); // set up the agent's context - ContextImpl context = new ContextImpl(); - context.init(packageInfo, null, this); + ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(agent); agent.attach(context); @@ -2617,11 +2604,10 @@ public final class ActivityThread { try { if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); - ContextImpl context = new ContextImpl(); - context.init(packageInfo, null, this); + ContextImpl context = ContextImpl.createAppContext(this, packageInfo); + context.setOuterContext(service); Application app = packageInfo.makeApplication(false, mInstrumentation); - context.setOuterContext(service); service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); service.onCreate(); @@ -4217,8 +4203,7 @@ public final class ActivityThread { } updateDefaultDensity(); - final ContextImpl appContext = new ContextImpl(); - appContext.init(data.info, null, this); + final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); if (!Process.isIsolated()) { final File cacheDir = appContext.getCacheDir(); @@ -4334,8 +4319,7 @@ public final class ActivityThread { instrApp.nativeLibraryDir = ii.nativeLibraryDir; LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, appContext.getClassLoader(), false, true); - ContextImpl instrContext = new ContextImpl(); - instrContext.init(pi, null, this); + ContextImpl instrContext = ContextImpl.createAppContext(this, pi); try { java.lang.ClassLoader cl = instrContext.getClassLoader(); @@ -4950,8 +4934,8 @@ public final class ActivityThread { UserHandle.myUserId()); try { mInstrumentation = new Instrumentation(); - ContextImpl context = new ContextImpl(); - context.init(getSystemContext().mPackageInfo, null, this); + ContextImpl context = ContextImpl.createAppContext( + this, getSystemContext().mPackageInfo); Application app = Instrumentation.newApplication(Application.class, context); mAllApplications.add(app); mInitialApplication = app; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index aece462..079cf7a 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -36,7 +36,7 @@ import android.os.RemoteException; * API for interacting with "application operation" tracking. * * <p>This API is not generally intended for third party application developers; most - * features are only available to system applicatins. Obtain an instance of it through + * features are only available to system applications. Obtain an instance of it through * {@link Context#getSystemService(String) Context.getSystemService} with * {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.</p> */ @@ -878,7 +878,7 @@ public class AppOpsManager { } /** - * Like {@link #checkOp but instead of throwing a {@link SecurityException} it + * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. */ public int checkOpNoThrow(String op, int uid, String packageName) { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 8d127c6..df50989 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -183,22 +183,31 @@ class ContextImpl extends Context { */ private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs; - /*package*/ LoadedApk mPackageInfo; - private String mBasePackageName; - private String mOpPackageName; - private Resources mResources; - /*package*/ ActivityThread mMainThread; + final ActivityThread mMainThread; + final LoadedApk mPackageInfo; + + private final IBinder mActivityToken; + + private final UserHandle mUser; + + private final ApplicationContentResolver mContentResolver; + + private final String mBasePackageName; + private final String mOpPackageName; + + private final ResourcesManager mResourcesManager; + private final Resources mResources; + private final Display mDisplay; // may be null if default display + private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); + private final Configuration mOverrideConfiguration; + + private final boolean mRestricted; + private Context mOuterContext; - private IBinder mActivityToken = null; - private ApplicationContentResolver mContentResolver; private int mThemeResource = 0; private Resources.Theme mTheme = null; private PackageManager mPackageManager; - private Display mDisplay; // may be null if default display private Context mReceiverRestrictedContext = null; - private boolean mRestricted; - private UserHandle mUser; - private ResourcesManager mResourcesManager; private final Object mSync = new Object(); @@ -220,8 +229,6 @@ class ContextImpl extends Context { private static final String[] EMPTY_FILE_LIST = {}; - final private DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments(); - /** * Override this class when the system service constructor needs a * ContextImpl. Else, use StaticServiceFetcher below. @@ -356,10 +363,11 @@ class ContextImpl extends Context { ctx.mMainThread.getHandler()); }}); - registerService(CONNECTIVITY_SERVICE, new StaticServiceFetcher() { - public Object createStaticService() { + registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE); - return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b)); + return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b), + ctx.getPackageName()); }}); registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() { @@ -1878,20 +1886,17 @@ class ContextImpl extends Context { @Override public Context createPackageContextAsUser(String packageName, int flags, UserHandle user) throws NameNotFoundException { + final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; if (packageName.equals("system") || packageName.equals("android")) { - final ContextImpl context = new ContextImpl(mMainThread.getSystemContext()); - context.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; - context.init(mPackageInfo, null, mMainThread, mResources, mBasePackageName, user); - return context; + return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, + user, restricted, mDisplay, mOverrideConfiguration); } - LoadedApk pi = - mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags, - user.getIdentifier()); + LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), + flags, user.getIdentifier()); if (pi != null) { - ContextImpl c = new ContextImpl(); - c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED; - c.init(pi, null, mMainThread, mResources, mBasePackageName, user); + ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken, + user, restricted, mDisplay, mOverrideConfiguration); if (c.mResources != null) { return c; } @@ -1899,7 +1904,7 @@ class ContextImpl extends Context { // Should be a better exception. throw new PackageManager.NameNotFoundException( - "Application package " + packageName + " not found"); + "Application package " + packageName + " not found"); } @Override @@ -1908,12 +1913,8 @@ class ContextImpl extends Context { throw new IllegalArgumentException("overrideConfiguration must not be null"); } - ContextImpl c = new ContextImpl(); - c.init(mPackageInfo, null, mMainThread); - c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - mPackageInfo.getOverlayDirs(), getDisplayId(), overrideConfiguration, - mResources.getCompatibilityInfo(), mActivityToken); - return c; + return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, + mUser, mRestricted, mDisplay, overrideConfiguration); } @Override @@ -1922,15 +1923,8 @@ class ContextImpl extends Context { throw new IllegalArgumentException("display must not be null"); } - int displayId = display.getDisplayId(); - - ContextImpl context = new ContextImpl(); - context.init(mPackageInfo, null, mMainThread); - context.mDisplay = display; - DisplayAdjustments daj = getDisplayAdjustments(displayId); - context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - mPackageInfo.getOverlayDirs(), displayId, null, daj.getCompatibilityInfo(), null); - return context; + return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken, + mUser, mRestricted, display, mOverrideConfiguration); } private int getDisplayId() { @@ -1972,43 +1966,76 @@ class ContextImpl extends Context { } static ContextImpl createSystemContext(ActivityThread mainThread) { - final ContextImpl context = new ContextImpl(); - context.init(Resources.getSystem(), mainThread, Process.myUserHandle()); + LoadedApk packageInfo = new LoadedApk(mainThread); + ContextImpl context = new ContextImpl(null, mainThread, + packageInfo, null, null, false, null, null); + context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), + context.mResourcesManager.getDisplayMetricsLocked(Display.DEFAULT_DISPLAY)); return context; } - ContextImpl() { - mOuterContext = this; + static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { + if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); + return new ContextImpl(null, mainThread, + packageInfo, null, null, false, null, null); } - /** - * Create a new ApplicationContext from an existing one. The new one - * works and operates the same as the one it is copying. - * - * @param context Existing application context. - */ - public ContextImpl(ContextImpl context) { - mPackageInfo = context.mPackageInfo; - mBasePackageName = context.mBasePackageName; - mOpPackageName = context.mOpPackageName; - mResources = context.mResources; - mMainThread = context.mMainThread; - mContentResolver = context.mContentResolver; - mUser = context.mUser; - mDisplay = context.mDisplay; - mOuterContext = this; - mDisplayAdjustments.setCompatibilityInfo(mPackageInfo.getCompatibilityInfo()); + static ContextImpl createActivityContext(ActivityThread mainThread, + LoadedApk packageInfo, IBinder activityToken) { + if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); + if (activityToken == null) throw new IllegalArgumentException("activityInfo"); + return new ContextImpl(null, mainThread, + packageInfo, activityToken, null, false, null, null); } - final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) { - init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle()); - } + private ContextImpl(ContextImpl container, ActivityThread mainThread, + LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted, + Display display, Configuration overrideConfiguration) { + mOuterContext = this; + + mMainThread = mainThread; + mActivityToken = activityToken; + mRestricted = restricted; + + if (user == null) { + user = Process.myUserHandle(); + } + mUser = user; - final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread, - Resources container, String basePackageName, UserHandle user) { mPackageInfo = packageInfo; - if (basePackageName != null) { - mBasePackageName = mOpPackageName = basePackageName; + mContentResolver = new ApplicationContentResolver(this, mainThread, user); + mResourcesManager = ResourcesManager.getInstance(); + mDisplay = display; + mOverrideConfiguration = overrideConfiguration; + + final int displayId = getDisplayId(); + CompatibilityInfo compatInfo = null; + if (container != null) { + compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo(); + } + if (compatInfo == null && displayId == Display.DEFAULT_DISPLAY) { + compatInfo = packageInfo.getCompatibilityInfo(); + } + mDisplayAdjustments.setCompatibilityInfo(compatInfo); + mDisplayAdjustments.setActivityToken(activityToken); + + Resources resources = packageInfo.getResources(mainThread); + if (resources != null) { + if (activityToken != null + || displayId != Display.DEFAULT_DISPLAY + || overrideConfiguration != null + || (compatInfo != null && compatInfo.applicationScale + != resources.getCompatibilityInfo().applicationScale)) { + resources = mResourcesManager.getTopLevelResources( + packageInfo.getResDir(), packageInfo.getOverlayDirs(), displayId, + overrideConfiguration, compatInfo, activityToken); + } + } + mResources = resources; + + if (container != null) { + mBasePackageName = container.mBasePackageName; + mOpPackageName = container.mOpPackageName; } else { mBasePackageName = packageInfo.mPackageName; ApplicationInfo ainfo = packageInfo.getApplicationInfo(); @@ -2022,45 +2049,10 @@ class ContextImpl extends Context { mOpPackageName = mBasePackageName; } } - mResources = mPackageInfo.getResources(mainThread); - mResourcesManager = ResourcesManager.getInstance(); - - CompatibilityInfo compatInfo = - container == null ? null : container.getCompatibilityInfo(); - if (mResources != null && - ((compatInfo != null && compatInfo.applicationScale != - mResources.getCompatibilityInfo().applicationScale) - || activityToken != null)) { - if (DEBUG) { - Log.d(TAG, "loaded context has different scaling. Using container's" + - " compatiblity info:" + container.getDisplayMetrics()); - } - if (compatInfo == null) { - compatInfo = packageInfo.getCompatibilityInfo(); - } - mDisplayAdjustments.setCompatibilityInfo(compatInfo); - mDisplayAdjustments.setActivityToken(activityToken); - mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - mPackageInfo.getOverlayDirs(), Display.DEFAULT_DISPLAY, null, compatInfo, - activityToken); - } else { - mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo()); - mDisplayAdjustments.setActivityToken(activityToken); - } - mMainThread = mainThread; - mActivityToken = activityToken; - mContentResolver = new ApplicationContentResolver(this, mainThread, user); - mUser = user; } - final void init(Resources resources, ActivityThread mainThread, UserHandle user) { - mPackageInfo = null; - mBasePackageName = null; - mOpPackageName = null; - mResources = resources; - mMainThread = mainThread; - mContentResolver = new ApplicationContentResolver(this, mainThread, user); - mUser = user; + void installSystemApplicationInfo(ApplicationInfo info) { + mPackageInfo.installSystemApplicationInfo(info); } final void scheduleFinalCleanup(String who, String what) { diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 0115d1b..d409352 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -72,7 +72,7 @@ public final class LoadedApk { private static final String TAG = "LoadedApk"; private final ActivityThread mActivityThread; - private final ApplicationInfo mApplicationInfo; + private ApplicationInfo mApplicationInfo; final String mPackageName; private final String mAppDir; private final String mResDir; @@ -111,8 +111,7 @@ public final class LoadedApk { * so MUST NOT call back out to the activity manager. */ public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo, - CompatibilityInfo compatInfo, - ActivityThread mainThread, ClassLoader baseLoader, + CompatibilityInfo compatInfo, ClassLoader baseLoader, boolean securityViolation, boolean includeCode) { mActivityThread = activityThread; mApplicationInfo = aInfo; @@ -134,31 +133,17 @@ public final class LoadedApk { mSecurityViolation = securityViolation; mIncludeCode = includeCode; mDisplayAdjustments.setCompatibilityInfo(compatInfo); - - if (mAppDir == null) { - if (ActivityThread.mSystemContext == null) { - ActivityThread.mSystemContext = - ContextImpl.createSystemContext(mainThread); - ResourcesManager resourcesManager = ResourcesManager.getInstance(); - ActivityThread.mSystemContext.getResources().updateConfiguration( - resourcesManager.getConfiguration(), - resourcesManager.getDisplayMetricsLocked( - Display.DEFAULT_DISPLAY, mDisplayAdjustments), compatInfo); - //Slog.i(TAG, "Created system resources " - // + mSystemContext.getResources() + ": " - // + mSystemContext.getResources().getConfiguration()); - } - mClassLoader = ActivityThread.mSystemContext.getClassLoader(); - mResources = ActivityThread.mSystemContext.getResources(); - } } - public LoadedApk(ActivityThread activityThread, String name, - Context systemContext, ApplicationInfo info, CompatibilityInfo compatInfo) { + /** + * Create information about the system package. + * Must call {@link #installSystemApplicationInfo} later. + */ + LoadedApk(ActivityThread activityThread) { mActivityThread = activityThread; - mApplicationInfo = info != null ? info : new ApplicationInfo(); - mApplicationInfo.packageName = name; - mPackageName = name; + mApplicationInfo = new ApplicationInfo(); + mApplicationInfo.packageName = "android"; + mPackageName = "android"; mAppDir = null; mResDir = null; mOverlayDirs = null; @@ -169,9 +154,16 @@ public final class LoadedApk { mBaseClassLoader = null; mSecurityViolation = false; mIncludeCode = true; - mClassLoader = systemContext.getClassLoader(); - mResources = systemContext.getResources(); - mDisplayAdjustments.setCompatibilityInfo(compatInfo); + mClassLoader = ClassLoader.getSystemClassLoader(); + mResources = Resources.getSystem(); + } + + /** + * Sets application info about the system package. + */ + void installSystemApplicationInfo(ApplicationInfo info) { + assert info.packageName.equals("android"); + mApplicationInfo = info; } public String getPackageName() { @@ -513,8 +505,7 @@ public final class LoadedApk { try { java.lang.ClassLoader cl = getClassLoader(); - ContextImpl appContext = new ContextImpl(); - appContext.init(this, null, mActivityThread); + ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index c63e586..cce6fc4 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1778,7 +1778,7 @@ public class Notification implements Parcelable RemoteViews button = new RemoteViews(mContext.getPackageName(), tombstone ? R.layout.notification_action_tombstone : R.layout.notification_action); - button.setTextViewCompoundDrawables(R.id.action0, action.icon, 0, 0, 0); + button.setTextViewCompoundDrawablesRelative(R.id.action0, action.icon, 0, 0, 0); button.setTextViewText(R.id.action0, action.title); if (!tombstone) { button.setOnClickPendingIntent(R.id.action0, action.actionIntent); diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index bdd0adb..45467b8 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -87,23 +87,25 @@ public final class PendingIntent implements Parcelable { private final IIntentSender mTarget; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: this - * PendingIntent can only be used once. If set, after + * Flag indicating that this PendingIntent can be used only once. + * For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. <p>If set, after * {@link #send()} is called on it, it will be automatically * canceled for you and any future attempt to send through it will fail. */ public static final int FLAG_ONE_SHOT = 1<<30; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: if the described PendingIntent does not already - * exist, then simply return null instead of creating it. + * Flag indicating that if the described PendingIntent already + * exists, then simply return null instead of creating it. + * For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. */ public static final int FLAG_NO_CREATE = 1<<29; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: if the described PendingIntent already exists, - * the current one is canceled before generating a new one. You can use + * Flag indicating that if the described PendingIntent already exists, + * the current one should be canceled before generating a new one. + * For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. <p>You can use * this to retrieve a new PendingIntent when you are only changing the * extra data in the Intent; by canceling the previous pending intent, * this ensures that only entities given the new data will be able to @@ -112,10 +114,10 @@ public final class PendingIntent implements Parcelable { */ public static final int FLAG_CANCEL_CURRENT = 1<<28; /** - * Flag for use with {@link #getActivity}, {@link #getBroadcast}, and - * {@link #getService}: if the described PendingIntent already exists, - * then keep it but its replace its extra data with what is in this new - * Intent. This can be used if you are creating intents where only the + * Flag indicating that if the described PendingIntent already exists, + * then keep it but replace its extra data with what is in this new + * Intent. For use with {@link #getActivity}, {@link #getBroadcast}, and + * {@link #getService}. <p>This can be used if you are creating intents where only the * extras change, and don't care that any entities that received your * previous PendingIntent will be able to launch it with your new * extras even if they are not explicitly given to it. @@ -203,7 +205,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -234,7 +236,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -326,7 +328,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} objects * you supply here should almost always be <em>explicit intents</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -376,7 +378,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} objects * you supply here should almost always be <em>explicit intents</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the activity. @@ -446,7 +448,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should perform * the broadcast. @@ -500,7 +502,7 @@ public final class PendingIntent implements Parcelable { * <p class="note">For security reasons, the {@link android.content.Intent} * you supply here should almost always be an <em>explicit intent</em>, * that is specify an explicit component to be delivered to through - * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p> + * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p> * * @param context The Context in which this PendingIntent should start * the service. diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index c2bbff0..62f7147 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -45,9 +45,7 @@ import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; -import android.util.DisplayMetrics; import android.util.Log; -import android.view.WindowManager; import android.view.WindowManagerGlobal; import java.io.BufferedInputStream; @@ -294,9 +292,8 @@ public class WallpaperManager { try { BitmapFactory.Options options = new BitmapFactory.Options(); - Bitmap bm = BitmapFactory.decodeFileDescriptor( + return BitmapFactory.decodeFileDescriptor( fd.getFileDescriptor(), null, options); - return generateBitmap(context, bm, width, height); } catch (OutOfMemoryError e) { Log.w(TAG, "Can't decode file", e); } finally { @@ -323,8 +320,7 @@ public class WallpaperManager { try { BitmapFactory.Options options = new BitmapFactory.Options(); - Bitmap bm = BitmapFactory.decodeStream(is, null, options); - return generateBitmap(context, bm, width, height); + return BitmapFactory.decodeStream(is, null, options); } catch (OutOfMemoryError e) { Log.w(TAG, "Can't decode stream", e); } finally { @@ -1033,62 +1029,4 @@ public class WallpaperManager { public void clear() throws IOException { setResource(com.android.internal.R.drawable.default_wallpaper); } - - static Bitmap generateBitmap(Context context, Bitmap bm, int width, int height) { - if (bm == null) { - return null; - } - - WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); - DisplayMetrics metrics = new DisplayMetrics(); - wm.getDefaultDisplay().getMetrics(metrics); - bm.setDensity(metrics.noncompatDensityDpi); - - if (width <= 0 || height <= 0 - || (bm.getWidth() == width && bm.getHeight() == height)) { - return bm; - } - - // This is the final bitmap we want to return. - try { - Bitmap newbm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - newbm.setDensity(metrics.noncompatDensityDpi); - - Canvas c = new Canvas(newbm); - Rect targetRect = new Rect(); - targetRect.right = bm.getWidth(); - targetRect.bottom = bm.getHeight(); - - int deltaw = width - targetRect.right; - int deltah = height - targetRect.bottom; - - if (deltaw > 0 || deltah > 0) { - // We need to scale up so it covers the entire area. - float scale; - if (deltaw > deltah) { - scale = width / (float)targetRect.right; - } else { - scale = height / (float)targetRect.bottom; - } - targetRect.right = (int)(targetRect.right*scale); - targetRect.bottom = (int)(targetRect.bottom*scale); - deltaw = width - targetRect.right; - deltah = height - targetRect.bottom; - } - - targetRect.offset(deltaw/2, deltah/2); - - Paint paint = new Paint(); - paint.setFilterBitmap(true); - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); - c.drawBitmap(bm, null, targetRect, paint); - - bm.recycle(); - c.setBitmap(null); - return newbm; - } catch (OutOfMemoryError e) { - Log.w(TAG, "Can't generate default bitmap", e); - return bm; - } - } } diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index bb4f5f1..12ee3b6 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -43,14 +43,14 @@ interface IBackupManager { void dataChanged(String packageName); /** - * Erase all backed-up data for the given package from the storage + * Erase all backed-up data for the given package from the given storage * destination. * * Any application can invoke this method for its own package, but * only callers who hold the android.permission.BACKUP permission * may invoke it for arbitrary packages. */ - void clearBackupData(String packageName); + void clearBackupData(String transportName, String packageName); /** * Notifies the Backup Manager Service that an agent has become available. This diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index e2bc80a..75b007c 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -20,21 +20,23 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.Pair; + import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.HashMap; -import java.util.LinkedList; +import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Random; @@ -214,6 +216,22 @@ public final class BluetoothAdapter { "android.bluetooth.adapter.action.SCAN_MODE_CHANGED"; /** + * Broadcast Action: Indicate BLE Advertising is started. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STARTED = + "android.bluetooth.adapter.action.ADVERTISING_STARTED"; + + /** + * Broadcast Action: Indicated BLE Advertising is stopped. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_BLUETOOTH_ADVERTISING_STOPPED = + "android.bluetooth.adapter.action.ADVERTISING_STOPPED"; + + /** * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED} * intents to request the current scan mode. Possible values are: * {@link #SCAN_MODE_NONE}, @@ -251,7 +269,6 @@ public final class BluetoothAdapter { */ public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23; - /** * Broadcast Action: The local Bluetooth adapter has started the remote * device discovery process. @@ -350,9 +367,27 @@ public final class BluetoothAdapter { /** The profile is in disconnecting state */ public static final int STATE_DISCONNECTING = 3; + /** States for Bluetooth LE advertising */ + /** @hide */ + public static final int STATE_ADVERTISE_STARTING = 0; + /** @hide */ + public static final int STATE_ADVERTISE_STARTED = 1; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPING = 2; + /** @hide */ + public static final int STATE_ADVERTISE_STOPPED = 3; + /** + * Force stopping advertising without callback in case the advertising app dies. + * @hide + */ + public static final int STATE_ADVERTISE_FORCE_STOPPING = 4; + /** @hide */ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager"; + /** @hide */ + public static final int ADVERTISE_CALLBACK_SUCCESS = 0; + private static final int ADDRESS_LENGTH = 17; /** @@ -365,6 +400,10 @@ public final class BluetoothAdapter { private IBluetooth mService; private final Map<LeScanCallback, GattCallbackWrapper> mLeScanClients; + private BluetoothAdvScanData mBluetoothAdvScanData = null; + private GattCallbackWrapper mAdvertisingGattCallback; + private final Handler mHandler; // Handler to post the advertise callback to run on main thread. + private final Object mLock = new Object(); /** * Get a handle to the default local Bluetooth adapter. @@ -400,6 +439,7 @@ public final class BluetoothAdapter { } catch (RemoteException e) {Log.e(TAG, "", e);} mManagerService = managerService; mLeScanClients = new HashMap<LeScanCallback, GattCallbackWrapper>(); + mHandler = new Handler(Looper.getMainLooper()); } /** @@ -438,6 +478,129 @@ public final class BluetoothAdapter { } /** + * Returns a {@link BluetoothAdvScanData} object representing advertising data. + * Data will be reset when bluetooth service is turned off. + * @hide + */ + public BluetoothAdvScanData getAdvScanData() { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + Log.e(TAG, "failed to start, iGatt null"); + return null; + } + if (mBluetoothAdvScanData == null) { + mBluetoothAdvScanData = new BluetoothAdvScanData(iGatt, BluetoothAdvScanData.AD); + } + return mBluetoothAdvScanData; + } catch (RemoteException e) { + Log.e(TAG, "failed to get advScanData, error: " + e); + return null; + } + } + + /** + * Interface for BLE advertising callback. + * + * @hide + */ + public interface AdvertiseCallback { + /** + * Callback when advertise starts. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStart(int status); + /** + * Callback when advertise stops. + * @param status - {@link #ADVERTISE_CALLBACK_SUCCESS} for success, others for failure. + */ + void onAdvertiseStop(int status); + } + + /** + * Start BLE advertising using current {@link BluetoothAdvScanData}. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} + * + * @param callback - {@link AdvertiseCallback} + * @return true if BLE advertising succeeds, false otherwise. + * @hide + */ + public boolean startAdvertising(final AdvertiseCallback callback) { + if (getState() != STATE_ON) return false; + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported. + return false; + } + // Restart/reset advertising packets if advertising is in progress. + if (isAdvertising()) { + // Invalid advertising callback. + if (mAdvertisingGattCallback == null || mAdvertisingGattCallback.mLeHandle == -1) { + Log.e(TAG, "failed to restart advertising, invalid callback"); + return false; + } + iGatt.startAdvertising(mAdvertisingGattCallback.mLeHandle); + // Run the callback from main thread. + mHandler.post(new Runnable() { + @Override + public void run() { + // callback with status success. + callback.onAdvertiseStart(ADVERTISE_CALLBACK_SUCCESS); + } + }); + return true; + } + UUID uuid = UUID.randomUUID(); + GattCallbackWrapper wrapper = + new GattCallbackWrapper(this, null, null, callback); + iGatt.registerClient(new ParcelUuid(uuid), wrapper); + if (!wrapper.advertiseStarted()) { + return false; + } + synchronized (mLock) { + mAdvertisingGattCallback = wrapper; + } + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** + * Stop BLE advertising. + * + * @param callback - {@link AdvertiseCallback} + * @return true if BLE advertising stops, false otherwise. + * @hide + */ + public boolean stopAdvertising(AdvertiseCallback callback) { + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + if (iGatt == null) { + // BLE is not supported + return false; + } + if (mAdvertisingGattCallback == null) { + // no callback. + return false; + } + // Make sure same callback is used for start and stop advertising. + if (callback != mAdvertisingGattCallback.mAdvertiseCallback) { + Log.e(TAG, "must use the same callback for star/stop advertising"); + return false; + } + mAdvertisingGattCallback.stopAdvertising(); + return true; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** * Return true if Bluetooth is currently enabled and ready for use. * <p>Equivalent to: * <code>getBluetoothState() == STATE_ON</code> @@ -849,6 +1012,23 @@ public final class BluetoothAdapter { } /** + * Returns whether BLE is currently advertising. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}. + * + * @hide + */ + public boolean isAdvertising() { + if (getState() != STATE_ON) return false; + try { + IBluetoothGatt iGatt = mManagerService.getBluetoothGatt(); + return iGatt.isAdvertising(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return false; + } + + /** * Return the set of {@link BluetoothDevice} objects that are bonded * (paired) to the local adapter. * <p>If Bluetooth state is not {@link #STATE_ON}, this API @@ -1272,6 +1452,8 @@ public final class BluetoothAdapter { if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService); synchronized (mManagerCallback) { mService = null; + // Reset bluetooth adv scan data when Gatt service is down. + mBluetoothAdvScanData = null; for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){ try { if (cb != null) { @@ -1547,7 +1729,9 @@ public final class BluetoothAdapter { private static final int LE_CALLBACK_REG_TIMEOUT = 2000; private static final int LE_CALLBACK_REG_WAIT_COUNT = 5; + private final AdvertiseCallback mAdvertiseCallback; private final LeScanCallback mLeScanCb; + // mLeHandle 0: not registered // -1: scan stopped // >0: registered and scan started @@ -1561,16 +1745,34 @@ public final class BluetoothAdapter { mLeScanCb = leScanCb; mScanFilter = uuid; mLeHandle = 0; + mAdvertiseCallback = null; + } + + public GattCallbackWrapper(BluetoothAdapter bluetoothAdapter, LeScanCallback leScanCb, + UUID[] uuid, AdvertiseCallback callback) { + mBluetoothAdapter = new WeakReference<BluetoothAdapter>(bluetoothAdapter); + mLeScanCb = leScanCb; + mScanFilter = uuid; + mLeHandle = 0; + mAdvertiseCallback = callback; } public boolean scanStarted() { + return waitForRegisteration(LE_CALLBACK_REG_WAIT_COUNT); + } + + public boolean advertiseStarted() { + // Wait for registeration callback. + return waitForRegisteration(1); + } + + private boolean waitForRegisteration(int maxWaitCount) { boolean started = false; synchronized(this) { if (mLeHandle == -1) return false; - int count = 0; // wait for callback registration and LE scan to start - while (mLeHandle == 0 && count < LE_CALLBACK_REG_WAIT_COUNT) { + while (mLeHandle == 0 && count < maxWaitCount) { try { wait(LE_CALLBACK_REG_TIMEOUT); } catch (InterruptedException e) { @@ -1583,6 +1785,27 @@ public final class BluetoothAdapter { return started; } + public void stopAdvertising() { + synchronized (this) { + if (mLeHandle <= 0) { + Log.e(TAG, "Error state, mLeHandle: " + mLeHandle); + return; + } + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = adapter.getBluetoothManager().getBluetoothGatt(); + iGatt.stopAdvertising(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to stop advertising" + e); + } + } else { + Log.e(TAG, "stopAdvertising, BluetoothAdapter is null"); + } + notifyAll(); + } + } + public void stopLeScan() { synchronized(this) { if (mLeHandle <= 0) { @@ -1624,14 +1847,18 @@ public final class BluetoothAdapter { BluetoothAdapter adapter = mBluetoothAdapter.get(); if (adapter != null) { iGatt = adapter.getBluetoothManager().getBluetoothGatt(); - if (mScanFilter == null) { - iGatt.startScan(mLeHandle, false); + if (mAdvertiseCallback != null) { + iGatt.startAdvertising(mLeHandle); } else { - ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; - for(int i = 0; i != uuids.length; ++i) { - uuids[i] = new ParcelUuid(mScanFilter[i]); - } - iGatt.startScanWithUuids(mLeHandle, false, uuids); + if (mScanFilter == null) { + iGatt.startScan(mLeHandle, false); + } else { + ParcelUuid[] uuids = new ParcelUuid[mScanFilter.length]; + for(int i = 0; i != uuids.length; ++i) { + uuids[i] = new ParcelUuid(mScanFilter[i]); + } + iGatt.startScanWithUuids(mLeHandle, false, uuids); + } } } else { Log.e(TAG, "onClientRegistered, BluetoothAdapter null"); @@ -1642,7 +1869,7 @@ public final class BluetoothAdapter { mLeHandle = -1; } if (mLeHandle == -1) { - // registration succeeded but start scan failed + // registration succeeded but start scan or advertise failed if (iGatt != null) { try { iGatt.unregisterClient(mLeHandle); @@ -1670,7 +1897,7 @@ public final class BluetoothAdapter { * @hide */ public void onScanResult(String address, int rssi, byte[] advData) { - if (DBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); + if (VDBG) Log.d(TAG, "onScanResult() - Device=" + address + " RSSI=" +rssi); // Check null in case the scan has been stopped synchronized(this) { @@ -1759,9 +1986,33 @@ public final class BluetoothAdapter { // no op } - public void onListen(int status) { - // no op + public void onAdvertiseStateChange(int advertiseState, int status) { + Log.d(TAG, "on advertise call back, state: " + advertiseState + " status: " + status); + if (advertiseState == STATE_ADVERTISE_STARTED) { + mAdvertiseCallback.onAdvertiseStart(status); + } else { + synchronized (this) { + if (status == ADVERTISE_CALLBACK_SUCCESS) { + BluetoothAdapter adapter = mBluetoothAdapter.get(); + if (adapter != null) { + try { + IBluetoothGatt iGatt = + adapter.getBluetoothManager().getBluetoothGatt(); + Log.d(TAG, "unregistering client " + mLeHandle); + iGatt.unregisterClient(mLeHandle); + // Reset advertise app handle. + mLeHandle = -1; + adapter.mAdvertisingGattCallback = null; + } catch (RemoteException e) { + Log.e(TAG, "Failed to unregister client" + e); + } + } else { + Log.e(TAG, "cannot unregister client, BluetoothAdapter is null"); + } + } + } + mAdvertiseCallback.onAdvertiseStop(status); + } } } - } diff --git a/core/java/android/bluetooth/BluetoothAdvScanData.java b/core/java/android/bluetooth/BluetoothAdvScanData.java new file mode 100644 index 0000000..df2c256 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothAdvScanData.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; +import android.os.ParcelUuid; +import android.os.RemoteException; +import android.util.Log; + +import java.util.Collections; +import java.util.List; + + +/** + * This class provides the public APIs to set advertising and scan response data when BLE device + * operates in peripheral mode. <br> + * The exact format is defined in Bluetooth 4.0 specification, Volume 3, Part C, Section 11 + * @hide + */ +public final class BluetoothAdvScanData { + + /** + * Available data types of {@link BluetoothAdvScanData}. + */ + public static final int AD = 0; // Advertising Data + public static final int SCAN_RESPONSE = 1; // Scan Response + public static final int EIR = 2; // Extended Inquiry Response + + private static final String TAG = "BluetoothAdvScanData"; + + /** + * Data type of BluetoothAdvScanData. + */ + private final int mDataType; + /** + * Bluetooth Gatt Service. + */ + private IBluetoothGatt mBluetoothGatt; + + /** + * @param mBluetoothGatt + * @param dataType + */ + public BluetoothAdvScanData(IBluetoothGatt mBluetoothGatt, int dataType) { + this.mBluetoothGatt = mBluetoothGatt; + this.mDataType = dataType; + } + + /** + * @return advertising data type. + */ + public int getDataType() { + return mDataType; + } + + /** + * Set manufactureCode and manufactureData. + * Returns true if manufacturer data is set, false if there is no enough room to set + * manufacturer data or the data is already set. + * @param manufacturerCode - unique identifier for the manufacturer + * @param manufacturerData - data associated with the specific manufacturer. + */ + public boolean setManufacturerData(int manufacturerCode, byte[] manufacturerData) { + if (mDataType != AD) return false; + try { + return mBluetoothGatt.setAdvManufacturerCodeAndData(manufacturerCode, manufacturerData); + } catch (RemoteException e) { + Log.e(TAG, "Unable to set manufacturer id and data.", e); + return false; + } + } + + /** + * Set service data. Note the service data can only be set when the data type is {@code AD}; + * @param serviceData + */ + public boolean setServiceData(byte[] serviceData) { + + if (mDataType != AD) return false; + if (serviceData == null) return false; + try { + return mBluetoothGatt.setAdvServiceData(serviceData); + } catch (RemoteException e) { + Log.e(TAG, "Unable to set service data.", e); + return false; + } + } + + /** + * Returns an immutable list of service uuids that will be advertised. + */ + public List<ParcelUuid> getServiceUuids() { + try { + return Collections.unmodifiableList(mBluetoothGatt.getAdvServiceUuids()); + } catch (RemoteException e) { + Log.e(TAG, "Unable to get service uuids.", e); + return null; + } + } + + /** + * Returns manufacturer data. + */ + public byte[] getManufacturerData() { + if (mBluetoothGatt == null) return null; + try { + return mBluetoothGatt.getAdvManufacturerData(); + } catch (RemoteException e) { + Log.e(TAG, "Unable to get manufacturer data.", e); + return null; + } + } + + /** + * Returns service data. + */ + public byte[] getServiceData() { + if (mBluetoothGatt == null) return null; + try { + return mBluetoothGatt.getAdvServiceData(); + } catch (RemoteException e) { + Log.e(TAG, "Unable to get service data.", e); + return null; + } + } + + /** + * Remove manufacturer data based on given manufacturer code. + * @param manufacturerCode + */ + public void removeManufacturerCodeAndData(int manufacturerCode) { + if (mBluetoothGatt != null) { + try { + mBluetoothGatt.removeAdvManufacturerCodeAndData(manufacturerCode); + } catch (RemoteException e) { + Log.e(TAG, "Unable to remove manufacturer : " + manufacturerCode, e); + } + } + } +} diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index a2bb78c..ae6ad3b 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -555,11 +555,12 @@ public final class BluetoothGatt implements BluetoothProfile { } /** - * Listen command status callback + * Advertise state change callback * @hide */ - public void onListen(int status) { - if (DBG) Log.d(TAG, "onListen() - status=" + status); + public void onAdvertiseStateChange(int state, int status) { + if (DBG) Log.d(TAG, "onAdvertiseStateChange() - state = " + + state + " status=" + status); } }; @@ -693,71 +694,6 @@ public final class BluetoothGatt implements BluetoothProfile { return true; } - /** - * Starts or stops sending of advertisement packages to listen for connection - * requests from a central devices. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param start Start or stop advertising - */ - /*package*/ void listen(boolean start) { - if (mContext == null || !mContext.getResources(). - getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) { - throw new UnsupportedOperationException("BluetoothGatt#listen is blocked"); - } - if (DBG) Log.d(TAG, "listen() - start: " + start); - if (mService == null || mClientIf == 0) return; - - try { - mService.clientListen(mClientIf, start); - } catch (RemoteException e) { - Log.e(TAG,"",e); - } - } - - /** - * Sets the advertising data contained in the adv. response packet. - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. - * - * @param advData true to set adv. data, false to set scan response - * @param includeName Inlucde the name in the adv. response - * @param includeTxPower Include TX power value - * @param minInterval Minimum desired scan interval (optional) - * @param maxInterval Maximum desired scan interval (optional) - * @param appearance The appearance flags for the device (optional) - * @param manufacturerData Manufacturer specific data including company ID (optional) - */ - /*package*/ void setAdvData(boolean advData, boolean includeName, boolean includeTxPower, - Integer minInterval, Integer maxInterval, - Integer appearance, Byte[] manufacturerData) { - if (mContext == null || !mContext.getResources(). - getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) { - throw new UnsupportedOperationException("BluetoothGatt#setAdvData is blocked"); - } - if (DBG) Log.d(TAG, "setAdvData()"); - if (mService == null || mClientIf == 0) return; - - byte[] data = new byte[0]; - if (manufacturerData != null) { - data = new byte[manufacturerData.length]; - for(int i = 0; i != manufacturerData.length; ++i) { - data[i] = manufacturerData[i]; - } - } - - try { - mService.setAdvData(mClientIf, !advData, - includeName, includeTxPower, - minInterval != null ? minInterval : 0, - maxInterval != null ? maxInterval : 0, - appearance != null ? appearance : 0, data); - } catch (RemoteException e) { - Log.e(TAG,"",e); - } - } - /** * Disconnects an established connection, or cancels a connection attempt * currently in progress. diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java index 58ee54f..153215c 100644 --- a/core/java/android/bluetooth/BluetoothGattServer.java +++ b/core/java/android/bluetooth/BluetoothGattServer.java @@ -537,7 +537,7 @@ public final class BluetoothGattServer implements BluetoothProfile { try { mService.beginServiceDeclaration(mServerIf, service.getType(), service.getInstanceId(), service.getHandles(), - new ParcelUuid(service.getUuid())); + new ParcelUuid(service.getUuid()), service.isAdvertisePreferred()); List<BluetoothGattService> includedServices = service.getIncludedServices(); for (BluetoothGattService includedService : includedServices) { diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java index 1e66369..52bc0f7 100644 --- a/core/java/android/bluetooth/BluetoothGattService.java +++ b/core/java/android/bluetooth/BluetoothGattService.java @@ -15,8 +15,6 @@ */ package android.bluetooth; -import android.bluetooth.BluetoothDevice; - import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -82,6 +80,11 @@ public class BluetoothGattService { protected List<BluetoothGattService> mIncludedServices; /** + * Whether the service uuid should be advertised. + */ + private boolean mAdvertisePreferred; + + /** * Create a new BluetoothGattService. * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. * @@ -263,4 +266,20 @@ public class BluetoothGattService { } return null; } + + /** + * Returns whether the uuid of the service should be advertised. + * @hide + */ + public boolean isAdvertisePreferred() { + return mAdvertisePreferred; + } + + /** + * Set whether the service uuid should be advertised. + * @hide + */ + public void setAdvertisePreferred(boolean advertisePreferred) { + this.mAdvertisePreferred = advertisePreferred; + } } diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index abdf949..4b28516 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -73,6 +73,9 @@ public final class BluetoothUuid { public static final ParcelUuid MAS = ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); + public static final ParcelUuid BASE_UUID = + ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); + public static final ParcelUuid[] RESERVED_UUIDS = { AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget, @@ -211,4 +214,17 @@ public final class BluetoothUuid { long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32; return (int)value; } + + /** + * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid. + * @param parcelUuid + * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise. + */ + public static boolean isShortUuid(ParcelUuid parcelUuid) { + UUID uuid = parcelUuid.getUuid(); + if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { + return false; + } + return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L); + } } diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index df393db..784cdcc 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -37,10 +37,15 @@ interface IBluetoothGatt { void unregisterClient(in int clientIf); void clientConnect(in int clientIf, in String address, in boolean isDirect); void clientDisconnect(in int clientIf, in String address); - void clientListen(in int clientIf, in boolean start); - void setAdvData(in int clientIf, in boolean setScanRsp, in boolean inclName, - in boolean inclTxPower, in int minInterval, in int maxInterval, - in int appearance, in byte[] manufacturerData); + void startAdvertising(in int appIf); + void stopAdvertising(); + boolean setAdvServiceData(in byte[] serviceData); + byte[] getAdvServiceData(); + boolean setAdvManufacturerCodeAndData(int manufactureCode, in byte[] manufacturerData); + byte[] getAdvManufacturerData(); + List<ParcelUuid> getAdvServiceUuids(); + void removeAdvManufacturerCodeAndData(int manufacturerCode); + boolean isAdvertising(); void refreshDevice(in int clientIf, in String address); void discoverServices(in int clientIf, in String address); void readCharacteristic(in int clientIf, in String address, in int srvcType, @@ -75,7 +80,7 @@ interface IBluetoothGatt { void serverDisconnect(in int serverIf, in String address); void beginServiceDeclaration(in int serverIf, in int srvcType, in int srvcInstanceId, in int minHandles, - in ParcelUuid srvcId); + in ParcelUuid srvcId, boolean advertisePreferred); void addIncludedService(in int serverIf, in int srvcType, in int srvcInstanceId, in ParcelUuid srvcId); void addCharacteristic(in int serverIf, in ParcelUuid charId, diff --git a/core/java/android/bluetooth/IBluetoothGattCallback.aidl b/core/java/android/bluetooth/IBluetoothGattCallback.aidl index 60c297b..7c69a06 100644 --- a/core/java/android/bluetooth/IBluetoothGattCallback.aidl +++ b/core/java/android/bluetooth/IBluetoothGattCallback.aidl @@ -63,5 +63,5 @@ interface IBluetoothGattCallback { in int charInstId, in ParcelUuid charUuid, in byte[] value); void onReadRemoteRssi(in String address, in int rssi, in int status); - void onListen(in int status); + oneway void onAdvertiseStateChange(in int advertiseState, in int status); } diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html index 200a21b..d9ca4f1 100644 --- a/core/java/android/bluetooth/package.html +++ b/core/java/android/bluetooth/package.html @@ -8,17 +8,19 @@ The Bluetooth API supports both "Classic Bluetooth" and Bluetooth Low Energy.</p <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> guide. For more information about Bluetooth Low Energy, see the <a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html"> -Bluetooth Low Energy</a> guide.</p> +Bluetooth Low Energy</a> (BLE) guide.</p> {@more} <p>The Bluetooth APIs let applications:</p> <ul> - <li>Scan for other Bluetooth devices (including Bluetooth Low Energy - devices)</li> - <li>Query the local Bluetooth adapter for paired Bluetooth devices</li> - <li>Establish RFCOMM channels/sockets</li> - <li>Connect to specified sockets on other devices</li> - <li>Transfer data to and from other devices</li> + <li>Scan for other Bluetooth devices (including BLE devices).</li> + <li>Query the local Bluetooth adapter for paired Bluetooth devices.</li> + <li>Establish RFCOMM channels/sockets.</li> + <li>Connect to specified sockets on other devices.</li> + <li>Transfer data to and from other devices.</li> + <li>Communicate with BLE devices, such as proximity sensors, heart rate + monitors, fitness devices, and so on.</li> + <li>Act as a GATT client or a GATT server (BLE).</li> </ul> <p> diff --git a/core/java/android/content/ClipDescription.java b/core/java/android/content/ClipDescription.java index 5cb6e77..be35f08 100644 --- a/core/java/android/content/ClipDescription.java +++ b/core/java/android/content/ClipDescription.java @@ -87,7 +87,7 @@ public class ClipDescription implements Parcelable { /** * Helper to compare two MIME types, where one may be a pattern. * @param concreteType A fully-specified MIME type. - * @param desiredType A desired MIME type that may be a pattern such as *\/*. + * @param desiredType A desired MIME type that may be a pattern such as */*. * @return Returns true if the two MIME types match. */ public static boolean compareMimeTypes(String concreteType, String desiredType) { diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 44831fc..02c850b 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -1328,7 +1328,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param uri The data in the content provider being queried. * @param mimeTypeFilter The type of data the client desires. May be - * a pattern, such as *\/* to retrieve all possible data types. + * a pattern, such as */* to retrieve all possible data types. * @return Returns {@code null} if there are no possible data streams for the * given mimeTypeFilter. Otherwise returns an array of all available * concrete MIME types. @@ -1366,7 +1366,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param uri The data in the content provider being queried. * @param mimeTypeFilter The type of data the client desires. May be - * a pattern, such as *\/*, if the caller does not have specific type + * a pattern, such as */*, if the caller does not have specific type * requirements; in this case the content provider will pick its best * type matching the pattern. * @param opts Additional options from the client. The definitions of @@ -1427,7 +1427,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * * @param uri The data in the content provider being queried. * @param mimeTypeFilter The type of data the client desires. May be - * a pattern, such as *\/*, if the caller does not have specific type + * a pattern, such as */*, if the caller does not have specific type * requirements; in this case the content provider will pick its best * type matching the pattern. * @param opts Additional options from the client. The definitions of diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 4e6cc92..2bf4d7d 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -344,7 +344,7 @@ public abstract class ContentResolver { * @param url A Uri identifying content (either a list or specific type), * using the content:// scheme. * @param mimeTypeFilter The desired MIME type. This may be a pattern, - * such as *\/*, to query for all available MIME types that match the + * such as */*, to query for all available MIME types that match the * pattern. * @return Returns an array of MIME type strings for all available * data streams that match the given mimeTypeFilter. If there are none, @@ -815,7 +815,7 @@ public abstract class ContentResolver { * * <p>Note that if this function is called for read-only input (mode is "r") * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} - * for you with a MIME type of "*\/*". This allows such callers to benefit + * for you with a MIME type of "*/*". This allows such callers to benefit * from any built-in data conversion that a provider implements. * * @param uri The desired URI to open. @@ -868,7 +868,7 @@ public abstract class ContentResolver { * * <p>Note that if this function is called for read-only input (mode is "r") * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} - * for you with a MIME type of "*\/*". This allows such callers to benefit + * for you with a MIME type of "*/*". This allows such callers to benefit * from any built-in data conversion that a provider implements. * * @param uri The desired URI to open. @@ -993,7 +993,7 @@ public abstract class ContentResolver { * * @param uri The desired URI to open. * @param mimeType The desired MIME type of the returned data. This can - * be a pattern such as *\/*, which will allow the content provider to + * be a pattern such as */*, which will allow the content provider to * select a type, though there is no way for you to determine what type * it is returning. * @param opts Additional provider-dependent options. @@ -1026,7 +1026,7 @@ public abstract class ContentResolver { * * @param uri The desired URI to open. * @param mimeType The desired MIME type of the returned data. This can - * be a pattern such as *\/*, which will allow the content provider to + * be a pattern such as */*, which will allow the content provider to * select a type, though there is no way for you to determine what type * it is returning. * @param opts Additional provider-dependent options. @@ -1535,7 +1535,7 @@ public abstract class ContentResolver { * for a whole class of content. * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code> * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI - * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values + * specified by <em>uri</em> will cause notifications to be sent. If <code>true</code>, any URI values * at or below the specified URI will also trigger a match. * @param observer The object that receives callbacks when changes occur. * @see #unregisterContentObserver diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 2e2d4b8..a50b650 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -844,7 +844,7 @@ public class Intent implements Parcelable, Cloneable { * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, then these flags will also be * set in the returned chooser intent, with its ClipData set appropriately: * either a direct reflection of {@link #getClipData()} if that is non-null, - * or a new ClipData build from {@link #getData()}. + * or a new ClipData built from {@link #getData()}. * * @param target The Intent that the user will be selecting an activity * to perform. @@ -4424,7 +4424,7 @@ public class Intent implements Parcelable, Cloneable { * Return the {@link ClipData} associated with this Intent. If there is * none, returns null. See {@link #setClipData} for more information. * - * @see #setClipData; + * @see #setClipData */ public ClipData getClipData() { return mClipData; @@ -5440,7 +5440,7 @@ public class Intent implements Parcelable, Cloneable { * directly used by Intent. Applications should generally rely on the * MIME type of the Intent itself, not what it may find in the ClipData. * A common practice is to construct a ClipData for use with an Intent - * with a MIME type of "*\/*". + * with a MIME type of "*/*". * * @param clip The new clip to set. May be null to clear the current clip. */ @@ -7162,8 +7162,8 @@ public class Intent implements Parcelable, Cloneable { * * @param type MIME data type to normalize * @return normalized MIME data type, or null if the input was null - * @see {@link #setType} - * @see {@link #setTypeAndNormalize} + * @see #setType + * @see #setTypeAndNormalize */ public static String normalizeMimeType(String type) { if (type == null) { diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 111062d..eae4a46 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -45,6 +45,7 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.locks.ReentrantLock; @@ -2150,10 +2151,20 @@ public class Camera { private static final String PIXEL_FORMAT_JPEG = "jpeg"; private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb"; - private HashMap<String, String> mMap; + /** + * Order matters: Keys that are {@link #set(String, String) set} later + * will take precedence over keys that are set earlier (if the two keys + * conflict with each other). + * + * <p>One example is {@link #setPreviewFpsRange(int, int)} , since it + * conflicts with {@link #setPreviewFrameRate(int)} whichever key is set later + * is the one that will take precedence. + * </p> + */ + private final LinkedHashMap<String, String> mMap; private Parameters() { - mMap = new HashMap<String, String>(64); + mMap = new LinkedHashMap<String, String>(/*initialCapacity*/64); } /** @@ -2233,7 +2244,7 @@ public class Camera { return; } - mMap.put(key, value); + put(key, value); } /** @@ -2243,7 +2254,18 @@ public class Camera { * @param value the int value of the parameter */ public void set(String key, int value) { - mMap.put(key, Integer.toString(value)); + put(key, Integer.toString(value)); + } + + private void put(String key, String value) { + /* + * Remove the key if it already exists. + * + * This way setting a new value for an already existing key will always move + * that key to be ordered the latest in the map. + */ + mMap.remove(key); + mMap.put(key, value); } private void set(String key, List<Area> areas) { diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index ac9189d..5f2b5f0 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -1056,8 +1056,8 @@ public abstract class SensorManager { * is mapped. * * @param outR - * the transformed rotation matrix. inR and outR can be the same - * array, but it is not recommended for performance reason. + * the transformed rotation matrix. inR and outR should not be the same + * array. * * @return <code>true</code> on success. <code>false</code> if the input * parameters are incorrect, for instance if X and Y define the same diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index d5208d9..093e0e9 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -297,16 +297,31 @@ public final class DisplayManager { } /** - * Initiates a fresh scan of availble Wifi displays. + * Starts scanning for available Wifi displays. * The results are sent as a {@link #ACTION_WIFI_DISPLAY_STATUS_CHANGED} broadcast. * <p> + * Calls to this method nest and must be matched by an equal number of calls to + * {@link #stopWifiDisplayScan()}. + * </p><p> + * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. + * </p> + * + * @hide + */ + public void startWifiDisplayScan() { + mGlobal.startWifiDisplayScan(); + } + + /** + * Stops scanning for available Wifi displays. + * <p> * Requires {@link android.Manifest.permission#CONFIGURE_WIFI_DISPLAY}. * </p> * * @hide */ - public void scanWifiDisplays() { - mGlobal.scanWifiDisplays(); + public void stopWifiDisplayScan() { + mGlobal.stopWifiDisplayScan(); } /** diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 936a086..3417430 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -72,6 +72,8 @@ public final class DisplayManagerGlobal { private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>(); private int[] mDisplayIdCache; + private int mWifiDisplayScanNestCount; + private DisplayManagerGlobal(IDisplayManager dm) { mDm = dm; } @@ -267,11 +269,32 @@ public final class DisplayManagerGlobal { } } - public void scanWifiDisplays() { - try { - mDm.scanWifiDisplays(); - } catch (RemoteException ex) { - Log.e(TAG, "Failed to scan for Wifi displays.", ex); + public void startWifiDisplayScan() { + synchronized (mLock) { + if (mWifiDisplayScanNestCount++ == 0) { + registerCallbackIfNeededLocked(); + try { + mDm.startWifiDisplayScan(); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to scan for Wifi displays.", ex); + } + } + } + } + + public void stopWifiDisplayScan() { + synchronized (mLock) { + if (--mWifiDisplayScanNestCount == 0) { + try { + mDm.stopWifiDisplayScan(); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to scan for Wifi displays.", ex); + } + } else if (mWifiDisplayScanNestCount < 0) { + Log.wtf(TAG, "Wifi display scan nest count became negative: " + + mWifiDisplayScanNestCount); + mWifiDisplayScanNestCount = 0; + } } } diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl index 6b2c887..68eb13f 100644 --- a/core/java/android/hardware/display/IDisplayManager.aidl +++ b/core/java/android/hardware/display/IDisplayManager.aidl @@ -29,11 +29,14 @@ interface IDisplayManager { void registerCallback(in IDisplayManagerCallback callback); - // No permissions required. - void scanWifiDisplays(); + // Requires CONFIGURE_WIFI_DISPLAY permission. + // The process must have previously registered a callback. + void startWifiDisplayScan(); - // Requires CONFIGURE_WIFI_DISPLAY permission to connect to an unknown device. - // No permissions required to connect to a known device. + // Requires CONFIGURE_WIFI_DISPLAY permission. + void stopWifiDisplayScan(); + + // Requires CONFIGURE_WIFI_DISPLAY permission. void connectWifiDisplay(String address); // No permissions required. @@ -45,6 +48,12 @@ interface IDisplayManager { // Requires CONFIGURE_WIFI_DISPLAY permission. void forgetWifiDisplay(String address); + // Requires CONFIGURE_WIFI_DISPLAY permission. + void pauseWifiDisplay(); + + // Requires CONFIGURE_WIFI_DISPLAY permission. + void resumeWifiDisplay(); + // No permissions required. WifiDisplayStatus getWifiDisplayStatus(); @@ -55,10 +64,4 @@ interface IDisplayManager { // No permissions required but must be same Uid as the creator. void releaseVirtualDisplay(in IBinder token); - - // Requires CONFIGURE_WIFI_DISPLAY permission. - void pauseWifiDisplay(); - - // Requires CONFIGURE_WIFI_DISPLAY permission. - void resumeWifiDisplay(); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c78a973..70c8750 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -395,6 +395,8 @@ public class ConnectivityManager { private final IConnectivityManager mService; + private final String mPackageName; + /** * Tests if a given integer represents a valid network type. * @param networkType the type to be tested @@ -802,7 +804,7 @@ public class ConnectivityManager { public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); try { - return mService.requestRouteToHostAddress(networkType, address); + return mService.requestRouteToHostAddress(networkType, address, mPackageName); } catch (RemoteException e) { return false; } @@ -898,8 +900,9 @@ public class ConnectivityManager { /** * {@hide} */ - public ConnectivityManager(IConnectivityManager service) { + public ConnectivityManager(IConnectivityManager service, String packageName) { mService = checkNotNull(service, "missing IConnectivityManager"); + mPackageName = checkNotNull(packageName, "missing package name"); } /** {@hide} */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c1da2e3..4bca7fe 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -71,9 +71,9 @@ interface IConnectivityManager int stopUsingNetworkFeature(int networkType, in String feature); - boolean requestRouteToHost(int networkType, int hostAddress); + boolean requestRouteToHost(int networkType, int hostAddress, String packageName); - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); + boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); boolean getMobileDataEnabled(); void setMobileDataEnabled(boolean enabled); diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index c106514..21352bf 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -566,6 +566,17 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker { return false; } + + public void setInternalDataEnable(boolean enabled) { + if (DBG) log("setInternalDataEnable: E enabled=" + enabled); + final AsyncChannel channel = mDataConnectionTrackerAc; + if (channel != null) { + channel.sendMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, + enabled ? DctConstants.ENABLED : DctConstants.DISABLED); + } + if (VDBG) log("setInternalDataEnable: X enabled=" + enabled); + } + @Override public void setUserDataEnable(boolean enabled) { if (DBG) log("setUserDataEnable: E enabled=" + enabled); diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index d7dc7f5..7385dff 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -151,9 +151,10 @@ public class VpnService extends Service { } /** - * Protect a socket from VPN connections. The socket will be bound to the - * current default network interface, so its traffic will not be forwarded - * through VPN. This method is useful if some connections need to be kept + * Protect a socket from VPN connections. After protecting, data sent + * through this socket will go directly to the underlying network, + * so its traffic will not be forwarded through the VPN. + * This method is useful if some connections need to be kept * outside of VPN. For example, a VPN tunnel should protect itself if its * destination is covered by VPN routes. Otherwise its outgoing packets * will be sent back to the VPN interface and cause an infinite loop. This diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java index d4a3006..26e09b6 100644 --- a/core/java/android/os/AsyncTask.java +++ b/core/java/android/os/AsyncTask.java @@ -610,7 +610,7 @@ public abstract class AsyncTask<Params, Progress, Result> { * still running. Each call to this method will trigger the execution of * {@link #onProgressUpdate} on the UI thread. * - * {@link #onProgressUpdate} will note be called if the task has been + * {@link #onProgressUpdate} will not be called if the task has been * canceled. * * @param values The progress values to update the UI with. diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 1bddc7a..ab45f02 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -49,7 +49,7 @@ public class Build { /** The manufacturer of the product/hardware. */ public static final String MANUFACTURER = getString("ro.product.manufacturer"); - /** The brand (e.g., carrier) the software is customized for, if any. */ + /** The consumer-visible brand with which the product/hardware will be associated, if any. */ public static final String BRAND = getString("ro.product.brand"); /** The end-user-visible name for the end product. */ diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 21b8ae5..f65b6ba 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -420,7 +420,7 @@ interface INetworkManagementService /** * Clear a user range from being associated with an interface. */ - void clearDnsInterfaceForUidRange(int uid_start, int uid_end); + void clearDnsInterfaceForUidRange(String iface, int uid_start, int uid_end); /** * Clear the mappings from pid to Dns interface and from uid range to Dns interface. diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index 6650fca..5d55143 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -21,11 +21,11 @@ import android.content.Context; /** * Class that operates the vibrator on the device. * <p> - * If your process exits, any vibration you started with will stop. + * If your process exits, any vibration you started will stop. * </p> * * To obtain an instance of the system vibrator, call - * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as argument. + * {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as the argument. */ public abstract class Vibrator { /** diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java index 7ddfa87..2ab5a91 100644 --- a/core/java/android/preference/PreferenceActivity.java +++ b/core/java/android/preference/PreferenceActivity.java @@ -33,6 +33,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Log; import android.util.TypedValue; import android.util.Xml; import android.view.LayoutInflater; @@ -124,6 +125,8 @@ public abstract class PreferenceActivity extends ListActivity implements PreferenceManager.OnPreferenceTreeClickListener, PreferenceFragment.OnPreferenceStartFragmentCallback { + private static final String TAG = "PreferenceActivity"; + // Constants for state save/restore private static final String HEADERS_TAG = ":android:headers"; private static final String CUR_HEADER_TAG = ":android:cur_header"; @@ -521,9 +524,7 @@ public abstract class PreferenceActivity extends ListActivity implements int initialTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE, 0); int initialShortTitle = getIntent().getIntExtra(EXTRA_SHOW_FRAGMENT_SHORT_TITLE, 0); - // Restore from headers only if they are supported which - // is in multi-pane mode. - if (savedInstanceState != null && !mSinglePane) { + if (savedInstanceState != null) { // We are restarting from a previous saved state; used that to // initialize, instead of starting fresh. ArrayList<Header> headers = savedInstanceState.getParcelableArrayList(HEADERS_TAG); diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java index b615600..806a89d 100644 --- a/core/java/android/print/PrinterCapabilitiesInfo.java +++ b/core/java/android/print/PrinterCapabilitiesInfo.java @@ -475,6 +475,12 @@ public final class PrinterCapabilitiesInfo implements Parcelable { * @param colorModes The color mode bit mask. * @param defaultColorMode The default color mode. * @return This builder. + * <p> + * <strong>Note:</strong> On platform version 19 (Kitkat) specifying + * only PrintAttributes#COLOR_MODE_MONOCHROME leads to a print spooler + * crash. Hence, you should declare either both color modes or + * PrintAttributes#COLOR_MODE_COLOR. + * </p> * * @throws IllegalArgumentException If color modes contains an invalid * mode bit or if the default color mode is invalid. diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index b16df28..0863368 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -18,6 +18,7 @@ package android.provider; import android.accounts.Account; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentResolver; @@ -40,6 +41,7 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Pair; import android.view.View; +import android.widget.Toast; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -7981,7 +7983,7 @@ public final class ContactsContract { // Trigger with obtained rectangle Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); - context.startActivity(intent); + startActivityWithErrorToast(context, intent); } /** @@ -8014,7 +8016,16 @@ public final class ContactsContract { String[] excludeMimes) { Intent intent = composeQuickContactsIntent(context, target, lookupUri, mode, excludeMimes); - context.startActivity(intent); + startActivityWithErrorToast(context, intent); + } + + private static void startActivityWithErrorToast(Context context, Intent intent) { + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Toast.makeText(context, com.android.internal.R.string.quick_contacts_not_available, + Toast.LENGTH_SHORT).show(); + } } } diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 39775b6..6519f7e 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -257,8 +257,6 @@ public final class DocumentsContract { * {@link #MIME_TYPE_DIR}. * * @see #COLUMN_FLAGS - * @see DocumentsContract#createDocument(ContentResolver, Uri, String, - * String) * @see DocumentsProvider#createDocument(String, String, String) */ public static final int FLAG_DIR_SUPPORTS_CREATE = 1 << 3; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 04f3f0a..3810eb3 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5140,6 +5140,12 @@ public final class Settings { public static final String SMS_SHORT_CODE_RULE = "sms_short_code_rule"; /** + * Used to select TCP's default initial receiver window size in segments - defaults to a build config value + * @hide + */ + public static final String TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd"; + + /** * Used to disable Tethering on a device - defaults to true * @hide */ diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 5ef86b1..f34e746 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -512,7 +512,7 @@ public class Time { * <pre> * Time time = new Time(); * time.set(4, 10, 2007); // set the date to Nov 4, 2007, 12am - * time.normalize(); // this sets isDst = 1 + * time.normalize(false); // this sets isDst = 1 * time.monthDay += 1; // changes the date to Nov 5, 2007, 12am * millis = time.toMillis(false); // millis is Nov 4, 2007, 11pm * millis = time.toMillis(true); // millis is Nov 5, 2007, 12am diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java index d6e116f..dab853a 100644 --- a/core/java/android/util/LongSparseArray.java +++ b/core/java/android/util/LongSparseArray.java @@ -44,7 +44,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class LongSparseArray<E> implements Cloneable { private static final Object DELETED = new Object(); diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java index 87d868b..6654899 100644 --- a/core/java/android/util/LongSparseLongArray.java +++ b/core/java/android/util/LongSparseLongArray.java @@ -39,7 +39,7 @@ import java.util.Arrays; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> * * @hide */ diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 6e168a8..46d9d45 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -44,7 +44,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseArray<E> implements Cloneable { private static final Object DELETED = new Object(); diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java index 68487e3..905dcb0 100644 --- a/core/java/android/util/SparseBooleanArray.java +++ b/core/java/android/util/SparseBooleanArray.java @@ -38,7 +38,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseBooleanArray implements Cloneable { /** diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java index 0835cb0..4f5ca07 100644 --- a/core/java/android/util/SparseIntArray.java +++ b/core/java/android/util/SparseIntArray.java @@ -37,7 +37,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseIntArray implements Cloneable { private int[] mKeys; diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java index 62c1c0d..39fc8a3 100644 --- a/core/java/android/util/SparseLongArray.java +++ b/core/java/android/util/SparseLongArray.java @@ -37,7 +37,7 @@ import com.android.internal.util.ArrayUtils; * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending - * order in the case of <code>valueAt(int)<code>.</p> + * order in the case of <code>valueAt(int)</code>.</p> */ public class SparseLongArray implements Cloneable { private int[] mKeys; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index bdf4141..ef60755 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6543,7 +6543,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @attr ref android.R.styleable#View_filterTouchesWhenObscured */ public void setFilterTouchesWhenObscured(boolean enabled) { - setFlags(enabled ? 0 : FILTER_TOUCHES_WHEN_OBSCURED, + setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, FILTER_TOUCHES_WHEN_OBSCURED); } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index c3f064f..e67659c 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -212,6 +212,14 @@ public class ViewConfiguration { */ private static final int OVERFLING_DISTANCE = 6; + /** + * Configuration values for overriding {@link #hasPermanentMenuKey()} behavior. + * These constants must match the definition in res/values/config.xml. + */ + private static final int HAS_PERMANENT_MENU_KEY_AUTODETECT = 0; + private static final int HAS_PERMANENT_MENU_KEY_TRUE = 1; + private static final int HAS_PERMANENT_MENU_KEY_FALSE = 2; + private final int mEdgeSlop; private final int mFadingEdgeLength; private final int mMinimumFlingVelocity; @@ -296,12 +304,31 @@ public class ViewConfiguration { mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f); if (!sHasPermanentMenuKeySet) { - IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); - try { - sHasPermanentMenuKey = !wm.hasNavigationBar(); - sHasPermanentMenuKeySet = true; - } catch (RemoteException ex) { - sHasPermanentMenuKey = false; + final int configVal = res.getInteger( + com.android.internal.R.integer.config_overrideHasPermanentMenuKey); + + switch (configVal) { + default: + case HAS_PERMANENT_MENU_KEY_AUTODETECT: { + IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + try { + sHasPermanentMenuKey = !wm.hasNavigationBar(); + sHasPermanentMenuKeySet = true; + } catch (RemoteException ex) { + sHasPermanentMenuKey = false; + } + } + break; + + case HAS_PERMANENT_MENU_KEY_TRUE: + sHasPermanentMenuKey = true; + sHasPermanentMenuKeySet = true; + break; + + case HAS_PERMANENT_MENU_KEY_FALSE: + sHasPermanentMenuKey = false; + sHasPermanentMenuKeySet = true; + break; } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 0f633a0..5b2a452 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -232,8 +232,6 @@ public final class ViewRootImpl implements ViewParent, InputStage mFirstInputStage; InputStage mFirstPostImeInputStage; - boolean mFlipControllerFallbackKeys; - boolean mWindowAttributesChanged = false; int mWindowAttributesChangesFlag = 0; @@ -370,8 +368,6 @@ public final class ViewRootImpl implements ViewParent, mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context); mChoreographer = Choreographer.getInstance(); - mFlipControllerFallbackKeys = - context.getResources().getBoolean(R.bool.flip_controller_fallback_keys); PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mAttachInfo.mScreenOn = powerManager.isScreenOn(); @@ -674,11 +670,6 @@ public final class ViewRootImpl implements ViewParent, } } - public boolean invokeFunctor(long functor, boolean waitForCompletion) { - // stub - return false; - } - private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { mAttachInfo.mHardwareAccelerated = false; mAttachInfo.mHardwareAccelerationRequested = false; @@ -2917,11 +2908,8 @@ public final class ViewRootImpl implements ViewParent, mView.dispatchConfigurationChanged(config); } } - - mFlipControllerFallbackKeys = - mContext.getResources().getBoolean(R.bool.flip_controller_fallback_keys); } - + /** * Return true if child is an ancestor of parent, (or equal to the parent). */ @@ -3990,7 +3978,6 @@ public final class ViewRootImpl implements ViewParent, private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler(); private final SyntheticTouchNavigationHandler mTouchNavigation = new SyntheticTouchNavigationHandler(); - private final SyntheticKeyHandler mKeys = new SyntheticKeyHandler(); public SyntheticInputStage() { super(null); @@ -4013,12 +4000,7 @@ public final class ViewRootImpl implements ViewParent, mTouchNavigation.process(event); return FINISH_HANDLED; } - } else if (q.mEvent instanceof KeyEvent) { - if (mKeys.process((KeyEvent) q.mEvent)) { - return FINISH_HANDLED; - } } - return FORWARD; } @@ -4848,63 +4830,6 @@ public final class ViewRootImpl implements ViewParent, }; } - final class SyntheticKeyHandler { - - public boolean process(KeyEvent event) { - // In some locales (like Japan) controllers use B for confirm and A for back, rather - // than vice versa, so we need to special case this here since the input system itself - // is not locale-aware. - int keyCode; - switch(event.getKeyCode()) { - case KeyEvent.KEYCODE_BUTTON_A: - case KeyEvent.KEYCODE_BUTTON_C: - case KeyEvent.KEYCODE_BUTTON_X: - case KeyEvent.KEYCODE_BUTTON_Z: - keyCode = mFlipControllerFallbackKeys ? - KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_DPAD_CENTER; - break; - case KeyEvent.KEYCODE_BUTTON_B: - case KeyEvent.KEYCODE_BUTTON_Y: - keyCode = mFlipControllerFallbackKeys ? - KeyEvent.KEYCODE_DPAD_CENTER : KeyEvent.KEYCODE_BACK; - break; - case KeyEvent.KEYCODE_BUTTON_THUMBL: - case KeyEvent.KEYCODE_BUTTON_THUMBR: - case KeyEvent.KEYCODE_BUTTON_START: - case KeyEvent.KEYCODE_BUTTON_1: - case KeyEvent.KEYCODE_BUTTON_2: - case KeyEvent.KEYCODE_BUTTON_3: - case KeyEvent.KEYCODE_BUTTON_4: - case KeyEvent.KEYCODE_BUTTON_5: - case KeyEvent.KEYCODE_BUTTON_6: - case KeyEvent.KEYCODE_BUTTON_7: - case KeyEvent.KEYCODE_BUTTON_8: - case KeyEvent.KEYCODE_BUTTON_9: - case KeyEvent.KEYCODE_BUTTON_10: - case KeyEvent.KEYCODE_BUTTON_11: - case KeyEvent.KEYCODE_BUTTON_12: - case KeyEvent.KEYCODE_BUTTON_13: - case KeyEvent.KEYCODE_BUTTON_14: - case KeyEvent.KEYCODE_BUTTON_15: - case KeyEvent.KEYCODE_BUTTON_16: - keyCode = KeyEvent.KEYCODE_DPAD_CENTER; - break; - case KeyEvent.KEYCODE_BUTTON_SELECT: - case KeyEvent.KEYCODE_BUTTON_MODE: - keyCode = KeyEvent.KEYCODE_MENU; - default: - return false; - } - - enqueueInputEvent(new KeyEvent(event.getDownTime(), event.getEventTime(), - event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(), - event.getDeviceId(), event.getScanCode(), - event.getFlags() | KeyEvent.FLAG_FALLBACK, event.getSource())); - return true; - } - - } - /** * Returns true if the key is used for keyboard navigation. * @param keyEvent The key event. diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index f0e6677..52f9c0b 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -311,7 +311,6 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie lp.type = LayoutParams.TYPE_VOLUME_OVERLAY; lp.width = LayoutParams.WRAP_CONTENT; lp.height = LayoutParams.WRAP_CONTENT; - lp.privateFlags |= LayoutParams.PRIVATE_FLAG_FORCE_SHOW_NAV_BAR; window.setAttributes(lp); window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 0ce4da5..53a4c0d0 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1063,13 +1063,6 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010; /** - * Special flag for the volume overlay: force the window manager out of "hide nav bar" - * mode while the window is on screen. - * - * {@hide} */ - public static final int PRIVATE_FLAG_FORCE_SHOW_NAV_BAR = 0x00000020; - - /** * Never animate position changes of the window. * * {@hide} */ diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 5bc39f1..d53bb74 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -686,6 +686,15 @@ public class WebView extends AbsoluteLayout } /** + * Used only by internal tests to free up memory. + * + * @hide + */ + public static void freeMemoryForTests() { + getFactory().getStatics().freeMemoryForTests(); + } + + /** * Informs WebView of the network state. This is used to set * the JavaScript property window.navigator.isOnline and * generates the online/offline event as specified in HTML5, sec. 5.7.7 diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java index 9d9d882..e391aaf 100644 --- a/core/java/android/webkit/WebViewFactoryProvider.java +++ b/core/java/android/webkit/WebViewFactoryProvider.java @@ -50,6 +50,11 @@ public interface WebViewFactoryProvider { String getDefaultUserAgent(Context context); /** + * Used for tests only. + */ + void freeMemoryForTests(); + + /** * Implements the API method: * {@link android.webkit.WebView#setWebContentsDebuggingEnabled(boolean) } */ diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 092f474..25a43a6 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -723,7 +723,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * * @param view The view whose scroll state is being reported * - * @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE}, + * @param scrollState The current scroll state. One of * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}. */ public void onScrollStateChanged(AbsListView view, int scrollState); @@ -2076,22 +2076,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mInLayout = true; + final int childCount = getChildCount(); if (changed) { - int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { getChildAt(i).forceLayout(); } mRecycler.markChildrenDirty(); } - if (mFastScroller != null && (mItemCount != mOldItemCount || mDataChanged)) { - mFastScroller.onItemCountChanged(mItemCount); - } - layoutChildren(); mInLayout = false; mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR; + + // TODO: Move somewhere sane. This doesn't belong in onLayout(). + if (mFastScroller != null) { + mFastScroller.onItemCountChanged(getChildCount(), mItemCount); + } } /** @@ -2228,26 +2229,34 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te Trace.traceBegin(Trace.TRACE_TAG_VIEW, "obtainView"); isScrap[0] = false; - View scrapView; - scrapView = mRecycler.getTransientStateView(position); - if (scrapView == null) { - scrapView = mRecycler.getScrapView(position); - } + // Check whether we have a transient state view. Attempt to re-bind the + // data and discard the view if we fail. + final View transientView = mRecycler.getTransientStateView(position); + if (transientView != null) { + final LayoutParams params = (LayoutParams) transientView.getLayoutParams(); - View child; - if (scrapView != null) { - child = mAdapter.getView(position, scrapView, this); + // If the view type hasn't changed, attempt to re-bind the data. + if (params.viewType == mAdapter.getItemViewType(position)) { + final View updatedView = mAdapter.getView(position, transientView, this); - if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + // If we failed to re-bind the data, scrap the obtained view. + if (updatedView != transientView) { + mRecycler.addScrapView(updatedView, position); + } } + // Scrap view implies temporary detachment. + isScrap[0] = true; + return transientView; + } + + final View scrapView = mRecycler.getScrapView(position); + final View child = mAdapter.getView(position, scrapView, this); + if (scrapView != null) { if (child != scrapView) { + // Failed to re-bind the data, return scrap to the heap. mRecycler.addScrapView(scrapView, position); - if (mCacheColorHint != 0) { - child.setDrawingCacheBackgroundColor(mCacheColorHint); - } } else { isScrap[0] = true; @@ -2259,16 +2268,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te child.dispatchFinishTemporaryDetach(); } - } else { - child = mAdapter.getView(position, null, this); + } - if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); - } + if (mCacheColorHint != 0) { + child.setDrawingCacheBackgroundColor(mCacheColorHint); + } - if (mCacheColorHint != 0) { - child.setDrawingCacheBackgroundColor(mCacheColorHint); - } + if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } if (mAdapterHasStableIds) { @@ -6562,12 +6569,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } } - if (mTransientStateViews != null) { - mTransientStateViews.clear(); - } - if (mTransientStateViewsById != null) { - mTransientStateViewsById.clear(); - } + + clearTransientStateViews(); } /** @@ -6634,14 +6637,26 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** - * Dump any currently saved views with transient state. + * Dumps and fully detaches any currently saved views with transient + * state. */ void clearTransientStateViews() { - if (mTransientStateViews != null) { - mTransientStateViews.clear(); + final SparseArray<View> viewsByPos = mTransientStateViews; + if (viewsByPos != null) { + final int N = viewsByPos.size(); + for (int i = 0; i < N; i++) { + removeDetachedView(viewsByPos.valueAt(i), false); + } + viewsByPos.clear(); } - if (mTransientStateViewsById != null) { - mTransientStateViewsById.clear(); + + final LongSparseArray<View> viewsById = mTransientStateViewsById; + if (viewsById != null) { + final int N = viewsById.size(); + for (int i = 0; i < N; i++) { + removeDetachedView(viewsById.valueAt(i), false); + } + viewsById.clear(); } } @@ -6766,44 +6781,48 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (victim != null) { final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) victim.getLayoutParams(); - int whichScrap = lp.viewType; + final int whichScrap = lp.viewType; activeViews[i] = null; - final boolean scrapHasTransientState = victim.hasTransientState(); - if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) { - // Do not move views that should be ignored - if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER && - scrapHasTransientState) { + if (victim.hasTransientState()) { + // Store views with transient state for later use. + victim.dispatchStartTemporaryDetach(); + + if (mAdapter != null && mAdapterHasStableIds) { + if (mTransientStateViewsById == null) { + mTransientStateViewsById = new LongSparseArray<View>(); + } + long id = mAdapter.getItemId(mFirstActivePosition + i); + mTransientStateViewsById.put(id, victim); + } else if (!mDataChanged) { + if (mTransientStateViews == null) { + mTransientStateViews = new SparseArray<View>(); + } + mTransientStateViews.put(mFirstActivePosition + i, victim); + } else if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { + // The data has changed, we can't keep this view. removeDetachedView(victim, false); } - if (scrapHasTransientState) { - if (mAdapter != null && mAdapterHasStableIds) { - if (mTransientStateViewsById == null) { - mTransientStateViewsById = new LongSparseArray<View>(); - } - long id = mAdapter.getItemId(mFirstActivePosition + i); - mTransientStateViewsById.put(id, victim); - } else { - if (mTransientStateViews == null) { - mTransientStateViews = new SparseArray<View>(); - } - mTransientStateViews.put(mFirstActivePosition + i, victim); - } + } else if (!shouldRecycleViewType(whichScrap)) { + // Discard non-recyclable views except headers/footers. + if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { + removeDetachedView(victim, false); + } + } else { + // Store everything else on the appropriate scrap heap. + if (multipleScraps) { + scrapViews = mScrapViews[whichScrap]; } - continue; - } - if (multipleScraps) { - scrapViews = mScrapViews[whichScrap]; - } - victim.dispatchStartTemporaryDetach(); - lp.scrappedFromPosition = mFirstActivePosition + i; - scrapViews.add(victim); + victim.dispatchStartTemporaryDetach(); + lp.scrappedFromPosition = mFirstActivePosition + i; + scrapViews.add(victim); - victim.setAccessibilityDelegate(null); - if (hasListener) { - mRecyclerListener.onMovedToScrapHeap(victim); + victim.setAccessibilityDelegate(null); + if (hasListener) { + mRecyclerListener.onMovedToScrapHeap(victim); + } } } } @@ -6812,8 +6831,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** - * Makes sure that the size of mScrapViews does not exceed the size of mActiveViews. - * (This can happen if an adapter does not recycle its views). + * Makes sure that the size of mScrapViews does not exceed the size of + * mActiveViews, which can happen if an adapter does not recycle its + * views. Removes cached transient state views that no longer have + * transient state. */ private void pruneScrapViews() { final int maxViews = mActiveViews.length; @@ -6829,20 +6850,25 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } - if (mTransientStateViews != null) { - for (int i = 0; i < mTransientStateViews.size(); i++) { - final View v = mTransientStateViews.valueAt(i); + final SparseArray<View> transViewsByPos = mTransientStateViews; + if (transViewsByPos != null) { + for (int i = 0; i < transViewsByPos.size(); i++) { + final View v = transViewsByPos.valueAt(i); if (!v.hasTransientState()) { - mTransientStateViews.removeAt(i); + removeDetachedView(v, false); + transViewsByPos.removeAt(i); i--; } } } - if (mTransientStateViewsById != null) { - for (int i = 0; i < mTransientStateViewsById.size(); i++) { - final View v = mTransientStateViewsById.valueAt(i); + + final LongSparseArray<View> transViewsById = mTransientStateViewsById; + if (transViewsById != null) { + for (int i = 0; i < transViewsById.size(); i++) { + final View v = transViewsById.valueAt(i); if (!v.hasTransientState()) { - mTransientStateViewsById.removeAt(i); + removeDetachedView(v, false); + transViewsById.removeAt(i); i--; } } diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index 0957ab4..e90b460 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -1210,35 +1210,38 @@ public class CalendarView extends FrameLayout { child = (WeekView) view.getChildAt(offset); } - // Find out which month we're moving into - int month; - if (mIsScrollingUp) { - month = child.getMonthOfFirstWeekDay(); - } else { - month = child.getMonthOfLastWeekDay(); - } - - // And how it relates to our current highlighted month - int monthDiff; - if (mCurrentMonthDisplayed == 11 && month == 0) { - monthDiff = 1; - } else if (mCurrentMonthDisplayed == 0 && month == 11) { - monthDiff = -1; - } else { - monthDiff = month - mCurrentMonthDisplayed; - } - - // Only switch months if we're scrolling away from the currently - // selected month - if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) { - Calendar firstDay = child.getFirstDay(); + if (child != null) { + // Find out which month we're moving into + int month; if (mIsScrollingUp) { - firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK); + month = child.getMonthOfFirstWeekDay(); } else { - firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK); + month = child.getMonthOfLastWeekDay(); + } + + // And how it relates to our current highlighted month + int monthDiff; + if (mCurrentMonthDisplayed == 11 && month == 0) { + monthDiff = 1; + } else if (mCurrentMonthDisplayed == 0 && month == 11) { + monthDiff = -1; + } else { + monthDiff = month - mCurrentMonthDisplayed; + } + + // Only switch months if we're scrolling away from the currently + // selected month + if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) { + Calendar firstDay = child.getFirstDay(); + if (mIsScrollingUp) { + firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK); + } else { + firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK); + } + setMonthDisplayed(firstDay); } - setMonthDisplayed(firstDay); } + mPreviousScrollPosition = currScroll; mPreviousScrollState = mCurrentScrollState; } diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java index 01ac8fd..4379bf6 100644 --- a/core/java/android/widget/FastScroller.java +++ b/core/java/android/widget/FastScroller.java @@ -224,6 +224,8 @@ class FastScroller { mHasPendingDrag = false; } }; + private int mOldItemCount; + private int mOldChildCount; /** * Used to delay hiding fast scroll decorations. @@ -248,6 +250,8 @@ class FastScroller { public FastScroller(AbsListView listView) { mList = listView; mOverlay = listView.getOverlay(); + mOldItemCount = listView.getCount(); + mOldChildCount = listView.getChildCount(); final Context context = listView.getContext(); mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); @@ -258,6 +262,7 @@ class FastScroller { final ImageView trackImage = new ImageView(context); mTrackImage = trackImage; + updateLongList(mOldChildCount, mOldItemCount); int width = 0; // Add track to overlay if it has an image. @@ -445,20 +450,23 @@ class FastScroller { updateLayout(); } - public void onItemCountChanged(int totalItemCount) { - final int visibleItemCount = mList.getChildCount(); - final boolean hasMoreItems = totalItemCount - visibleItemCount > 0; - if (hasMoreItems && mState != STATE_DRAGGING) { - final int firstVisibleItem = mList.getFirstVisiblePosition(); - setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount)); - } + public void onItemCountChanged(int childCount, int itemCount) { + if (mOldItemCount != itemCount || mOldChildCount != childCount) { + mOldItemCount = itemCount; + mOldChildCount = childCount; - updateLongList(visibleItemCount, totalItemCount); + final boolean hasMoreItems = itemCount - childCount > 0; + if (hasMoreItems && mState != STATE_DRAGGING) { + final int firstVisibleItem = mList.getFirstVisiblePosition(); + setThumbPos(getPosFromItemCount(firstVisibleItem, childCount, itemCount)); + } + + updateLongList(childCount, itemCount); + } } - private void updateLongList(int visibleItemCount, int totalItemCount) { - final boolean longList = visibleItemCount > 0 - && totalItemCount / visibleItemCount >= MIN_PAGES; + private void updateLongList(int childCount, int itemCount) { + final boolean longList = childCount > 0 && itemCount / childCount >= MIN_PAGES; if (mLongList != longList) { mLongList = longList; diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 7daf798..f05179b 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -563,7 +563,7 @@ public class ImageView extends View { } /** Return the view's optional matrix. This is applied to the - view's drawable when it is drawn. If there is not matrix, + view's drawable when it is drawn. If there is no matrix, this method will return an identity matrix. Do not change this matrix in place but make a copy. If you want a different matrix applied to the drawable, diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 5663959..be20d2d 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1330,7 +1330,7 @@ public class PopupWindow { /** * Updates the state of the popup window, if it is currently being displayed, - * from the currently set state. This include: + * from the currently set state. This includes: * {@link #setClippingEnabled(boolean)}, {@link #setFocusable(boolean)}, * {@link #setIgnoreCheekPress()}, {@link #setInputMethodMode(int)}, * {@link #setTouchable(boolean)}, and {@link #setAnimationStyle(int)}. diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 5392a96..6a369a6 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -308,6 +308,11 @@ public class ProgressBar extends View { mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl); a.recycle(); + + // If not explicitly specified this view is important for accessibility. + if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); + } } /** diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java index 62afd2e..bdaaa01 100644 --- a/core/java/android/widget/ShareActionProvider.java +++ b/core/java/android/widget/ShareActionProvider.java @@ -266,7 +266,7 @@ public class ShareActionProvider extends ActionProvider { * Intent shareIntent = new Intent(Intent.ACTION_SEND); * shareIntent.setType("image/*"); * Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg")); - * shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());</pre> + * shareIntent.putExtra(Intent.EXTRA_STREAM, uri));</pre> * * @param shareIntent The share intent. * diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index b204dfd..1cda631 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -731,10 +731,14 @@ public class SpellChecker implements SpellCheckerSessionListener { } } - if (scheduleOtherSpellCheck) { + if (scheduleOtherSpellCheck && wordStart <= end) { // Update range span: start new spell check from last wordStart setRangeSpan(editable, wordStart, end); } else { + if (DBG && scheduleOtherSpellCheck) { + Log.w(TAG, "Trying to schedule spellcheck for invalid region, from " + + wordStart + " to " + end); + } removeRangeSpan(editable); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 3f35875..5ece016 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8667,6 +8667,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener super.onRtlPropertiesChanged(layoutDirection); mTextDir = getTextDirectionHeuristic(); + + if (mLayout != null) { + checkForRelayout(); + } } TextDirectionHeuristic getTextDirectionHeuristic() { diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index a87992a..a13a1cb 100644 --- a/core/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -1004,7 +1004,7 @@ public final class ProcessStats implements Parcelable { for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) { ProcessState ps = pkgState.mProcesses.valueAt(iproc); if (ps.isInUse() || ps.mCommonProcess.isInUse()) { - pkgState.mProcesses.valueAt(iproc).resetSafely(now); + ps.resetSafely(now); } else { pkgState.mProcesses.valueAt(iproc).makeDead(); pkgState.mProcesses.removeAt(iproc); @@ -1013,7 +1013,7 @@ public final class ProcessStats implements Parcelable { for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) { ServiceState ss = pkgState.mServices.valueAt(isvc); if (ss.isInUse()) { - pkgState.mServices.valueAt(isvc).resetSafely(now); + ss.resetSafely(now); } else { pkgState.mServices.removeAt(isvc); } @@ -3014,7 +3014,7 @@ public final class ProcessStats implements Parcelable { } public boolean isInUse() { - return mOwner != null; + return mOwner != null || mRestarting; } void add(ServiceState other) { diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java index ab871fb..942995b 100644 --- a/core/java/com/android/internal/content/PackageMonitor.java +++ b/core/java/com/android/internal/content/PackageMonitor.java @@ -372,23 +372,25 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); mAppearingPackages = pkgList; - mChangeType = PACKAGE_TEMPORARY_CHANGE; + mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) + ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE; mSomePackagesChanged = true; if (pkgList != null) { onPackagesAvailable(pkgList); for (int i=0; i<pkgList.length; i++) { - onPackageAppeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE); + onPackageAppeared(pkgList[i], mChangeType); } } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); mDisappearingPackages = pkgList; - mChangeType = PACKAGE_TEMPORARY_CHANGE; + mChangeType = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false) + ? PACKAGE_UPDATING : PACKAGE_TEMPORARY_CHANGE; mSomePackagesChanged = true; if (pkgList != null) { onPackagesUnavailable(pkgList); for (int i=0; i<pkgList.length; i++) { - onPackageDisappeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE); + onPackageDisappeared(pkgList[i], mChangeType); } } } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index bee1391..3ea749e 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -28,6 +28,7 @@ import android.os.Process; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; +import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.util.EventLog; @@ -192,10 +193,16 @@ public class ZygoteInit { static void closeServerSocket() { try { if (sServerSocket != null) { + FileDescriptor fd = sServerSocket.getFileDescriptor(); sServerSocket.close(); + if (fd != null) { + Os.close(fd); + } } } catch (IOException ex) { Log.e(TAG, "Zygote: error closing sockets", ex); + } catch (ErrnoException ex) { + Log.e(TAG, "Zygote: error closing descriptor", ex); } sServerSocket = null; @@ -238,9 +245,11 @@ public class ZygoteInit { } static void preload() { + Log.d(TAG, "begin preload"); preloadClasses(); preloadResources(); preloadOpenGL(); + Log.d(TAG, "end preload"); } private static void preloadOpenGL() { diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 12ced68..3724a08 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -73,5 +73,5 @@ interface IInputMethodManager { boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme); boolean shouldOfferSwitchingToNextInputMethod(in IBinder token); boolean setInputMethodEnabled(String id, boolean enabled); - oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes); + void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes); } diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index 4654178..fe1cf72 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -164,8 +164,24 @@ public class ActionMenuPresenter extends BaseMenuPresenter } actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE); + final ActionMenuView menuParent = (ActionMenuView) parent; + final ViewGroup.LayoutParams lp = actionView.getLayoutParams(); + if (!menuParent.checkLayoutParams(lp)) { + actionView.setLayoutParams(menuParent.generateLayoutParams(lp)); + } + return actionView; + } + + @Override + public void bindItemView(final MenuItemImpl item, MenuView.ItemView itemView) { + itemView.initialize(item, 0); + + final ActionMenuView menuView = (ActionMenuView) mMenuView; + final ActionMenuItemView actionItemView = (ActionMenuItemView) itemView; + actionItemView.setItemInvoker(menuView); + if (item.hasSubMenu()) { - actionView.setOnTouchListener(new ForwardingListener(actionView) { + actionItemView.setOnTouchListener(new ForwardingListener(actionItemView) { @Override public ListPopupWindow getPopup() { return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null; @@ -182,24 +198,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter } }); } else { - actionView.setOnTouchListener(null); + actionItemView.setOnTouchListener(null); } - - final ActionMenuView menuParent = (ActionMenuView) parent; - final ViewGroup.LayoutParams lp = actionView.getLayoutParams(); - if (!menuParent.checkLayoutParams(lp)) { - actionView.setLayoutParams(menuParent.generateLayoutParams(lp)); - } - return actionView; - } - - @Override - public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) { - itemView.initialize(item, 0); - - final ActionMenuView menuView = (ActionMenuView) mMenuView; - ActionMenuItemView actionItemView = (ActionMenuItemView) itemView; - actionItemView.setItemInvoker(menuView); } @Override diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java index 4882adc..e1bb3621 100644 --- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java @@ -163,7 +163,7 @@ public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClick @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - mMenu.performItemAction(mAdapter.getItem(position), 0); + mMenu.performItemAction(mAdapter.getItem(position), this, 0); } @Override diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index aff697a..195a00d 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -247,11 +247,17 @@ public class MenuBuilder implements Menu { startDispatchingItemsChanged(); } - private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) { + private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu, + MenuPresenter preferredPresenter) { if (mPresenters.isEmpty()) return false; boolean result = false; + // Try the preferred presenter first. + if (preferredPresenter != null) { + result = preferredPresenter.onSubMenuSelected(subMenu); + } + for (WeakReference<MenuPresenter> ref : mPresenters) { final MenuPresenter presenter = ref.get(); if (presenter == null) { @@ -865,6 +871,10 @@ public class MenuBuilder implements Menu { } public boolean performItemAction(MenuItem item, int flags) { + return performItemAction(item, null, flags); + } + + public boolean performItemAction(MenuItem item, MenuPresenter preferredPresenter, int flags) { MenuItemImpl itemImpl = (MenuItemImpl) item; if (itemImpl == null || !itemImpl.isEnabled()) { @@ -889,7 +899,7 @@ public class MenuBuilder implements Menu { if (providerHasSubMenu) { provider.onPrepareSubMenu(subMenu); } - invoked |= dispatchSubMenuSelected(subMenu); + invoked |= dispatchSubMenuSelected(subMenu, preferredPresenter); if (!invoked) close(true); } else { if ((flags & FLAG_PERFORM_NO_CLOSE) == 0) { diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 7143a8a..d97a945 100644 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -227,7 +227,7 @@ static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width, do {
*dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
} while (--width != 0);
- ctable->unlockColors(false);
+ ctable->unlockColors();
}
static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
@@ -240,7 +240,7 @@ static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width, *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
SkGetPackedG32(c), SkGetPackedB32(c));
} while (--width != 0);
- ctable->unlockColors(false);
+ ctable->unlockColors();
}
static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
@@ -253,7 +253,7 @@ static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width, *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
SkGetPackedB32(c));
} while (--width != 0);
- ctable->unlockColors(false);
+ ctable->unlockColors();
}
// can return NULL
@@ -456,10 +456,16 @@ static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) { return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
}
-static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
- jboolean hasAlpha) {
+static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
+ jboolean hasAlpha, jboolean isPremul) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- bitmap->setIsOpaque(!hasAlpha);
+ if (!hasAlpha) {
+ bitmap->setAlphaType(kOpaque_SkAlphaType);
+ } else if (isPremul) {
+ bitmap->setAlphaType(kPremul_SkAlphaType);
+ } else {
+ bitmap->setAlphaType(kUnpremul_SkAlphaType);
+ }
}
static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -561,14 +567,14 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, p->writeInt32(bitmap->rowBytes());
p->writeInt32(density);
- if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {
+ if (bitmap->config() == SkBitmap::kIndex8_Config) {
SkColorTable* ctable = bitmap->getColorTable();
if (ctable != NULL) {
int count = ctable->count();
p->writeInt32(count);
memcpy(p->writeInplace(count * sizeof(SkPMColor)),
ctable->lockColors(), count * sizeof(SkPMColor));
- ctable->unlockColors(false);
+ ctable->unlockColors();
} else {
p->writeInt32(0); // indicate no ctable
}
@@ -800,7 +806,7 @@ static JNINativeMethod gBitmapMethods[] = { { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
{ "nativeConfig", "(J)I", (void*)Bitmap_config },
{ "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
- { "nativeSetHasAlpha", "(JZ)V", (void*)Bitmap_setHasAlpha },
+ { "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
{ "nativeHasMipMap", "(J)Z", (void*)Bitmap_hasMipMap },
{ "nativeSetHasMipMap", "(JZ)V", (void*)Bitmap_setHasMipMap },
{ "nativeCreateFromParcel",
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 44bf7f8..2b9a5c4 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -21,6 +21,7 @@ #include <androidfw/Asset.h> #include <androidfw/ResourceTypes.h> #include <netinet/in.h> +#include <stdio.h> #include <sys/mman.h> #include <sys/stat.h> @@ -126,12 +127,18 @@ static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale) { static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream, int sampleSize, bool ditherImage) { + SkImageInfo bitmapInfo; + if (!bitmap->asImageInfo(&bitmapInfo)) { + ALOGW("bitmap has unknown configuration so no memory has been allocated"); + return NULL; + } + SkImageRef* pr; // only use ashmem for large images, since mmaps come at a price if (bitmap->getSize() >= 32 * 1024) { - pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize); + pr = new SkImageRef_ashmem(bitmapInfo, stream, sampleSize); } else { - pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize); + pr = new SkImageRef_GlobalPool(bitmapInfo, stream, sampleSize); } pr->setDitherImage(ditherImage); bitmap->setPixelRef(pr)->unref(); @@ -159,7 +166,7 @@ public: virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { // accounts for scale in final allocation, using eventual size and config const int bytesPerPixel = SkBitmap::ComputeBytesPerPixel( - configForScaledOutput(bitmap->getConfig())); + configForScaledOutput(bitmap->config())); const int requestedSize = bytesPerPixel * int(bitmap->width() * mScale + 0.5f) * int(bitmap->height() * mScale + 0.5f); @@ -193,8 +200,15 @@ public: return false; } + SkImageInfo bitmapInfo; + if (!bitmap->asImageInfo(&bitmapInfo)) { + ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration"); + return false; + } + // Create a new pixelref with the new ctable that wraps the previous pixelref - SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef), ctable); + SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef), + bitmapInfo, bitmap->rowBytes(), ctable); bitmap->setPixelRef(pr)->unref(); // since we're already allocated, we lockPixels right away @@ -403,8 +417,11 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding // TODO: avoid copying when scaled size equals decodingBitmap size SkBitmap::Config config = configForScaledOutput(decodingBitmap.config()); - outputBitmap->setConfig(config, scaledWidth, scaledHeight); - outputBitmap->setIsOpaque(decodingBitmap.isOpaque()); + // FIXME: If the alphaType is kUnpremul and the image has alpha, the + // colors may not be correct, since Skia does not yet support drawing + // to/from unpremultiplied bitmaps. + outputBitmap->setConfig(config, scaledWidth, scaledHeight, 0, + decodingBitmap.alphaType()); if (!outputBitmap->allocPixels(outputAllocator, NULL)) { return nullObjectReturn("allocation failed for scaled bitmap"); } @@ -416,7 +433,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding } SkPaint paint; - paint.setFilterBitmap(true); + paint.setFilterLevel(SkPaint::kLow_FilterLevel); SkCanvas canvas(*outputBitmap); canvas.scale(sx, sy); @@ -472,6 +489,12 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding bitmapCreateFlags, ninePatchChunk, layoutBounds, -1); } +// Need to buffer enough input to be able to rewind as much as might be read by a decoder +// trying to determine the stream's format. Currently the most is 64, read by +// SkImageDecoder_libwebp. +// FIXME: Get this number from SkImageDecoder +#define BYTES_TO_BUFFER 64 + static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage, jobject padding, jobject options) { @@ -479,11 +502,8 @@ static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteA SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage)); if (stream.get()) { - // Need to buffer enough input to be able to rewind as much as might be read by a decoder - // trying to determine the stream's format. Currently the most is 64, read by - // SkImageDecoder_libwebp. - // FIXME: Get this number from SkImageDecoder - SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64)); + SkAutoTUnref<SkStreamRewindable> bufferedStream( + SkFrontBufferedStream::Create(stream, BYTES_TO_BUFFER)); SkASSERT(bufferedStream.get() != NULL); // for now we don't allow purgeable with java inputstreams bitmap = doDecode(env, bufferedStream, padding, options, false, false); @@ -504,27 +524,48 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi return nullObjectReturn("fstat return -1"); } - bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions); - bool isShareable = optionsShareable(env, bitmapFactoryOptions); - bool weOwnTheFD = false; - if (isPurgeable && isShareable) { - int newFD = ::dup(descriptor); - if (-1 != newFD) { - weOwnTheFD = true; - descriptor = newFD; - } + // Restore the descriptor's offset on exiting this function. + AutoFDSeek autoRestore(descriptor); + + FILE* file = fdopen(descriptor, "r"); + if (file == NULL) { + return nullObjectReturn("Could not open file"); } - SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor)); - if (data.get() == NULL) { - return nullObjectReturn("NewFromFD failed in nativeDecodeFileDescriptor"); + SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file, + SkFILEStream::kCallerRetains_Ownership)); + + SkAutoTUnref<SkStreamRewindable> stream; + + // Retain the old behavior of allowing purgeable if both purgeable and + // shareable are set to true. + bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions) + && optionsShareable(env, bitmapFactoryOptions); + if (isPurgeable) { + // Copy the stream, so the image can be decoded multiple times without + // continuing to modify the original file descriptor. + // Copy beginning from the current position. + const size_t fileSize = fileStream->getLength() - fileStream->getPosition(); + void* buffer = sk_malloc_flags(fileSize, 0); + if (buffer == NULL) { + return nullObjectReturn("Could not make a copy for ashmem"); + } + + SkAutoTUnref<SkData> data(SkData::NewFromMalloc(buffer, fileSize)); + + if (fileStream->read(buffer, fileSize) != fileSize) { + return nullObjectReturn("Could not read the file."); + } + + stream.reset(new SkMemoryStream(data)); + } else { + // Use a buffered stream. Although an SkFILEStream can be rewound, this + // ensures that SkImageDecoder::Factory never rewinds beyond the + // current position of the file descriptor. + stream.reset(SkFrontBufferedStream::Create(fileStream, BYTES_TO_BUFFER)); } - SkAutoTUnref<SkMemoryStream> stream(new SkMemoryStream(data)); - /* Allow purgeable iff we own the FD, i.e., in the puregeable and - shareable case. - */ - return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD); + return doDecode(env, stream, padding, bitmapFactoryOptions, isPurgeable); } static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset, @@ -543,7 +584,9 @@ static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset, } else { // since we know we'll be done with the asset when we return, we can // just use a simple wrapper - stream = new AssetStreamAdaptor(asset); + stream = new AssetStreamAdaptor(asset, + AssetStreamAdaptor::kNo_OwnAsset, + AssetStreamAdaptor::kNo_HasMemoryBase); } SkAutoUnref aur(stream); return doDecode(env, stream, padding, options, forcePurgeable, forcePurgeable); diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index e7d2422..0d67b07 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -29,7 +29,6 @@ #include "CreateJavaOutputStreamAdaptor.h" #include "Utils.h" #include "JNIHelp.h" -#include "SkTScopedPtr.h" #include <android_runtime/AndroidRuntime.h> #include "android_util_Binder.h" @@ -76,7 +75,7 @@ private: int fHeight; }; -static jobject createBitmapRegionDecoder(JNIEnv* env, SkStream* stream) { +static jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) { SkImageDecoder* decoder = SkImageDecoder::Factory(stream); int width, height; if (NULL == decoder) { @@ -108,7 +107,7 @@ static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray b For now we just always copy the array's data if isShareable. */ AutoJavaByteArray ar(env, byteArray); - SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true); + SkStreamRewindable* stream = new SkMemoryStream(ar.ptr() + offset, length, true); jobject brd = createBitmapRegionDecoder(env, stream); SkSafeUnref(stream); // the decoder now holds a reference @@ -216,7 +215,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, region.fRight = start_x + width; region.fBottom = start_y + height; SkBitmap* bitmap = NULL; - SkTScopedPtr<SkBitmap> adb; + SkAutoTDelete<SkBitmap> adb; if (tileBitmap != NULL) { // Re-use bitmap. @@ -247,7 +246,7 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, } // detach bitmap from its autodeleter, since we want to own it now - adb.release(); + adb.detach(); JavaPixelAllocator* allocator = (JavaPixelAllocator*) decoder->getAllocator(); jbyteArray buff = allocator->getStorageObjAndReset(); diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 11089da..f6ab39c 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -549,7 +549,7 @@ public: if (paint) { filteredPaint = *paint; } - filteredPaint.setFilterBitmap(true); + filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint); } else { canvas->drawBitmap(*bitmap, left_, top_, paint); @@ -564,7 +564,7 @@ public: if (paint) { filteredPaint = *paint; } - filteredPaint.setFilterBitmap(true); + filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); @@ -587,7 +587,7 @@ public: if (paint) { filteredPaint = *paint; } - filteredPaint.setFilterBitmap(true); + filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel); canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint); } else { canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 2f4fd29..5d951ca 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -357,6 +357,18 @@ SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region) /////////////////////////////////////////////////////////////////////////////////////////// +// Assert that bitmap's SkAlphaType is consistent with isPremultiplied. +static void assert_premultiplied(const SkBitmap& bitmap, bool isPremultiplied) { + // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is + // irrelevant. This just tests to ensure that the SkAlphaType is not + // opposite of isPremultiplied. + if (isPremultiplied) { + SkASSERT(bitmap.alphaType() != kUnpremul_SkAlphaType); + } else { + SkASSERT(bitmap.alphaType() != kPremul_SkAlphaType); + } +} + jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer, int bitmapCreateFlags, jbyteArray ninepatch, jintArray layoutbounds, int density) { @@ -365,6 +377,10 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buff bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable; bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied; + // The caller needs to have already set the alpha type properly, so the + // native SkBitmap stays in sync with the Java Bitmap. + assert_premultiplied(*bitmap, isPremultiplied); + jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID, reinterpret_cast<jlong>(bitmap), buffer, bitmap->width(), bitmap->height(), density, isMutable, isPremultiplied, @@ -382,6 +398,10 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, int bitmapCreat void GraphicsJNI::reinitBitmap(JNIEnv* env, jobject javaBitmap, SkBitmap* bitmap, bool isPremultiplied) { + // The caller needs to have already set the alpha type properly, so the + // native SkBitmap stays in sync with the Java Bitmap. + assert_premultiplied(*bitmap, isPremultiplied); + env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID, bitmap->width(), bitmap->height(), isPremultiplied); } @@ -424,8 +444,9 @@ static JNIEnv* vm2env(JavaVM* vm) /////////////////////////////////////////////////////////////////////////////// -AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj, - SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable, (storageObj == NULL)), +AndroidPixelRef::AndroidPixelRef(JNIEnv* env, const SkImageInfo& info, void* storage, + size_t rowBytes, jbyteArray storageObj, SkColorTable* ctable) : + SkMallocPixelRef(info, storage, rowBytes, ctable, (storageObj == NULL)), fWrappedPixelRef(NULL) { SkASSERT(storage); SkASSERT(env); @@ -440,13 +461,13 @@ AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteA // If storageObj is NULL, the memory was NOT allocated on the Java heap fOnJavaHeap = (storageObj != NULL); - } -AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable) : - SkMallocPixelRef(wrappedPixelRef.getAddr(), wrappedPixelRef.getSize(), ctable, false), +AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, const SkImageInfo& info, + size_t rowBytes, SkColorTable* ctable) : + SkMallocPixelRef(info, wrappedPixelRef.getAddr(), rowBytes, ctable, false), fWrappedPixelRef(wrappedPixelRef.fWrappedPixelRef ? - wrappedPixelRef.fWrappedPixelRef : &wrappedPixelRef) + wrappedPixelRef.fWrappedPixelRef : &wrappedPixelRef) { SkASSERT(fWrappedPixelRef); SkSafeRef(fWrappedPixelRef); @@ -548,6 +569,14 @@ jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, "bitmap size exceeds 32bits"); return NULL; } + + SkImageInfo bitmapInfo; + if (!bitmap->asImageInfo(&bitmapInfo)) { + jniThrowException(env, "java/lang/IllegalArgumentException", + "unknown bitmap configuration"); + return NULL; + } + size_t size = size64.get32(); jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime, gVMRuntime_newNonMovableArray, @@ -561,7 +590,8 @@ jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap, return NULL; } SkASSERT(addr); - SkPixelRef* pr = new AndroidPixelRef(env, (void*) addr, size, arrayObj, ctable); + SkPixelRef* pr = new AndroidPixelRef(env, bitmapInfo, (void*) addr, + bitmap->rowBytes(), arrayObj, ctable); bitmap->setPixelRef(pr)->unref(); // since we're already allocated, we lockPixels right away // HeapAllocator behaves this way too diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index f4590b9..cb154aa 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -57,6 +57,7 @@ public: /** Create a java Bitmap object given the native bitmap (required) and optional storage array (may be null). + bitmap's SkAlphaType must already be in sync with bitmapCreateFlags. */ static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer, int bitmapCreateFlags, jbyteArray ninepatch, jintArray layoutbounds, int density = -1); @@ -64,6 +65,9 @@ public: static jobject createBitmap(JNIEnv* env, SkBitmap* bitmap, int bitmapCreateFlags, jbyteArray ninepatch, int density = -1); + /** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in + sync with isPremultiplied + */ static void reinitBitmap(JNIEnv* env, jobject javaBitmap, SkBitmap* bitmap, bool isPremultiplied); @@ -88,15 +92,16 @@ public: class AndroidPixelRef : public SkMallocPixelRef { public: - AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj, - SkColorTable* ctable); + AndroidPixelRef(JNIEnv* env, const SkImageInfo& info, void* storage, size_t rowBytes, + jbyteArray storageObj, SkColorTable* ctable); /** * Creates an AndroidPixelRef that wraps (and refs) another to reuse/share * the same storage and java byte array refcounting, yet have a different * color table. */ - AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable); + AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, const SkImageInfo& info, + size_t rowBytes, SkColorTable* ctable); virtual ~AndroidPixelRef(); diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp index 0040b6f..461f723 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -85,7 +85,9 @@ static void movie_draw(JNIEnv* env, jobject movie, jobject canvas, static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) { android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset); if (asset == NULL) return NULL; - SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset)); + SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset, + android::AssetStreamAdaptor::kNo_OwnAsset, + android::AssetStreamAdaptor::kNo_HasMemoryBase)); SkMovie* moov = SkMovie::DecodeStream(stream.get()); return create_jmovie(env, moov); } diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/core/jni/android/graphics/NinePatchPeeker.cpp index 51392ab..5daa1ad 100644 --- a/core/jni/android/graphics/NinePatchPeeker.cpp +++ b/core/jni/android/graphics/NinePatchPeeker.cpp @@ -40,15 +40,14 @@ bool NinePatchPeeker::peek(const char tag[], const void* data, size_t length) { // now update our host to force index or 32bit config // 'cause we don't want 565 predithered, since as a 9patch, we know // we will be stretched, and therefore we want to dither afterwards. - static const SkBitmap::Config gNo565Pref[] = { - SkBitmap::kIndex8_Config, - SkBitmap::kIndex8_Config, - SkBitmap::kARGB_8888_Config, - SkBitmap::kARGB_8888_Config, - SkBitmap::kARGB_8888_Config, - SkBitmap::kARGB_8888_Config, - }; - fHost->setPrefConfigTable(gNo565Pref); + SkImageDecoder::PrefConfigTable table; + table.fPrefFor_8Index_NoAlpha_src = SkBitmap::kIndex8_Config; + table.fPrefFor_8Index_YesAlpha_src = SkBitmap::kIndex8_Config; + table.fPrefFor_8Gray_src = SkBitmap::kARGB_8888_Config; + table.fPrefFor_8bpc_NoAlpha_src = SkBitmap::kARGB_8888_Config; + table.fPrefFor_8bpc_YesAlpha_src = SkBitmap::kARGB_8888_Config; + + fHost->setPrefConfigTable(table); } else if (strcmp("npLb", tag) == 0 && length == sizeof(int) * 4) { fLayoutBounds = new int[4]; memcpy(fLayoutBounds, data, sizeof(int) * 4); diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 2523481..dc97c22 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -155,7 +155,8 @@ public: static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) { NPE_CHECK_RETURN_VOID(env, paint); - GraphicsJNI::getNativePaint(env, paint)->setFilterBitmap(filterBitmap); + GraphicsJNI::getNativePaint(env, paint)->setFilterLevel( + filterBitmap ? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel); } static void setDither(JNIEnv* env, jobject paint, jboolean dither) { @@ -609,7 +610,7 @@ public: return 0; } } - jfloat advancesArray[count]; + jfloat* advancesArray = new jfloat[count]; jfloat totalAdvance = 0; TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags, @@ -618,6 +619,7 @@ public: if (advances != NULL) { env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray); } + delete [] advancesArray; return totalAdvance; } diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index bcf1273..912968a 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -214,7 +214,7 @@ static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) SkRegion* region = new SkRegion; size_t size = p->readInt32(); - region->readFromMemory(p->readInplace(size)); + region->readFromMemory(p->readInplace(size), size); return reinterpret_cast<jlong>(region); } diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp index e2c78b1..5db083a 100644 --- a/core/jni/android/graphics/TextLayoutCache.cpp +++ b/core/jni/android/graphics/TextLayoutCache.cpp @@ -20,6 +20,7 @@ #include "TextLayoutCache.h" #include "TextLayout.h" +#include "SkGlyphCache.h" #include "SkTypeface_android.h" #include "HarfBuzzNGFaceSkia.h" #include <unicode/unistr.h> @@ -757,8 +758,8 @@ void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* conte outPos->add(ypos); totalAdvance += xAdvance; - // TODO: consider using glyph cache - const SkGlyph& metrics = mShapingPaint.getGlyphMetrics(glyphId, NULL); + SkAutoGlyphCache autoCache(mShapingPaint, NULL, NULL); + const SkGlyph& metrics = autoCache.getCache()->getGlyphIDMetrics(glyphId); outBounds->join(xpos + metrics.fLeft, ypos + metrics.fTop, xpos + metrics.fLeft + metrics.fWidth, ypos + metrics.fTop + metrics.fHeight); diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index d096c2a..8164625 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -4,6 +4,7 @@ #include "GraphicsJNI.h" #include "SkStream.h" #include "SkTypeface.h" +#include "Utils.h" #include <android_runtime/android_util_AssetManager.h> #include <androidfw/AssetManager.h> @@ -77,65 +78,6 @@ static jint Typeface_getStyle(JNIEnv* env, jobject obj, jlong faceHandle) { return static_cast<jint>(face->style()); } -class AssetStream : public SkStream { -public: - AssetStream(Asset* asset, bool hasMemoryBase) : fAsset(asset) - { - fMemoryBase = hasMemoryBase ? fAsset->getBuffer(false) : NULL; - } - - virtual ~AssetStream() - { - delete fAsset; - } - - virtual const void* getMemoryBase() - { - return fMemoryBase; - } - - virtual bool rewind() - { - off64_t pos = fAsset->seek(0, SEEK_SET); - return pos != (off64_t)-1; - } - - virtual size_t read(void* buffer, size_t size) - { - ssize_t amount; - - if (NULL == buffer) - { - if (0 == size) // caller is asking us for our total length - return fAsset->getLength(); - - // asset->seek returns new total offset - // we want to return amount that was skipped - - off64_t oldOffset = fAsset->seek(0, SEEK_CUR); - if (-1 == oldOffset) - return 0; - off64_t newOffset = fAsset->seek(size, SEEK_CUR); - if (-1 == newOffset) - return 0; - - amount = newOffset - oldOffset; - } - else - { - amount = fAsset->read(buffer, size); - } - - if (amount < 0) - amount = 0; - return amount; - } - -private: - Asset* fAsset; - const void* fMemoryBase; -}; - static jlong Typeface_createFromAsset(JNIEnv* env, jobject, jobject jassetMgr, jstring jpath) { @@ -154,7 +96,9 @@ static jlong Typeface_createFromAsset(JNIEnv* env, jobject, return NULL; } - SkStream* stream = new AssetStream(asset, true); + SkStream* stream = new AssetStreamAdaptor(asset, + AssetStreamAdaptor::kYes_OwnAsset, + AssetStreamAdaptor::kYes_HasMemoryBase); SkTypeface* face = SkTypeface::CreateFromStream(stream); // SkTypeFace::CreateFromStream calls ref() on the stream, so we // need to unref it here or it won't be freed later on diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp index b7d1f3a..eb416cb 100644 --- a/core/jni/android/graphics/Utils.cpp +++ b/core/jni/android/graphics/Utils.cpp @@ -19,6 +19,21 @@ using namespace android; +AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset, OwnAsset ownAsset, + HasMemoryBase hasMemoryBase) + : fAsset(asset) + , fMemoryBase(kYes_HasMemoryBase == hasMemoryBase ? + asset->getBuffer(false) : NULL) + , fOwnAsset(ownAsset) +{ +} + +AssetStreamAdaptor::~AssetStreamAdaptor() { + if (kYes_OwnAsset == fOwnAsset) { + delete fAsset; + } +} + bool AssetStreamAdaptor::rewind() { off64_t pos = fAsset->seek(0, SEEK_SET); if (pos == (off64_t)-1) { diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h index a1ac72a..b90593c 100644 --- a/core/jni/android/graphics/Utils.h +++ b/core/jni/android/graphics/Utils.h @@ -28,16 +28,36 @@ namespace android { class AssetStreamAdaptor : public SkStreamRewindable { public: - AssetStreamAdaptor(Asset* a) : fAsset(a) {} + // Enum passed to constructor. If set to kYes_OwnAsset, + // the passed in Asset will be deleted upon destruction. + enum OwnAsset { + kYes_OwnAsset, + kNo_OwnAsset, + }; + + // Enum passed to constructor. If set to kYes_HasMemoryBase, + // getMemoryBase will return the Asset's buffer. + enum HasMemoryBase { + kYes_HasMemoryBase, + kNo_HasMemoryBase, + }; + + AssetStreamAdaptor(Asset*, OwnAsset, HasMemoryBase); + ~AssetStreamAdaptor(); + virtual bool rewind(); virtual size_t read(void* buffer, size_t size); virtual bool hasLength() const { return true; } virtual size_t getLength() const; virtual bool isAtEnd() const; + virtual const void* getMemoryBase() { return fMemoryBase; } + virtual SkStreamRewindable* duplicate() const; private: - Asset* fAsset; + Asset* fAsset; + const void* const fMemoryBase; + const OwnAsset fOwnAsset; }; /** diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp index 48367ff..a17f328 100644 --- a/core/jni/android/opengl/util.cpp +++ b/core/jni/android/opengl/util.cpp @@ -632,7 +632,7 @@ static jint util_getInternalFormat(JNIEnv *env, jclass clazz, SkBitmap const * nativeBitmap = (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); const SkBitmap& bitmap(*nativeBitmap); - SkBitmap::Config config = bitmap.getConfig(); + SkBitmap::Config config = bitmap.config(); return getInternalFormat(config); } @@ -642,7 +642,7 @@ static jint util_getType(JNIEnv *env, jclass clazz, SkBitmap const * nativeBitmap = (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); const SkBitmap& bitmap(*nativeBitmap); - SkBitmap::Config config = bitmap.getConfig(); + SkBitmap::Config config = bitmap.config(); return getType(config); } @@ -653,7 +653,7 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz, SkBitmap const * nativeBitmap = (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); const SkBitmap& bitmap(*nativeBitmap); - SkBitmap::Config config = bitmap.getConfig(); + SkBitmap::Config config = bitmap.config(); if (internalformat < 0) { internalformat = getInternalFormat(config); } @@ -681,7 +681,7 @@ static jint util_texImage2D(JNIEnv *env, jclass clazz, SkColorTable* ctable = bitmap.getColorTable(); memcpy(data, ctable->lockColors(), ctable->count() * sizeof(SkPMColor)); memcpy(pixels, p, size); - ctable->unlockColors(false); + ctable->unlockColors(); glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data); free(data); } else { @@ -702,7 +702,7 @@ static jint util_texSubImage2D(JNIEnv *env, jclass clazz, SkBitmap const * nativeBitmap = (SkBitmap const *)env->GetLongField(jbitmap, nativeBitmapID); const SkBitmap& bitmap(*nativeBitmap); - SkBitmap::Config config = bitmap.getConfig(); + SkBitmap::Config config = bitmap.config(); if (format < 0) { format = getInternalFormat(config); if (format == GL_PALETTE8_RGBA8_OES) diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index c2d4ec0..ab6c1e0 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -39,6 +39,7 @@ #include <SkCanvas.h> #include <SkBitmap.h> +#include <SkImage.h> #include <SkRegion.h> #include <utils/misc.h> @@ -179,7 +180,8 @@ static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jlong n static inline SkBitmap::Config convertPixelFormat(PixelFormat format) { /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then we can map to SkBitmap::kARGB_8888_Config, and optionally call - bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator) + bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap + (as an accelerator) */ switch (format) { case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config; @@ -235,7 +237,7 @@ static jlong nativeLockCanvas(JNIEnv* env, jclass clazz, ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr); if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) { - bitmap.setIsOpaque(true); + bitmap.setAlphaType(kOpaque_SkAlphaType); } if (outBuffer.width > 0 && outBuffer.height > 0) { bitmap.setPixels(outBuffer.bits); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index bd53095..ed84a64 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -61,51 +61,21 @@ static struct { class ScreenshotPixelRef : public SkPixelRef { public: - ScreenshotPixelRef(SkColorTable* ctable) { - fCTable = ctable; - SkSafeRef(ctable); + ScreenshotPixelRef(const SkImageInfo& info, ScreenshotClient* screenshot) : + SkPixelRef(info), + mScreenshot(screenshot) { setImmutable(); } virtual ~ScreenshotPixelRef() { - SkSafeUnref(fCTable); - } - - status_t update(const sp<IBinder>& display, int width, int height, - int minLayer, int maxLayer, bool allLayers) { - status_t res = (width > 0 && height > 0) - ? (allLayers - ? mScreenshot.update(display, width, height) - : mScreenshot.update(display, width, height, minLayer, maxLayer)) - : mScreenshot.update(display); - if (res != NO_ERROR) { - return res; - } - - return NO_ERROR; - } - - uint32_t getWidth() const { - return mScreenshot.getWidth(); - } - - uint32_t getHeight() const { - return mScreenshot.getHeight(); - } - - uint32_t getStride() const { - return mScreenshot.getStride(); - } - - uint32_t getFormat() const { - return mScreenshot.getFormat(); + delete mScreenshot; } protected: // overrides from SkPixelRef virtual void* onLockPixels(SkColorTable** ct) { - *ct = fCTable; - return (void*)mScreenshot.getPixels(); + *ct = NULL; + return (void*)mScreenshot->getPixels(); } virtual void onUnlockPixels() { @@ -113,8 +83,7 @@ protected: SK_DECLARE_UNFLATTENABLE_OBJECT() private: - ScreenshotClient mScreenshot; - SkColorTable* fCTable; + ScreenshotClient* mScreenshot; typedef SkPixelRef INHERITED; }; @@ -147,19 +116,6 @@ static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) { ctrl->decStrong((void *)nativeCreate); } -static inline SkBitmap::Config convertPixelFormat(PixelFormat format) { - /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then - we can map to SkBitmap::kARGB_8888_Config, and optionally call - bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator) - */ - switch (format) { - case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config; - case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config; - case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config; - default: return SkBitmap::kNo_Config; - } -} - static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj, jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) { sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj); @@ -167,26 +123,50 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject display return NULL; } - ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL); - if (pixels->update(displayToken, width, height, - minLayer, maxLayer, allLayers) != NO_ERROR) { - delete pixels; + ScreenshotClient* screenshot = new ScreenshotClient(); + status_t res = (width > 0 && height > 0) + ? (allLayers + ? screenshot->update(displayToken, width, height) + : screenshot->update(displayToken, width, height, minLayer, maxLayer)) + : screenshot->update(displayToken); + if (res != NO_ERROR) { + delete screenshot; return NULL; } - uint32_t w = pixels->getWidth(); - uint32_t h = pixels->getHeight(); - uint32_t s = pixels->getStride(); - uint32_t f = pixels->getFormat(); - ssize_t bpr = s * android::bytesPerPixel(f); + SkImageInfo screenshotInfo; + screenshotInfo.fWidth = screenshot->getWidth(); + screenshotInfo.fHeight = screenshot->getHeight(); - SkBitmap* bitmap = new SkBitmap(); - bitmap->setConfig(convertPixelFormat(f), w, h, bpr); - if (f == PIXEL_FORMAT_RGBX_8888) { - bitmap->setIsOpaque(true); + switch (screenshot->getFormat()) { + case PIXEL_FORMAT_RGBX_8888: { + screenshotInfo.fColorType = kRGBA_8888_SkColorType; + screenshotInfo.fAlphaType = kIgnore_SkAlphaType; + break; + } + case PIXEL_FORMAT_RGBA_8888: { + screenshotInfo.fColorType = kRGBA_8888_SkColorType; + screenshotInfo.fAlphaType = kPremul_SkAlphaType; + break; + } + case PIXEL_FORMAT_RGB_565: { + screenshotInfo.fColorType = kRGB_565_SkColorType; + screenshotInfo.fAlphaType = kIgnore_SkAlphaType; + break; + } + default: { + delete screenshot; + return NULL; + } } - if (w > 0 && h > 0) { + // takes ownership of ScreenshotClient + ScreenshotPixelRef* pixels = new ScreenshotPixelRef(screenshotInfo, screenshot); + ssize_t rowBytes = screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat()); + + SkBitmap* bitmap = new SkBitmap(); + bitmap->setConfig(screenshotInfo, rowBytes); + if (screenshotInfo.fWidth > 0 && screenshotInfo.fHeight > 0) { bitmap->setPixelRef(pixels)->unref(); bitmap->lockPixels(); } else { diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp index 54f9278..77ede33 100644 --- a/core/jni/android_view_TextureView.cpp +++ b/core/jni/android_view_TextureView.cpp @@ -27,6 +27,7 @@ #include <SkBitmap.h> #include <SkCanvas.h> +#include <SkImage.h> namespace android { @@ -162,7 +163,7 @@ static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject, bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount); if (buffer.format == WINDOW_FORMAT_RGBX_8888) { - bitmap.setIsOpaque(true); + bitmap.setAlphaType(kOpaque_SkAlphaType); } if (buffer.width > 0 && buffer.height > 0) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8355928..8ec2d64 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1056,8 +1056,9 @@ android:permissionGroupFlags="personalInfo" android:priority="370" /> - <!-- Allows an application to monitor, modify, or abort outgoing - calls. --> + <!-- Allows an application to see the number being dialed during an outgoing + call with the option to redirect the call to a different number or + abort the call altogether. --> <permission android:name="android.permission.PROCESS_OUTGOING_CALLS" android:permissionGroup="android.permission-group.PHONE_CALLS" android:protectionLevel="dangerous" @@ -1199,7 +1200,7 @@ android:permissionGroup="android.permission-group.STORAGE" android:label="@string/permlab_manageDocs" android:description="@string/permdesc_manageDocs" - android:protectionLevel="signature|system" /> + android:protectionLevel="signature" /> <!-- ================================== --> <!-- Permissions for screenlock --> @@ -1534,7 +1535,7 @@ @hide --> <permission android:name="android.permission.FORCE_STOP_PACKAGES" android:permissionGroup="android.permission-group.SYSTEM_TOOLS" - android:protectionLevel="signature" + android:protectionLevel="signature|system" android:label="@string/permlab_forceStopPackages" android:description="@string/permdesc_forceStopPackages" /> diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png Binary files differindex 458a2a6..e215b96 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png +++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_dark.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.png Binary files differindex 03b0d2a..a014e91 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.png +++ b/core/res/res/drawable-hdpi/ic_media_route_disabled_holo_light.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png Binary files differindex c91faa9..bb8bec1 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png +++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_dark.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png Binary files differindex 14c9183..aa1737e 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png +++ b/core/res/res/drawable-hdpi/ic_media_route_off_holo_light.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png Binary files differindex b388d86..2c1434b 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_dark.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png Binary files differindex 76c1323..dbdce3e 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_0_holo_light.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png Binary files differindex fd39f9d..1101864 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_dark.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png Binary files differindex c74727a..e8e9069 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_1_holo_light.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png Binary files differindex 826c9ae..8595158 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_dark.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png Binary files differindex d0baec3..14844d4 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_2_holo_light.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png Binary files differindex c60ff59..1565a29 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_dark.png diff --git a/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png Binary files differindex 75552cc..9b8fe87 100644 --- a/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png +++ b/core/res/res/drawable-hdpi/ic_media_route_on_holo_light.png diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_0.png b/core/res/res/drawable-hdpi/ic_notification_cast_0.png Binary files differindex a35f281..74f7dc0 100644 --- a/core/res/res/drawable-hdpi/ic_notification_cast_0.png +++ b/core/res/res/drawable-hdpi/ic_notification_cast_0.png diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_1.png b/core/res/res/drawable-hdpi/ic_notification_cast_1.png Binary files differindex 9f6e2ad..c6d267d 100644 --- a/core/res/res/drawable-hdpi/ic_notification_cast_1.png +++ b/core/res/res/drawable-hdpi/ic_notification_cast_1.png diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_2.png b/core/res/res/drawable-hdpi/ic_notification_cast_2.png Binary files differindex 737137a..699b299 100644 --- a/core/res/res/drawable-hdpi/ic_notification_cast_2.png +++ b/core/res/res/drawable-hdpi/ic_notification_cast_2.png diff --git a/core/res/res/drawable-hdpi/ic_notification_cast_on.png b/core/res/res/drawable-hdpi/ic_notification_cast_on.png Binary files differindex ff2753a..3eaf13a 100644 --- a/core/res/res/drawable-hdpi/ic_notification_cast_on.png +++ b/core/res/res/drawable-hdpi/ic_notification_cast_on.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png Binary files differindex fa22d82..52e3a5a 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png +++ b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_dark.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.png Binary files differindex a686cd1..319c57e 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.png +++ b/core/res/res/drawable-mdpi/ic_media_route_disabled_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png Binary files differindex 9d92648..f98c0a8 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png +++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_dark.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png Binary files differindex 3e27fc8..b74cdb5 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png +++ b/core/res/res/drawable-mdpi/ic_media_route_off_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png Binary files differindex 72b9e78..a6a4bd0 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_dark.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png Binary files differindex bd462a2..106fd3a 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_0_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png Binary files differindex 0a2cc89..2c141ab 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_dark.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png Binary files differindex d162503..0b62d0b 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_1_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png Binary files differindex 997e32b..23442b0 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_dark.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png Binary files differindex d314967..42b329f 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_2_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png Binary files differindex f15d7a9..58ff506 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_dark.png diff --git a/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png Binary files differindex 26d46f8..25257f8 100644 --- a/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png +++ b/core/res/res/drawable-mdpi/ic_media_route_on_holo_light.png diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_0.png b/core/res/res/drawable-mdpi/ic_notification_cast_0.png Binary files differindex d9cedbd..a51a3cb 100644 --- a/core/res/res/drawable-mdpi/ic_notification_cast_0.png +++ b/core/res/res/drawable-mdpi/ic_notification_cast_0.png diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_1.png b/core/res/res/drawable-mdpi/ic_notification_cast_1.png Binary files differindex 414c67f..e081367 100644 --- a/core/res/res/drawable-mdpi/ic_notification_cast_1.png +++ b/core/res/res/drawable-mdpi/ic_notification_cast_1.png diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_2.png b/core/res/res/drawable-mdpi/ic_notification_cast_2.png Binary files differindex 280a888..a7f4de4 100644 --- a/core/res/res/drawable-mdpi/ic_notification_cast_2.png +++ b/core/res/res/drawable-mdpi/ic_notification_cast_2.png diff --git a/core/res/res/drawable-mdpi/ic_notification_cast_on.png b/core/res/res/drawable-mdpi/ic_notification_cast_on.png Binary files differindex ab5f1d7..42de8c4 100644 --- a/core/res/res/drawable-mdpi/ic_notification_cast_on.png +++ b/core/res/res/drawable-mdpi/ic_notification_cast_on.png diff --git a/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png Binary files differindex 6b31579..7b6d48b 100644 --- a/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png Binary files differindex df0121b..bafe878 100644 --- a/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png Binary files differindex 045eee0..4119cff 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_dark.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png Binary files differindex 6e14e29..b629a57 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_disabled_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png Binary files differindex 121bbf6..fe81128 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_dark.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png Binary files differindex 468a0c3..9b59eaf 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_off_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png Binary files differindex 414a322..1a513c1 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_dark.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png Binary files differindex 6088a48..ff78803 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_0_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png Binary files differindex 363d7d4..4c4b624 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_dark.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png Binary files differindex edf731e..60f8c4d 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_1_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png Binary files differindex 85cba7b..cdb2f30 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_dark.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png Binary files differindex e65ac31..97a10a3 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_2_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png Binary files differindex d8e3e3a..a19a083 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_dark.png diff --git a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png Binary files differindex 562dc9a..db30613 100644 --- a/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png +++ b/core/res/res/drawable-xhdpi/ic_media_route_on_holo_light.png diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_0.png b/core/res/res/drawable-xhdpi/ic_notification_cast_0.png Binary files differindex 5fb23a0..818c1cd 100644 --- a/core/res/res/drawable-xhdpi/ic_notification_cast_0.png +++ b/core/res/res/drawable-xhdpi/ic_notification_cast_0.png diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_1.png b/core/res/res/drawable-xhdpi/ic_notification_cast_1.png Binary files differindex f01d17d..2a56e31 100644 --- a/core/res/res/drawable-xhdpi/ic_notification_cast_1.png +++ b/core/res/res/drawable-xhdpi/ic_notification_cast_1.png diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_2.png b/core/res/res/drawable-xhdpi/ic_notification_cast_2.png Binary files differindex 4f4ba7f..3515a76 100644 --- a/core/res/res/drawable-xhdpi/ic_notification_cast_2.png +++ b/core/res/res/drawable-xhdpi/ic_notification_cast_2.png diff --git a/core/res/res/drawable-xhdpi/ic_notification_cast_on.png b/core/res/res/drawable-xhdpi/ic_notification_cast_on.png Binary files differindex 38f15dd..142065b 100644 --- a/core/res/res/drawable-xhdpi/ic_notification_cast_on.png +++ b/core/res/res/drawable-xhdpi/ic_notification_cast_on.png diff --git a/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png Binary files differindex 418f322..cbb4f4c 100644 --- a/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png +++ b/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png diff --git a/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png Binary files differindex a5a59d4..6d467f7 100644 --- a/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png +++ b/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png Binary files differindex 178774c..6fad4a64 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_dark.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png Binary files differindex 2dc2092..865617c 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_disabled_holo_light.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png Binary files differindex 592ee8c..44d98d5 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_dark.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png Binary files differindex f0549e2..b5b29b0 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_off_holo_light.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png Binary files differindex 91268f5..c807b50 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_dark.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png Binary files differindex 9d5436f..3fc7188 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_0_holo_light.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png Binary files differindex 8e77483..d54f44a 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_dark.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png Binary files differindex f396d22..092fe8c 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_1_holo_light.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png Binary files differindex 260bab4..17c1d99 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_dark.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png Binary files differindex 2c9fb1d..4fd5808 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_2_holo_light.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png Binary files differindex bdbd59c..906401e 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_dark.png diff --git a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png Binary files differindex f5c33dd..d29e563 100644 --- a/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png +++ b/core/res/res/drawable-xxhdpi/ic_media_route_on_holo_light.png diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png Binary files differindex f5b16ed..7ef0d3d 100644 --- a/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png +++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_0.png diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png Binary files differindex 22efeec..ed04beb 100644 --- a/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png +++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_1.png diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png Binary files differindex e24cd97..d62d27d 100644 --- a/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png +++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_2.png diff --git a/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png b/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png Binary files differindex da1a627..d562602 100644 --- a/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png +++ b/core/res/res/drawable-xxhdpi/ic_notification_cast_on.png diff --git a/core/res/res/values-ja/bools.xml b/core/res/res/values-ja/bools.xml deleted file mode 100644 index 59cf744..0000000 --- a/core/res/res/values-ja/bools.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<resources> - <bool name="flip_controller_fallback_keys">true</bool> -</resources> - diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml index 10a5d85..18e4f2f 100644 --- a/core/res/res/values/bools.xml +++ b/core/res/res/values/bools.xml @@ -26,5 +26,4 @@ <bool name="show_ongoing_ime_switcher">true</bool> <bool name="action_bar_expanded_action_views_exclusive">true</bool> <bool name="target_honeycomb_needs_options_menu">true</bool> - <bool name="flip_controller_fallback_keys">false</bool> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b34c792..a3b8132 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -352,6 +352,10 @@ <!-- Wifi driver supports batched scan --> <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool> + <!-- Wifi driver's fallback country code; WS is ISO-Alpha2 code for Samoa which + has restrictions on can be scanned; which may satisfy quite a few regulatory issues. --> + <string translatable="false" name="config_wifi_unknown_country_code">WS</string> + <!-- Flag indicating whether the we should enable the automatic brightness in Settings. Software implementation will be used if config_hardware_auto_brightness_available is not set --> <bool name="config_automatic_brightness_available">false</bool> @@ -1304,4 +1308,12 @@ <item>333</item> <item>353</item> </string-array> + + <!-- Override the default detection behavior for the framework method + android.view.ViewConfiguration#hasPermanentMenuKey(). + Valid settings are: + 0 - No change. Use the default autodetection behavior. + 1 - The device DOES have a permanent menu key; ignore autodetection. + 2 - The device DOES NOT have a permanent menu key; ignore autodetection. --> + <integer name="config_overrideHasPermanentMenuKey">0</integer> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 012fb83..538003f 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -625,9 +625,9 @@ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_processOutgoingCalls">reroute outgoing calls</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> - <string name="permdesc_processOutgoingCalls">Allows the app to process - outgoing calls and change the number to be dialed. This permission allows - the app to monitor, redirect, or prevent outgoing calls.</string> + <string name="permdesc_processOutgoingCalls">Allows the app to see the + number being dialed during an outgoing call with the option to redirect + the call to a different number or abort the call altogether.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_receiveSms">receive text messages (SMS)</string> @@ -932,13 +932,13 @@ <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_getAppOpsStats">Allows the app to retrieve collected application operation statistics. Not for use by normal apps.</string> - + <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_updateAppOpsStats">modify app ops statistics</string> <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_updateAppOpsStats">Allows the app to modify collected application operation statistics. Not for use by normal apps.</string> - + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_backup">control system backup and restore</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> @@ -2255,6 +2255,10 @@ <!-- Other SIP address type. Same context as Other phone type. --> <string name="sipAddressTypeOther">Other</string> + <!-- Error message that is displayed when the user clicks on a quick contacts badge, but + there is no contacts application installed that can display the quick contact --> + <string name="quick_contacts_not_available">No application found to view this contact.</string> + <!-- Instructions telling the user to enter their SIM PIN to unlock the keyguard. Displayed in one line in a large font. --> <string name="keyguard_password_enter_pin_code">Type PIN code</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6d90973..1200276 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -288,7 +288,6 @@ <java-symbol type="bool" name="config_useFixedVolume" /> <java-symbol type="bool" name="config_forceDefaultOrientation" /> <java-symbol type="bool" name="config_wifi_batched_scan_supported" /> - <java-symbol type="bool" name="flip_controller_fallback_keys" /> <java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_extraFreeKbytesAdjust" /> @@ -319,6 +318,7 @@ <java-symbol type="integer" name="config_mobile_mtu" /> <java-symbol type="integer" name="config_volte_replacement_rat"/> <java-symbol type="integer" name="config_valid_wappush_index" /> + <java-symbol type="integer" name="config_overrideHasPermanentMenuKey" /> <java-symbol type="color" name="tab_indicator_text_v4" /> @@ -478,6 +478,7 @@ <java-symbol type="string" name="config_ntpServer" /> <java-symbol type="string" name="config_tether_apndata" /> <java-symbol type="string" name="config_useragentprofile_url" /> + <java-symbol type="string" name="config_wifi_unknown_country_code" /> <java-symbol type="string" name="config_wifi_p2p_device_type" /> <java-symbol type="string" name="contentServiceSync" /> <java-symbol type="string" name="contentServiceSyncNotificationTitle" /> @@ -690,6 +691,7 @@ <java-symbol type="string" name="mobile_provisioning_apn" /> <java-symbol type="string" name="mobile_provisioning_url" /> <java-symbol type="string" name="mobile_redirected_provisioning_url" /> + <java-symbol type="string" name="quick_contacts_not_available" /> <java-symbol type="string" name="reboot_safemode_confirm" /> <java-symbol type="string" name="reboot_safemode_title" /> <java-symbol type="string" name="relationTypeAssistant" /> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java index 5a4a2d0..9d97ac5 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/NetworkState.java @@ -101,9 +101,10 @@ public class NetworkState { } /* - * Transition from CONNECTED -> DISCONNECTED: - * CONNECTED->DISCONNECTING->DISCONNECTED - * return false if any state transition is not valid and save a message in mReason + * Verifies state transition from CONNECTED->...-> DISCONNECTED. + * + * returns false if initial state or target state is not correct, or if there is + * any transition from DISCONNECTING/DISCONNECTED -> CONNECTED. */ public boolean transitToDisconnection () { mReason = "states: " + printStates(); @@ -120,13 +121,13 @@ public class NetworkState { for (int i = 1; i < mStateDepository.size() - 1; i++) { State preState = mStateDepository.get(i-1); State curState = mStateDepository.get(i); - if ((preState == State.CONNECTED) && ((curState == State.DISCONNECTING) || + if (preState == curState) { + continue; + } else if ((preState == State.CONNECTED) && ((curState == State.DISCONNECTING) || (curState == State.DISCONNECTED))) { continue; } else if ((preState == State.DISCONNECTING) && (curState == State.DISCONNECTED)) { continue; - } else if ((preState == State.DISCONNECTED) && (curState == State.DISCONNECTED)) { - continue; } else { mReason += " Transition state from " + preState.toString() + " to " + curState.toString() + " is not valid."; @@ -136,7 +137,12 @@ public class NetworkState { return true; } - // DISCONNECTED->CONNECTING->CONNECTED + /* + * Verifies state transition from DISCONNECTED->...-> CONNECTED. + * + * returns false if initial state or target state is not correct, or if there is + * any transition from CONNECED -> DISCONNECTED. + */ public boolean transitToConnection() { mReason = "states: " + printStates(); if (mStateDepository.get(0) != State.DISCONNECTED) { @@ -152,14 +158,15 @@ public class NetworkState { for (int i = 1; i < mStateDepository.size(); i++) { State preState = mStateDepository.get(i-1); State curState = mStateDepository.get(i); - if ((preState == State.DISCONNECTED) && ((curState == State.CONNECTING) || - (curState == State.CONNECTED) || (curState == State.DISCONNECTED))) { + if (preState == curState) { continue; - } else if ((preState == State.CONNECTING) && (curState == State.CONNECTED)) { - continue; - } else if ((preState == State.CONNECTED) && (curState == State.CONNECTED)) { + } + if ((preState == State.DISCONNECTED) && ((curState == State.CONNECTING) || + (curState == State.CONNECTED))) { continue; - } else { + } else if ((preState == State.CONNECTING) && (curState == State.CONNECTED)) { + continue; + } else { mReason += " Transition state from " + preState.toString() + " to " + curState.toString() + " is not valid."; return false; |