summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt22
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java8
-rw-r--r--core/java/android/app/ActivityThread.java26
-rw-r--r--core/java/android/app/ApplicationPackageManager.java4
-rw-r--r--core/java/android/app/ContextImpl.java8
-rw-r--r--core/java/android/app/LoadedApk.java151
-rw-r--r--core/java/android/app/ResourcesManager.java14
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java39
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl4
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java46
-rw-r--r--core/java/android/content/pm/InstrumentationInfo.java25
-rw-r--r--core/java/android/hardware/ICameraService.aidl5
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java104
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceState.java6
-rw-r--r--core/java/android/hardware/camera2/legacy/GLThreadManager.java6
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java96
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java139
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java132
-rw-r--r--core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java5
-rw-r--r--core/java/android/hardware/camera2/utils/CameraBinderDecorator.java2
-rw-r--r--core/java/android/widget/Spinner.java15
-rw-r--r--core/jni/android_os_Debug.cpp16
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/drawable/view_accessibility_focused.xml8
-rw-r--r--core/res/res/values/colors.xml2
-rw-r--r--core/res/res/values/strings.xml7
-rw-r--r--keystore/java/android/security/KeyChain.java17
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java61
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java23
-rw-r--r--rs/java/android/renderscript/Font.java8
-rw-r--r--services/core/java/com/android/server/MountServiceIdler.java3
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java25
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java17
-rwxr-xr-xservices/core/java/com/android/server/pm/PackageManagerService.java154
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java61
-rw-r--r--telecomm/java/android/telecomm/ConnectionService.java6
-rw-r--r--telecomm/java/android/telecomm/Subscription.aidl22
-rw-r--r--telecomm/java/android/telecomm/Subscription.java205
-rw-r--r--telecomm/java/com/android/internal/telecomm/ITelecommService.aidl16
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java53
41 files changed, 1227 insertions, 342 deletions
diff --git a/api/current.txt b/api/current.txt
index cf19d542117e..fd546f1cfb63 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -91,6 +91,7 @@ package android {
field public static final java.lang.String NFC = "android.permission.NFC";
field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+ field public static final java.lang.String READ_ALL_VOICEMAIL = "com.android.voicemail.permission.READ_ALL_VOICEMAIL";
field public static final java.lang.String READ_CALENDAR = "android.permission.READ_CALENDAR";
field public static final java.lang.String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
field public static final java.lang.String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -5243,10 +5244,7 @@ package android.app.admin {
method public int getPasswordQuality(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
- method public boolean hasAnyCaCertsInstalled();
- method public boolean hasCaCertInstalled(byte[]);
method public boolean hasGrantedPolicy(android.content.ComponentName, int);
- method public boolean installCaCert(android.content.ComponentName, byte[]);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationBlocked(android.content.ComponentName, java.lang.String);
@@ -5284,7 +5282,6 @@ package android.app.admin {
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public int setStorageEncryption(android.content.ComponentName, boolean);
- method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
@@ -8164,6 +8161,8 @@ package android.content.pm {
field public int requiresSmallestWidthDp;
field public java.lang.String[] sharedLibraryFiles;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitPublicSourceDirs;
+ field public java.lang.String[] splitSourceDirs;
field public int targetSdkVersion;
field public java.lang.String taskAffinity;
field public int theme;
@@ -8232,6 +8231,8 @@ package android.content.pm {
field public boolean handleProfiling;
field public java.lang.String publicSourceDir;
field public java.lang.String sourceDir;
+ field public java.lang.String[] splitPublicSourceDirs;
+ field public java.lang.String[] splitSourceDirs;
field public java.lang.String targetPackage;
}
@@ -27740,8 +27741,17 @@ package android.telecomm {
}
public class Subscription implements android.os.Parcelable {
- ctor public Subscription();
+ ctor public Subscription(android.content.ComponentName, java.lang.String, android.net.Uri, int, int, int, boolean, boolean);
method public int describeContents();
+ method public android.content.ComponentName getComponentName();
+ method public android.net.Uri getHandle();
+ method public android.graphics.drawable.Drawable getIcon(android.content.Context);
+ method public android.graphics.drawable.Drawable getIcon(android.content.Context, int);
+ method public java.lang.String getId();
+ method public java.lang.String getLabel(android.content.Context);
+ method public java.lang.String getShortDescription(android.content.Context);
+ method public boolean isEnabled();
+ method public boolean isSystemDefault();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
@@ -28205,6 +28215,7 @@ package android.telephony {
method public java.lang.String getSimSerialNumber();
method public int getSimState();
method public java.lang.String getSubscriberId();
+ method public java.util.List<android.telecomm.Subscription> getSubscriptions();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public boolean hasIccCard();
@@ -28229,6 +28240,7 @@ package android.telephony {
field public static final java.lang.String EXTRA_STATE_IDLE;
field public static final java.lang.String EXTRA_STATE_OFFHOOK;
field public static final java.lang.String EXTRA_STATE_RINGING;
+ field public static final java.lang.String EXTRA_SUBSCRIPTION = "subscription";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 47047b86a6ec..f85a7dc89876 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -58,11 +58,13 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;
+
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
public final class Pm {
IPackageManager mPm;
@@ -1548,6 +1550,12 @@ public final class Pm {
if (info != null && info.applicationInfo != null) {
System.out.print("package:");
System.out.println(info.applicationInfo.sourceDir);
+ if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
+ for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
+ System.out.print("package:");
+ System.out.println(splitSourceDir);
+ }
+ }
}
} catch (RemoteException e) {
System.err.println(e.toString());
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ea4604466a6b..b8f20891164e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -191,11 +191,13 @@ public final class ActivityThread {
/** Reference to singleton {@link ActivityThread} */
private static ActivityThread sCurrentActivityThread;
Instrumentation mInstrumentation;
+ String mInstrumentationPackageName = null;
String mInstrumentationAppDir = null;
- String mInstrumentationAppLibraryDir = null;
- String mInstrumentationAppPackage = null;
+ String[] mInstrumentationSplitAppDirs = null;
+ String mInstrumentationLibDir = null;
String mInstrumentedAppDir = null;
- String mInstrumentedAppLibraryDir = null;
+ String[] mInstrumentedSplitAppDirs = null;
+ String mInstrumentedLibDir = null;
boolean mSystemThread = false;
boolean mJitEnabled = false;
@@ -1585,11 +1587,11 @@ public final class ActivityThread {
/**
* Creates the top level resources for the given package.
*/
- Resources getTopLevelResources(String resDir, String[] overlayDirs, String[] libDirs,
- int displayId, Configuration overrideConfiguration,
+ Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
+ String[] libDirs, int displayId, Configuration overrideConfiguration,
LoadedApk pkgInfo) {
- return mResourcesManager.getTopLevelResources(resDir, overlayDirs, libDirs, displayId,
- overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
+ return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
+ displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
}
final Handler getHandler() {
@@ -4315,16 +4317,20 @@ public final class ActivityThread {
+ data.instrumentationName);
}
+ mInstrumentationPackageName = ii.packageName;
mInstrumentationAppDir = ii.sourceDir;
- mInstrumentationAppLibraryDir = ii.nativeLibraryDir;
- mInstrumentationAppPackage = ii.packageName;
+ mInstrumentationSplitAppDirs = ii.splitSourceDirs;
+ mInstrumentationLibDir = ii.nativeLibraryDir;
mInstrumentedAppDir = data.info.getAppDir();
- mInstrumentedAppLibraryDir = data.info.getLibDir();
+ mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
+ mInstrumentedLibDir = data.info.getLibDir();
ApplicationInfo instrApp = new ApplicationInfo();
instrApp.packageName = ii.packageName;
instrApp.sourceDir = ii.sourceDir;
instrApp.publicSourceDir = ii.publicSourceDir;
+ instrApp.splitSourceDirs = ii.splitSourceDirs;
+ instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
instrApp.dataDir = ii.dataDir;
instrApp.nativeLibraryDir = ii.nativeLibraryDir;
LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 84673d9e238e..de0396e478d7 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -823,8 +823,10 @@ final class ApplicationPackageManager extends PackageManager {
if (app.packageName.equals("system")) {
return mContext.mMainThread.getSystemContext().getResources();
}
+ final boolean sameUid = (app.uid == Process.myUid());
Resources r = mContext.mMainThread.getTopLevelResources(
- app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
+ sameUid ? app.sourceDir : app.publicSourceDir,
+ sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
app.resourceDirs, null, Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
if (r != null) {
return r;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a42bd3b92730..3e7d9b450708 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2190,10 +2190,10 @@ class ContextImpl extends Context {
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
- resources = mResourcesManager.getTopLevelResources(
- packageInfo.getResDir(), packageInfo.getOverlayDirs(),
- packageInfo.getApplicationInfo().sharedLibraryFiles,
- displayId, overrideConfiguration, compatInfo, activityToken);
+ resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
+ packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
+ packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
+ overrideConfiguration, compatInfo, activityToken);
}
}
mResources = resources;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 3ae8bfcb4f3f..065e88db320d 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -16,8 +16,8 @@
package android.app;
+import android.text.TextUtils;
import android.util.ArrayMap;
-import com.android.internal.util.ArrayUtils;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -52,6 +52,8 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Enumeration;
final class IntentReceiverLeaked extends AndroidRuntimeException {
@@ -79,6 +81,8 @@ public final class LoadedApk {
final String mPackageName;
private final String mAppDir;
private final String mResDir;
+ private final String[] mSplitAppDirs;
+ private final String[] mSplitResDirs;
private final String[] mOverlayDirs;
private final String[] mSharedLibraries;
private final String mDataDir;
@@ -116,13 +120,14 @@ public final class LoadedApk {
public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
CompatibilityInfo compatInfo, ClassLoader baseLoader,
boolean securityViolation, boolean includeCode) {
+ final int myUid = Process.myUid();
mActivityThread = activityThread;
mApplicationInfo = aInfo;
mPackageName = aInfo.packageName;
mAppDir = aInfo.sourceDir;
- final int myUid = Process.myUid();
- mResDir = aInfo.uid == myUid ? aInfo.sourceDir
- : aInfo.publicSourceDir;
+ mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
+ mSplitAppDirs = aInfo.splitSourceDirs;
+ mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
mOverlayDirs = aInfo.resourceDirs;
if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
@@ -149,6 +154,8 @@ public final class LoadedApk {
mPackageName = "android";
mAppDir = null;
mResDir = null;
+ mSplitAppDirs = null;
+ mSplitResDirs = null;
mOverlayDirs = null;
mSharedLibraries = null;
mDataDir = null;
@@ -214,53 +221,6 @@ public final class LoadedApk {
return ai.sharedLibraryFiles;
}
- /**
- * Combines two arrays (of library names) such that they are
- * concatenated in order but are devoid of duplicates. The
- * result is a single string with the names of the libraries
- * separated by colons, or <code>null</code> if both lists
- * were <code>null</code> or empty.
- *
- * @param list1 null-ok; the first list
- * @param list2 null-ok; the second list
- * @return null-ok; the combination
- */
- private static String combineLibs(String[] list1, String[] list2) {
- StringBuilder result = new StringBuilder(300);
- boolean first = true;
-
- if (list1 != null) {
- for (String s : list1) {
- if (first) {
- first = false;
- } else {
- result.append(':');
- }
- result.append(s);
- }
- }
-
- // Only need to check for duplicates if list1 was non-empty.
- boolean dupCheck = !first;
-
- if (list2 != null) {
- for (String s : list2) {
- if (dupCheck && ArrayUtils.contains(list1, s)) {
- continue;
- }
-
- if (first) {
- first = false;
- } else {
- result.append(':');
- }
- result.append(s);
- }
- }
-
- return result.toString();
- }
-
public ClassLoader getClassLoader() {
synchronized (this) {
if (mClassLoader != null) {
@@ -268,8 +228,15 @@ public final class LoadedApk {
}
if (mIncludeCode && !mPackageName.equals("android")) {
- String zip = mAppDir;
- String libraryPath = mLibDir;
+ final ArrayList<String> zipPaths = new ArrayList<>();
+ final ArrayList<String> libPaths = new ArrayList<>();
+
+ zipPaths.add(mAppDir);
+ if (mSplitAppDirs != null) {
+ Collections.addAll(zipPaths, mSplitAppDirs);
+ }
+
+ libPaths.add(mLibDir);
/*
* The following is a bit of a hack to inject
@@ -280,50 +247,70 @@ public final class LoadedApk {
* concatenation of both apps' shared library lists.
*/
- String instrumentationAppDir =
- mActivityThread.mInstrumentationAppDir;
- String instrumentationAppLibraryDir =
- mActivityThread.mInstrumentationAppLibraryDir;
- String instrumentationAppPackage =
- mActivityThread.mInstrumentationAppPackage;
- String instrumentedAppDir =
- mActivityThread.mInstrumentedAppDir;
- String instrumentedAppLibraryDir =
- mActivityThread.mInstrumentedAppLibraryDir;
+ String instrumentationPackageName = mActivityThread.mInstrumentationPackageName;
+ String instrumentationAppDir = mActivityThread.mInstrumentationAppDir;
+ String[] instrumentationSplitAppDirs = mActivityThread.mInstrumentationSplitAppDirs;
+ String instrumentationLibDir = mActivityThread.mInstrumentationLibDir;
+
+ String instrumentedAppDir = mActivityThread.mInstrumentedAppDir;
+ String[] instrumentedSplitAppDirs = mActivityThread.mInstrumentedSplitAppDirs;
+ String instrumentedLibDir = mActivityThread.mInstrumentedLibDir;
String[] instrumentationLibs = null;
if (mAppDir.equals(instrumentationAppDir)
|| mAppDir.equals(instrumentedAppDir)) {
- zip = instrumentationAppDir + ":" + instrumentedAppDir;
- libraryPath = instrumentationAppLibraryDir + ":" + instrumentedAppLibraryDir;
- if (! instrumentedAppDir.equals(instrumentationAppDir)) {
- instrumentationLibs =
- getLibrariesFor(instrumentationAppPackage);
+ zipPaths.clear();
+ zipPaths.add(instrumentationAppDir);
+ if (instrumentationSplitAppDirs != null) {
+ Collections.addAll(zipPaths, instrumentationSplitAppDirs);
+ }
+ zipPaths.add(instrumentedAppDir);
+ if (instrumentedSplitAppDirs != null) {
+ Collections.addAll(zipPaths, instrumentedSplitAppDirs);
+ }
+
+ libPaths.clear();
+ libPaths.add(instrumentationLibDir);
+ libPaths.add(instrumentedLibDir);
+
+ if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+ instrumentationLibs = getLibrariesFor(instrumentationPackageName);
}
}
- if ((mSharedLibraries != null) ||
- (instrumentationLibs != null)) {
- zip =
- combineLibs(mSharedLibraries, instrumentationLibs)
- + ':' + zip;
+ if (mSharedLibraries != null) {
+ for (String lib : mSharedLibraries) {
+ if (!zipPaths.contains(lib)) {
+ zipPaths.add(0, lib);
+ }
+ }
}
+ if (instrumentationLibs != null) {
+ for (String lib : instrumentationLibs) {
+ if (!zipPaths.contains(lib)) {
+ zipPaths.add(0, lib);
+ }
+ }
+ }
+
+ final String zip = TextUtils.join(File.pathSeparator, zipPaths);
+ final String lib = TextUtils.join(File.pathSeparator, libPaths);
+
/*
* With all the combination done (if necessary, actually
* create the class loader.
*/
if (ActivityThread.localLOGV)
- Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + libraryPath);
+ Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + lib);
// Temporarily disable logging of disk reads on the Looper thread
// as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- mClassLoader =
- ApplicationLoaders.getDefault().getClassLoader(
- zip, libraryPath, mBaseClassLoader);
+ mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,
+ mBaseClassLoader);
initializeJavaContextClassLoader();
StrictMode.setThreadPolicy(oldPolicy);
@@ -469,6 +456,14 @@ public final class LoadedApk {
return mResDir;
}
+ public String[] getSplitAppDirs() {
+ return mSplitAppDirs;
+ }
+
+ public String[] getSplitResDirs() {
+ return mSplitResDirs;
+ }
+
public String[] getOverlayDirs() {
return mOverlayDirs;
}
@@ -487,7 +482,7 @@ public final class LoadedApk {
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
- mResources = mainThread.getTopLevelResources(mResDir, mOverlayDirs,
+ mResources = mainThread.getTopLevelResources(mResDir, mSplitResDirs, mOverlayDirs,
mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY, null, this);
}
return mResources;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index a67faa09be86..3c1311537848 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -149,9 +149,9 @@ public class ResourcesManager {
* @param compatInfo the compability info. Must not be null.
* @param token the application token for determining stack bounds.
*/
- public Resources getTopLevelResources(String resDir, String[] overlayDirs, String[] libDirs,
- int displayId, Configuration overrideConfiguration, CompatibilityInfo compatInfo,
- IBinder token) {
+ public Resources getTopLevelResources(String resDir, String[] splitResDirs,
+ String[] overlayDirs, String[] libDirs, int displayId,
+ Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
final float scale = compatInfo.applicationScale;
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, token);
Resources r;
@@ -182,6 +182,14 @@ public class ResourcesManager {
return null;
}
+ if (splitResDirs != null) {
+ for (String splitResDir : splitResDirs) {
+ if (assets.addAssetPath(splitResDir) == 0) {
+ return null;
+ }
+ }
+ }
+
if (overlayDirs != null) {
for (String idmapPath : overlayDirs) {
assets.addOverlayPath(idmapPath);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 99f68d08e7b3..e80c7616204f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1506,11 +1506,12 @@ public class DevicePolicyManager {
*
* @return false if the certBuffer cannot be parsed or installation is
* interrupted, otherwise true
+ * @hide
*/
- public boolean installCaCert(ComponentName who, byte[] certBuffer) {
+ public boolean installCaCert(byte[] certBuffer) {
if (mService != null) {
try {
- return mService.installCaCert(who, certBuffer);
+ return mService.installCaCert(certBuffer);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1520,14 +1521,13 @@ public class DevicePolicyManager {
/**
* Uninstalls the given certificate from the list of User CAs, if present.
+ *
+ * @hide
*/
- public void uninstallCaCert(ComponentName who, byte[] certBuffer) {
+ public void uninstallCaCert(byte[] certBuffer) {
if (mService != null) {
try {
- final String alias = getCaCertAlias(certBuffer);
- mService.uninstallCaCert(who, alias);
- } catch (CertificateException e) {
- Log.w(TAG, "Unable to parse certificate", e);
+ mService.uninstallCaCert(certBuffer);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
@@ -1536,8 +1536,10 @@ public class DevicePolicyManager {
/**
* Returns whether there are any user-installed CA certificates.
+ *
+ * @hide
*/
- public boolean hasAnyCaCertsInstalled() {
+ public static boolean hasAnyCaCertsInstalled() {
TrustedCertificateStore certStore = new TrustedCertificateStore();
Set<String> aliases = certStore.userAliases();
return aliases != null && !aliases.isEmpty();
@@ -1545,10 +1547,18 @@ public class DevicePolicyManager {
/**
* Returns whether this certificate has been installed as a User CA.
+ *
+ * @hide
*/
public boolean hasCaCertInstalled(byte[] certBuffer) {
+ TrustedCertificateStore certStore = new TrustedCertificateStore();
+ String alias;
+ byte[] pemCert;
try {
- return getCaCertAlias(certBuffer) != null;
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+ X509Certificate cert = (X509Certificate) certFactory.generateCertificate(
+ new ByteArrayInputStream(certBuffer));
+ return certStore.getCertificateAlias(cert) != null;
} catch (CertificateException ce) {
Log.w(TAG, "Could not parse certificate", ce);
}
@@ -1556,17 +1566,6 @@ public class DevicePolicyManager {
}
/**
- * Returns the alias of a given CA certificate in the certificate store, or null if it
- * doesn't exist.
- */
- private static String getCaCertAlias(byte[] certBuffer) throws CertificateException {
- final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- final X509Certificate cert = (X509Certificate) certFactory.generateCertificate(
- new ByteArrayInputStream(certBuffer));
- return new TrustedCertificateStore().getCertificateAlias(cert);
- }
-
- /**
* Called by an application that is administering the device to disable all cameras
* on the device. After setting this, no applications will be able to access any cameras
* on the device.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e935da74b9bc..a1caa2199b1d 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -115,8 +115,8 @@ interface IDevicePolicyManager {
String getProfileOwnerName(int userHandle);
void setProfileEnabled(in ComponentName who);
- boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
- void uninstallCaCert(in ComponentName admin, in String alias);
+ boolean installCaCert(in byte[] certBuffer);
+ void uninstallCaCert(in byte[] certBuffer);
void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6b44a115cd42..06f4019df06d 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -23,8 +23,12 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.Printer;
+import com.android.internal.util.ArrayUtils;
+
import java.text.Collator;
+import java.util.Arrays;
import java.util.Comparator;
+import java.util.Objects;
/**
* Information you can retrieve about a particular application. This
@@ -398,17 +402,30 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public int largestWidthLimitDp = 0;
/**
- * Full path to the location of this package.
+ * Full path to the base APK for this application.
*/
public String sourceDir;
/**
- * Full path to the location of the publicly available parts of this
- * package (i.e. the primary resource package and manifest). For
- * non-forward-locked apps this will be the same as {@link #sourceDir).
+ * Full path to the publicly available parts of {@link #sourceDir},
+ * including resources and manifest. This may be different from
+ * {@link #sourceDir} if an application is forward locked.
*/
public String publicSourceDir;
-
+
+ /**
+ * Full paths to zero or more split APKs that, when combined with the base
+ * APK defined in {@link #sourceDir}, form a complete application.
+ */
+ public String[] splitSourceDirs;
+
+ /**
+ * Full path to the publicly available parts of {@link #splitSourceDirs},
+ * including resources and manifest. This may be different from
+ * {@link #splitSourceDirs} if an application is forward locked.
+ */
+ public String[] splitPublicSourceDirs;
+
/**
* Full paths to the locations of extra resource packages this application
* uses. This field is only used if there are extra resource packages,
@@ -512,13 +529,16 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
+ " compatibleWidthLimitDp=" + compatibleWidthLimitDp
+ " largestWidthLimitDp=" + largestWidthLimitDp);
pw.println(prefix + "sourceDir=" + sourceDir);
- if (sourceDir == null) {
- if (publicSourceDir != null) {
- pw.println(prefix + "publicSourceDir=" + publicSourceDir);
- }
- } else if (!sourceDir.equals(publicSourceDir)) {
+ if (!Objects.equals(sourceDir, publicSourceDir)) {
pw.println(prefix + "publicSourceDir=" + publicSourceDir);
}
+ if (!ArrayUtils.isEmpty(splitSourceDirs)) {
+ pw.println(prefix + "splitSourceDirs=" + Arrays.toString(splitSourceDirs));
+ }
+ if (!ArrayUtils.isEmpty(splitPublicSourceDirs)
+ && !Arrays.equals(splitSourceDirs, splitPublicSourceDirs)) {
+ pw.println(prefix + "splitPublicSourceDirs=" + Arrays.toString(splitPublicSourceDirs));
+ }
if (resourceDirs != null) {
pw.println(prefix + "resourceDirs=" + resourceDirs);
}
@@ -591,6 +611,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
largestWidthLimitDp = orig.largestWidthLimitDp;
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
+ splitSourceDirs = orig.splitSourceDirs;
+ splitPublicSourceDirs = orig.splitPublicSourceDirs;
nativeLibraryDir = orig.nativeLibraryDir;
cpuAbi = orig.cpuAbi;
resourceDirs = orig.resourceDirs;
@@ -633,6 +655,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(largestWidthLimitDp);
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
+ dest.writeStringArray(splitSourceDirs);
+ dest.writeStringArray(splitPublicSourceDirs);
dest.writeString(nativeLibraryDir);
dest.writeString(cpuAbi);
dest.writeStringArray(resourceDirs);
@@ -674,6 +698,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
largestWidthLimitDp = source.readInt();
sourceDir = source.readString();
publicSourceDir = source.readString();
+ splitSourceDirs = source.readStringArray();
+ splitPublicSourceDirs = source.readStringArray();
nativeLibraryDir = source.readString();
cpuAbi = source.readString();
resourceDirs = source.readStringArray();
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index a977e41c3d69..dab0caffd57a 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -30,17 +30,32 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable {
* "package" attribute.
*/
public String targetPackage;
-
+
/**
- * Full path to the location of this package.
+ * Full path to the base APK for this application.
*/
public String sourceDir;
-
+
/**
- * Full path to the location of the publicly available parts of this package (i.e. the resources
- * and manifest). For non-forward-locked apps this will be the same as {@link #sourceDir).
+ * Full path to the publicly available parts of {@link #sourceDir},
+ * including resources and manifest. This may be different from
+ * {@link #sourceDir} if an application is forward locked.
*/
public String publicSourceDir;
+
+ /**
+ * Full paths to zero or more split APKs that, when combined with the base
+ * APK defined in {@link #sourceDir}, form a complete application.
+ */
+ public String[] splitSourceDirs;
+
+ /**
+ * Full path to the publicly available parts of {@link #splitSourceDirs},
+ * including resources and manifest. This may be different from
+ * {@link #splitSourceDirs} if an application is forward locked.
+ */
+ public String[] splitPublicSourceDirs;
+
/**
* Full path to a directory assigned to the package for its persistent
* data.
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index 4c50dda1f096..31896f55b09f 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -69,4 +69,9 @@ interface ICameraService
* well-formatted in the generated java method.
*/
int getCameraVendorTagDescriptor(out BinderHolder desc);
+
+ // Writes the camera1 parameters into a single-element array.
+ int getLegacyParameters(int cameraId, out String[] parameters);
+ // Determines if a particular API version is supported; see ICameraService.h for version defines
+ int supportsCameraApi(int cameraId, int apiVersion);
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 09015622d2a0..73188ff0898b 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -19,8 +19,10 @@ package android.hardware.camera2;
import android.content.Context;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
+import android.hardware.CameraInfo;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.hardware.camera2.legacy.CameraDeviceUserShim;
+import android.hardware.camera2.legacy.LegacyMetadataMapper;
import android.hardware.camera2.utils.CameraBinderDecorator;
import android.hardware.camera2.utils.CameraRuntimeException;
import android.hardware.camera2.utils.BinderHolder;
@@ -57,6 +59,10 @@ public final class CameraManager {
private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
private static final int USE_CALLING_UID = -1;
+ @SuppressWarnings("unused")
+ private static final int API_VERSION_1 = 1;
+ private static final int API_VERSION_2 = 2;
+
private final ICameraService mCameraService;
private ArrayList<String> mDeviceIdList;
@@ -142,6 +148,9 @@ public final class CameraManager {
synchronized (mLock) {
mListenerMap.put(listener, handler);
+
+ // TODO: fire the current oldest known state when adding a new listener
+ // (must be done while holding lock)
}
}
@@ -185,16 +194,46 @@ public final class CameraManager {
}
}
- CameraMetadataNative info = new CameraMetadataNative();
- try {
- mCameraService.getCameraCharacteristics(Integer.valueOf(cameraId), info);
- } catch(CameraRuntimeException e) {
- throw e.asChecked();
- } catch(RemoteException e) {
- // impossible
- return null;
+ int id = Integer.valueOf(cameraId);
+
+ /*
+ * Get the camera characteristics from the camera service directly if it supports it,
+ * otherwise get them from the legacy shim instead.
+ */
+
+ if (!supportsCamera2Api(cameraId)) {
+ // Legacy backwards compatibility path; build static info from the camera parameters
+ String[] outParameters = new String[1];
+ try {
+ mCameraService.getLegacyParameters(id, /*out*/outParameters);
+ String parameters = outParameters[0];
+
+ CameraInfo info = new CameraInfo();
+ mCameraService.getCameraInfo(id, /*out*/info);
+
+ return LegacyMetadataMapper.createCharacteristics(parameters, info);
+ } catch (RemoteException e) {
+ // Impossible
+ return null;
+ } catch (CameraRuntimeException e) {
+ throw e.asChecked();
+ }
+
+ } else {
+ // Normal path: Get the camera characteristics directly from the camera service
+ CameraMetadataNative info = new CameraMetadataNative();
+
+ try {
+ mCameraService.getCameraCharacteristics(id, info);
+ } catch(CameraRuntimeException e) {
+ throw e.asChecked();
+ } catch(RemoteException e) {
+ // impossible
+ return null;
+ }
+
+ return new CameraCharacteristics(info);
}
- return new CameraCharacteristics(info);
}
/**
@@ -456,6 +495,53 @@ public final class CameraManager {
}
}
+ /**
+ * Queries the camera service if it supports the camera2 api directly, or needs a shim.
+ *
+ * @param cameraId a non-{@code null} camera identifier
+ * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise.
+ */
+ private boolean supportsCamera2Api(String cameraId) {
+ return supportsCameraApi(cameraId, API_VERSION_2);
+ }
+
+ /**
+ * Queries the camera service if it supports a camera api directly, or needs a shim.
+ *
+ * @param cameraId a non-{@code null} camera identifier
+ * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2}
+ * @return {@code true} if connecting will work for that device version.
+ */
+ private boolean supportsCameraApi(String cameraId, int apiVersion) {
+ int id = Integer.parseInt(cameraId);
+
+ /*
+ * Possible return values:
+ * - NO_ERROR => Camera2 API is supported
+ * - CAMERA_DEPRECATED_HAL => Camera2 API is *not* supported (thrown as an exception)
+ *
+ * Anything else is an unexpected error we don't want to recover from.
+ */
+
+ try {
+ int res = mCameraService.supportsCameraApi(id, apiVersion);
+
+ if (res != CameraBinderDecorator.NO_ERROR) {
+ throw new AssertionError("Unexpected value " + res);
+ }
+
+ return true;
+ } catch (CameraRuntimeException e) {
+ if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
+ return false;
+ } else {
+ throw e;
+ }
+ } catch (RemoteException e) {
+ throw new AssertionError("Camera service unreachable", e);
+ }
+ }
+
// TODO: this class needs unit tests
// TODO: extract class into top level
private class CameraServiceListener extends ICameraServiceListener.Stub {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index 22ff9c63114f..ab7e8449230c 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -34,6 +34,7 @@ import android.util.Log;
* <li>{@code CONFIGURING -> IDLE}</li>
* <li>{@code IDLE -> CONFIGURING}</li>
* <li>{@code IDLE -> CAPTURING}</li>
+ * <li>{@code IDLE -> IDLE}</li>
* <li>{@code CAPTURING -> IDLE}</li>
* <li>{@code ANY -> ERROR}</li>
* </ul>
@@ -216,12 +217,17 @@ public class CameraDeviceState {
mCurrentState = STATE_CONFIGURING;
break;
case STATE_IDLE:
+ if (mCurrentState == STATE_IDLE) {
+ break;
+ }
+
if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) {
Log.e(TAG, "Cannot call idle while in state: " + mCurrentState);
mCurrentError = CameraBinderDecorator.INVALID_OPERATION;
doStateTransition(STATE_ERROR);
break;
}
+
if (mCurrentState != STATE_IDLE && mCurrentHandler != null &&
mCurrentListener != null) {
mCurrentHandler.post(new Runnable() {
diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
index 3fd2309912ec..038255762040 100644
--- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
@@ -148,6 +148,12 @@ public class GLThreadManager {
Handler handler = mGLHandlerThread.getHandler();
handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
mGLHandlerThread.quitSafely();
+ try {
+ mGLHandlerThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mGLHandlerThread.getName(), mGLHandlerThread.getId()));
+ }
}
/**
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index f9cf90596973..c34a34de021e 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -48,7 +48,6 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
public class LegacyCameraDevice implements AutoCloseable {
public static final String DEBUG_PROP = "HAL1ShimLogging";
-
private final String TAG;
private final int mCameraId;
@@ -56,10 +55,11 @@ public class LegacyCameraDevice implements AutoCloseable {
private final CameraDeviceState mDeviceState = new CameraDeviceState();
private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
- private final AtomicInteger mRequestIdCounter = new AtomicInteger(0);
- private final HandlerThread mCallbackHandlerThread = new HandlerThread("ResultThread");
+ private final HandlerThread mResultThread = new HandlerThread("ResultThread");
+ private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
private final Handler mCallbackHandler;
+ private final Handler mResultHandler;
private static final int ILLEGAL_VALUE = -1;
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
@@ -81,11 +81,18 @@ public class LegacyCameraDevice implements AutoCloseable {
public void onError(final int errorCode, RequestHolder holder) {
mIdle.open();
final CaptureResultExtras extras = getExtrasFromRequest(holder);
- try {
- mDeviceCallbacks.onCameraError(errorCode, extras);
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraError callback: ", e);
- }
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mDeviceCallbacks.onCameraError(errorCode, extras);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraError callback: ", e);
+ }
+ }
+ });
+
}
@@ -98,36 +105,55 @@ public class LegacyCameraDevice implements AutoCloseable {
public void onIdle() {
mIdle.open();
- try {
- mDeviceCallbacks.onCameraIdle();
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraIdle callback: ", e);
- }
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mDeviceCallbacks.onCameraIdle();
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraIdle callback: ", e);
+ }
+ }
+ });
}
@Override
public void onCaptureStarted(RequestHolder holder) {
final CaptureResultExtras extras = getExtrasFromRequest(holder);
- try {
- // TODO: Don't fake timestamp
- mDeviceCallbacks.onCaptureStarted(extras, System.nanoTime());
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraError callback: ", e);
- }
+ final long timestamp = System.nanoTime();
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // TODO: Don't fake timestamp
+ mDeviceCallbacks.onCaptureStarted(extras, timestamp);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraError callback: ", e);
+ }
+ }
+ });
}
@Override
- public void onCaptureResult(CameraMetadataNative result, RequestHolder holder) {
+ public void onCaptureResult(final CameraMetadataNative result, RequestHolder holder) {
final CaptureResultExtras extras = getExtrasFromRequest(holder);
- try {
- // TODO: Don't fake metadata
- mDeviceCallbacks.onResultReceived(result, extras);
- } catch (RemoteException e) {
- Log.e(TAG, "Received remote exception during onCameraError callback: ", e);
- }
+ mResultHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // TODO: Don't fake metadata
+ mDeviceCallbacks.onResultReceived(result, extras);
+ } catch (RemoteException e) {
+ throw new IllegalStateException(
+ "Received remote exception during onCameraError callback: ", e);
+ }
+ }
+ });
}
};
@@ -161,6 +187,8 @@ public class LegacyCameraDevice implements AutoCloseable {
mDeviceCallbacks = callbacks;
TAG = String.format("CameraDevice-%d-LE", mCameraId);
+ mResultThread.start();
+ mResultHandler = new Handler(mResultThread.getLooper());
mCallbackHandlerThread.start();
mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
@@ -244,6 +272,22 @@ public class LegacyCameraDevice implements AutoCloseable {
public void close() {
mRequestThreadManager.quit();
mCallbackHandlerThread.quitSafely();
+ mResultThread.quitSafely();
+
+ try {
+ mCallbackHandlerThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
+ }
+
+ try {
+ mResultThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mResultThread.getName(), mResultThread.getId()));
+ }
+
// TODO: throw IllegalStateException in every method after close has been called
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
new file mode 100644
index 000000000000..8bb066fd09a3
--- /dev/null
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.legacy;
+
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+import android.hardware.Camera.Size;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.StreamConfiguration;
+import android.hardware.camera2.params.StreamConfigurationDuration;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.android.internal.util.Preconditions.*;
+import static android.hardware.camera2.CameraCharacteristics.*;
+
+/**
+ * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the
+ * camera characteristics.
+ */
+public class LegacyMetadataMapper {
+ private static final String TAG = "LegacyMetadataMapper";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+
+ // from graphics.h
+ private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+ private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
+
+ /**
+ * Create characteristics for a legacy device by mapping the {@code parameters}
+ * and {@code info}
+ *
+ * @param parameters A string parseable by {@link Camera.Parameters#unflatten}
+ * @param info Camera info with camera facing direction and angle of orientation
+ * @return static camera characteristics for a camera device
+ *
+ * @throws NullPointerException if any of the args were {@code null}
+ */
+ public static CameraCharacteristics createCharacteristics(String parameters,
+ android.hardware.CameraInfo info) {
+ checkNotNull(parameters, "parameters must not be null");
+ checkNotNull(info, "info must not be null");
+ checkNotNull(info.info, "info.info must not be null");
+
+ CameraMetadataNative m = new CameraMetadataNative();
+
+ mapCameraInfo(m, info.info);
+
+ Camera.Parameters params = Camera.getEmptyParameters();
+ params.unflatten(parameters);
+ mapCameraParameters(m, params);
+
+ if (VERBOSE) {
+ Log.v(TAG, "createCharacteristics metadata:");
+ Log.v(TAG, "--------------------------------------------------- (start)");
+ m.dumpToLog();
+ Log.v(TAG, "--------------------------------------------------- (end)");
+ }
+
+ return new CameraCharacteristics(m);
+ }
+
+ private static void mapCameraInfo(CameraMetadataNative m, CameraInfo i) {
+ m.set(LENS_FACING, i.facing == CameraInfo.CAMERA_FACING_BACK ?
+ LENS_FACING_BACK : LENS_FACING_FRONT);
+ m.set(SENSOR_ORIENTATION, i.orientation);
+ }
+
+ private static void mapCameraParameters(CameraMetadataNative m, Camera.Parameters p) {
+ mapStreamConfigs(m, p);
+
+ // TODO: map other fields
+ }
+
+ private static void mapStreamConfigs(CameraMetadataNative m, Camera.Parameters p) {
+ // TODO: set non-empty durations
+ m.set(SCALER_AVAILABLE_MIN_FRAME_DURATIONS, new StreamConfigurationDuration[] {} );
+ m.set(SCALER_AVAILABLE_STALL_DURATIONS, new StreamConfigurationDuration[] {} );
+
+ ArrayList<StreamConfiguration> availableStreamConfigs = new ArrayList<>();
+ /*
+ * Implementation-defined (preview, recording, etc) -> use camera1 preview sizes
+ * YUV_420_888 cpu callbacks -> use camera1 preview sizes
+ * Other preview callbacks (CPU) -> use camera1 preview sizes
+ * JPEG still capture -> use camera1 still capture sizes
+ *
+ * Use platform-internal format constants here, since StreamConfigurationMap does the
+ * remapping to public format constants.
+ */
+ List<Size> previewSizes = p.getSupportedPreviewSizes();
+ appendStreamConfig(availableStreamConfigs,
+ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, previewSizes);
+ appendStreamConfig(availableStreamConfigs,
+ ImageFormat.YUV_420_888, previewSizes);
+ for (int format : p.getSupportedPreviewFormats()) {
+ if (ImageFormat.isPublicFormat(format)) {
+ appendStreamConfig(availableStreamConfigs, format, previewSizes);
+ } else {
+ /*
+ * Do not add any formats unknown to us
+ * (since it would fail runtime checks in StreamConfigurationMap)
+ */
+ Log.w(TAG,
+ String.format("mapStreamConfigs - Skipping non-public format %x", format));
+ }
+ }
+ appendStreamConfig(availableStreamConfigs,
+ HAL_PIXEL_FORMAT_BLOB, p.getSupportedPictureSizes());
+ m.set(SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+ availableStreamConfigs.toArray(new StreamConfiguration[0]));
+ }
+
+ private static void appendStreamConfig(
+ ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) {
+ for (Camera.Size size : sizes) {
+ StreamConfiguration config =
+ new StreamConfiguration(format, size.width, size.height, /*input*/false);
+ configs.add(config);
+ }
+ }
+}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index c4669f516b1b..7b522ffa36ce 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -20,6 +20,7 @@ import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.utils.LongParcelable;
import android.hardware.camera2.impl.CameraMetadataNative;
import android.os.ConditionVariable;
@@ -28,12 +29,15 @@ import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.util.Pair;
+import android.util.Size;
import android.view.Surface;
import java.io.IOError;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -64,6 +68,7 @@ public class RequestThreadManager {
private static final int PREVIEW_FRAME_TIMEOUT = 300; // ms
private static final int JPEG_FRAME_TIMEOUT = 1000; // ms
+ private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
private boolean mPreviewRunning = false;
private volatile RequestHolder mInFlightPreview;
@@ -74,6 +79,8 @@ public class RequestThreadManager {
private GLThreadManager mGLThreadManager;
private SurfaceTexture mPreviewTexture;
+ private Size mIntermediateBufferSize;
+
private final RequestQueue mRequestQueue = new RequestQueue();
private SurfaceTexture mDummyTexture;
private Surface mDummySurface;
@@ -93,6 +100,31 @@ public class RequestThreadManager {
}
}
+
+ /**
+ * Comparator for {@link Size} objects.
+ *
+ * <p>This comparator compares by rectangle area. Tiebreaks on width.</p>
+ */
+ private static class SizeComparator implements Comparator<Size> {
+ @Override
+ public int compare(Size size, Size size2) {
+ if (size == null || size2 == null) {
+ throw new NullPointerException("Null argument passed to compare");
+ }
+ if (size.equals(size2)) return 0;
+ long width = size.getWidth();
+ long width2 = size2.getWidth();
+ long area = width * size.getHeight();
+ long area2 = width2 * size2.getHeight();
+ if (area == area2) {
+ return (width > width2) ? 1 : -1;
+ }
+ return (area > area2) ? 1 : -1;
+
+ }
+ }
+
/**
* Counter class used to calculate and log the current FPS of frame production.
*/
@@ -230,7 +262,13 @@ public class RequestThreadManager {
return; // Already running
}
- mPreviewTexture.setDefaultBufferSize(640, 480); // TODO: size selection based on request
+ if (mPreviewTexture == null) {
+ throw new IllegalStateException(
+ "Preview capture called with no preview surfaces configured.");
+ }
+
+ mPreviewTexture.setDefaultBufferSize(mIntermediateBufferSize.getWidth(),
+ mIntermediateBufferSize.getHeight());
mCamera.setPreviewTexture(mPreviewTexture);
Camera.Parameters params = mCamera.getParameters();
List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange();
@@ -248,6 +286,7 @@ public class RequestThreadManager {
startPreview();
}
+
private void configureOutputs(Collection<Surface> outputs) throws IOException {
stopPreview();
if (mGLThreadManager != null) {
@@ -261,6 +300,7 @@ public class RequestThreadManager {
mInFlightPreview = null;
mInFlightJpeg = null;
+
for (Surface s : outputs) {
int format = LegacyCameraDevice.nativeDetectSurfaceType(s);
switch (format) {
@@ -273,6 +313,52 @@ public class RequestThreadManager {
}
}
+ if (mPreviewOutputs.size() > 0) {
+ List<Size> outputSizes = new ArrayList<>(outputs.size());
+ for (Surface s : mPreviewOutputs) {
+ int[] dimens = {0, 0};
+ LegacyCameraDevice.nativeDetectSurfaceDimens(s, dimens);
+ outputSizes.add(new Size(dimens[0], dimens[1]));
+ }
+
+ Size largestOutput = findLargestByArea(outputSizes);
+
+ Camera.Parameters params = mCamera.getParameters();
+
+ // Find largest jpeg dimension - assume to have the same aspect ratio as sensor.
+ List<Size> supportedJpegSizes = convertSizeList(params.getSupportedPictureSizes());
+ Size largestJpegDimen = findLargestByArea(supportedJpegSizes);
+
+ List<Size> supportedPreviewSizes = convertSizeList(params.getSupportedPreviewSizes());
+
+ // Use smallest preview dimension with same aspect ratio as sensor that is >= than all
+ // of the configured output dimensions. If none exists, fall back to using the largest
+ // supported preview size.
+ long largestOutputArea = largestOutput.getHeight() * (long) largestOutput.getWidth();
+ Size bestPreviewDimen = findLargestByArea(supportedPreviewSizes);
+ for (Size s : supportedPreviewSizes) {
+ long currArea = s.getWidth() * s.getHeight();
+ long bestArea = bestPreviewDimen.getWidth() * bestPreviewDimen.getHeight();
+ if (checkAspectRatiosMatch(largestJpegDimen, s) && (currArea < bestArea &&
+ currArea >= largestOutputArea)) {
+ bestPreviewDimen = s;
+ }
+ }
+
+ mIntermediateBufferSize = bestPreviewDimen;
+ if (DEBUG) {
+ Log.d(TAG, "Intermediate buffer selected with dimens: " +
+ bestPreviewDimen.toString());
+ }
+ } else {
+ mIntermediateBufferSize = null;
+ if (DEBUG) {
+ Log.d(TAG, "No Intermediate buffer selected, no preview outputs were configured");
+ }
+ }
+
+
+
// TODO: Detect and optimize single-output paths here to skip stream teeing.
if (mGLThreadManager == null) {
mGLThreadManager = new GLThreadManager(mCameraId);
@@ -282,7 +368,28 @@ public class RequestThreadManager {
mGLThreadManager.setConfigurationAndWait(mPreviewOutputs);
mGLThreadManager.allowNewFrames();
mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture();
- mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);
+ if (mPreviewTexture != null) {
+ mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);
+ }
+ }
+
+ private static Size findLargestByArea(List<Size> sizes) {
+ return Collections.max(sizes, new SizeComparator());
+ }
+
+ private static boolean checkAspectRatiosMatch(Size a, Size b) {
+ float aAspect = a.getWidth() / (float) a.getHeight();
+ float bAspect = b.getWidth() / (float) b.getHeight();
+
+ return Math.abs(aAspect - bAspect) < ASPECT_RATIO_TOLERANCE;
+ }
+
+ private static List<Size> convertSizeList(List<Camera.Size> sizeList) {
+ List<Size> sizes = new ArrayList<>(sizeList.size());
+ for (Camera.Size s : sizeList) {
+ sizes.add(new Size(s.width, s.height));
+ }
+ return sizes;
}
// Calculate the highest FPS range supported
@@ -376,8 +483,10 @@ public class RequestThreadManager {
// TODO: err handling
throw new IOError(e);
}
- // TODO: Set fields in result.
- mDeviceState.setCaptureResult(holder, new CameraMetadataNative());
+ Camera.Parameters params = mCamera.getParameters();
+ CameraMetadataNative result = convertResultMetadata(params,
+ holder.getRequest());
+ mDeviceState.setCaptureResult(holder, result);
}
break;
case MSG_CLEANUP:
@@ -397,6 +506,15 @@ public class RequestThreadManager {
}
};
+ private CameraMetadataNative convertResultMetadata(Camera.Parameters params,
+ CaptureRequest request) {
+ CameraMetadataNative result = new CameraMetadataNative();
+ result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength());
+
+ // TODO: Remaining result metadata tags conversions.
+ return result;
+ }
+
/**
* Create a new RequestThreadManager.
*
@@ -437,6 +555,12 @@ public class RequestThreadManager {
Handler handler = mRequestThread.waitAndGetHandler();
handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
mRequestThread.quitSafely();
+ try {
+ mRequestThread.join();
+ } catch (InterruptedException e) {
+ Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
+ mRequestThread.getName(), mRequestThread.getId()));
+ }
}
/**
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index 2f0f6bc4582e..49f419f2dcf0 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -431,6 +431,11 @@ public class SurfaceTextureRenderer {
public void configureSurfaces(Collection<Surface> surfaces) {
releaseEGLContext();
+ if (surfaces == null || surfaces.size() == 0) {
+ Log.w(TAG, "No output surfaces configured for GL drawing.");
+ return;
+ }
+
for (Surface s : surfaces) {
// If pixel conversions aren't handled by egl, use a pbuffer
if (LegacyCameraDevice.needsConversion(s)) {
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index 40cda08cf7f7..898c74612ca6 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -47,6 +47,8 @@ public class CameraBinderDecorator {
* - POLICY_PROHIBITS
* - RESOURCE_BUSY
* - NO_SUCH_DEVICE
+ * - NOT_SUPPORTED
+ * - TOO_MANY_USERS
*/
public static final int EACCES = -13;
public static final int EBUSY = -16;
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 9601d4a703df..9914800ec6ca 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -25,6 +25,7 @@ import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -427,9 +428,15 @@ public class Spinner extends AbsSpinner implements OnClickListener {
* {@link Adapter#getItemViewType(int) getItemViewType(int)} on the object
* returned from {@link #getAdapter()} will always return 0. Calling
* {@link Adapter#getViewTypeCount() getViewTypeCount()} will always return
- * 1.
+ * 1. On API {@link Build.VERSION_CODES#L} and above, attempting to set an
+ * adapter with more than one view type will throw an
+ * {@link IllegalArgumentException}.
+ *
+ * @param adapter the adapter to set
*
* @see AbsSpinner#setAdapter(SpinnerAdapter)
+ * @throws IllegalArgumentException if the adapter has more than one view
+ * type
*/
@Override
public void setAdapter(SpinnerAdapter adapter) {
@@ -437,6 +444,12 @@ public class Spinner extends AbsSpinner implements OnClickListener {
mRecycler.clear();
+ final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ if (targetSdkVersion >= Build.VERSION_CODES.L
+ && adapter != null && adapter.getViewTypeCount() != 1) {
+ throw new IllegalArgumentException("Spinner adapter view type count must be 1");
+ }
+
if (mPopup != null) {
mPopup.setAdapter(new DropDownAdapter(adapter));
} else {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 86207f0a3ea2..87ee6184563d 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -174,21 +174,21 @@ static int read_memtrack_memory(struct memtrack_proc* p, int pid,
ssize_t pss = memtrack_proc_graphics_pss(p);
if (pss < 0) {
- ALOGW("failed to get graphics pss: %d", pss);
+ ALOGW("failed to get graphics pss: %zd", pss);
return pss;
}
graphics_mem->graphics = pss / 1024;
pss = memtrack_proc_gl_pss(p);
if (pss < 0) {
- ALOGW("failed to get gl pss: %d", pss);
+ ALOGW("failed to get gl pss: %zd", pss);
return pss;
}
graphics_mem->gl = pss / 1024;
pss = memtrack_proc_other_pss(p);
if (pss < 0) {
- ALOGW("failed to get other pss: %d", pss);
+ ALOGW("failed to get other pss: %zd", pss);
return pss;
}
graphics_mem->other = pss / 1024;
@@ -231,9 +231,9 @@ static void read_mapinfo(FILE *fp, stats_t* stats)
unsigned referenced = 0;
unsigned temp;
- unsigned long int start;
- unsigned long int end = 0;
- unsigned long int prevEnd = 0;
+ uint64_t start;
+ uint64_t end = 0;
+ uint64_t prevEnd = 0;
char* name;
int name_pos;
@@ -255,7 +255,7 @@ static void read_mapinfo(FILE *fp, stats_t* stats)
if (len < 1) return;
line[--len] = 0;
- if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
+ if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
skip = true;
} else {
while (isspace(line[name_pos])) {
@@ -371,7 +371,7 @@ static void read_mapinfo(FILE *fp, stats_t* stats)
referenced = temp;
} else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
swapped_out = temp;
- } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') {
+ } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
// looks like a new mapping
// example: "10000000-10001000 ---p 10000000 00:00 0"
break;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c08c5e2ef61c..8b5dff014e19 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -657,6 +657,13 @@
android:label="@string/permlab_addVoicemail"
android:description="@string/permdesc_addVoicemail" />
+ <!-- Allows an application to read all the voicemails in the system. -->
+ <permission android:name="com.android.voicemail.permission.READ_ALL_VOICEMAIL"
+ android:permissionGroup="android.permission-group.VOICEMAIL"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_readAllVoicemail"
+ android:description="@string/permdesc_readAllVoicemail" />
+
<!-- =============================================== -->
<!-- Permissions for enabling accessibility features -->
<!-- =============================================== -->
diff --git a/core/res/res/drawable/view_accessibility_focused.xml b/core/res/res/drawable/view_accessibility_focused.xml
index 0da9a81bd8fb..68e3f1ecb97f 100644
--- a/core/res/res/drawable/view_accessibility_focused.xml
+++ b/core/res/res/drawable/view_accessibility_focused.xml
@@ -17,9 +17,11 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke
- android:width="2dp"
- android:color="@color/accessibility_focus_highlight" />
+ android:width="4dp"
+ android:color="@color/accessibility_focus_highlight"
+ android:dashWidth="4dp"
+ android:dashGap="2dp" />
- <corners android:radius="2dp"/>
+ <corners android:radius="2dp" />
</shape>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 9f6c7ad81089..f3045144718c 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -143,7 +143,7 @@
<color name="keyguard_avatar_nick_color">#ffffffff</color>
<color name="keyguard_avatar_frame_pressed_color">#ff35b5e5</color>
- <color name="accessibility_focus_highlight">#80ffff00</color>
+ <color name="accessibility_focus_highlight">#bf39b500</color>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6e1b5ef62c47..e31dbaf08009 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2971,6 +2971,13 @@
to your voicemail inbox.</string>
<!-- Title of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permlab_readAllVoicemail">read all voicemail</string>
+ <!-- Description of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_readAllVoicemail">Allows the app to read all your voicemails.</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_writeGeolocationPermissions">modify Browser geolocation permissions</string>
<!-- Description of an application permission, listed so the user can choose whether
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 0da2b9989444..9d6d76e37118 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -23,9 +23,7 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Process;
import android.os.RemoteException;
-import android.os.UserHandle;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.security.InvalidKeyException;
@@ -439,14 +437,6 @@ public final class KeyChain {
* Caller should call unbindService on the result when finished.
*/
public static KeyChainConnection bind(Context context) throws InterruptedException {
- return bindAsUser(context, Process.myUserHandle());
- }
-
- /**
- * @hide
- */
- public static KeyChainConnection bindAsUser(Context context, UserHandle user)
- throws InterruptedException {
if (context == null) {
throw new NullPointerException("context == null");
}
@@ -469,10 +459,9 @@ public final class KeyChain {
Intent intent = new Intent(IKeyChainService.class.getName());
ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
intent.setComponent(comp);
- boolean isBound = context.bindServiceAsUser(intent,
- keyChainServiceConnection,
- Context.BIND_AUTO_CREATE,
- user);
+ boolean isBound = context.bindService(intent,
+ keyChainServiceConnection,
+ Context.BIND_AUTO_CREATE);
if (!isBound) {
throw new AssertionError("could not bind to KeyChainService");
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 8a7e64288412..7dba21da4c9d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -22,7 +22,6 @@ import android.hardware.ICameraClient;
import android.hardware.ICameraServiceListener;
import android.hardware.IProCameraCallbacks;
import android.hardware.IProCameraUser;
-import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.ICameraDeviceCallbacks;
import android.hardware.camera2.ICameraDeviceUser;
import android.hardware.camera2.impl.CameraMetadataNative;
@@ -51,8 +50,14 @@ import android.util.Log;
* </pre>
*/
public class CameraBinderTest extends AndroidTestCase {
+ private static final int MAX_PARAMETERS_LENGTH = 100;
+
static String TAG = "CameraBinderTest";
+ // From ICameraService.h
+ private static final int API_VERSION_1 = 1;
+ private static final int API_VERSION_2 = 2;
+
protected CameraBinderTestUtils mUtils;
public CameraBinderTest() {
@@ -95,6 +100,56 @@ public class CameraBinderTest extends AndroidTestCase {
}
}
+ @SmallTest
+ public void testGetLegacyParameters() throws Exception {
+ for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+ String[] parameters = new String[1];
+ assertEquals("Camera service returned parameters for camera " + cameraId,
+ CameraBinderTestUtils.NO_ERROR,
+ mUtils.getCameraService().getLegacyParameters(cameraId, /*out*/parameters));
+ assertNotNull(parameters[0]);
+ assertTrue("Parameters should have at least one character in it",
+ parameters[0].length() > 0);
+
+ int end = parameters[0].length();
+ if (end > MAX_PARAMETERS_LENGTH) {
+ end = MAX_PARAMETERS_LENGTH;
+ }
+
+ Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters[0].substring(0, end));
+ }
+ }
+
+ /** The camera2 api is only supported on HAL3.2+ devices */
+ @SmallTest
+ public void testSupportsCamera2Api() throws Exception {
+ for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+ int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
+
+ if (res != CameraBinderTestUtils.NO_ERROR && res != CameraBinderTestUtils.EOPNOTSUPP) {
+ fail("Camera service returned bad value when queried if it supports camera2 api: "
+ + res + " for camera ID " + cameraId);
+ }
+
+ boolean supports = res == CameraBinderTestUtils.NO_ERROR;
+ Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
+ }
+ }
+
+ /** The camera1 api is supported on *all* devices regardless of HAL version */
+ @SmallTest
+ public void testSupportsCamera1Api() throws Exception {
+ for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
+
+ int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
+ assertEquals(
+ "Camera service returned bad value when queried if it supports camera1 api: "
+ + res + " for camera ID " + cameraId, CameraBinderTestUtils.NO_ERROR, res);
+ }
+ }
+
static abstract class DummyBase extends Binder implements android.os.IInterface {
@Override
public IBinder asBinder() {
@@ -158,6 +213,7 @@ public class CameraBinderTest extends AndroidTestCase {
* android.hardware.camera2.ICameraDeviceCallbacks#onCameraError(int,
* android.hardware.camera2.CaptureResultExtras)
*/
+ @Override
public void onCameraError(int errorCode, CaptureResultExtras resultExtras)
throws RemoteException {
// TODO Auto-generated method stub
@@ -170,6 +226,7 @@ public class CameraBinderTest extends AndroidTestCase {
* android.hardware.camera2.ICameraDeviceCallbacks#onCaptureStarted(
* android.hardware.camera2.CaptureResultExtras, long)
*/
+ @Override
public void onCaptureStarted(CaptureResultExtras resultExtras, long timestamp)
throws RemoteException {
// TODO Auto-generated method stub
@@ -183,6 +240,7 @@ public class CameraBinderTest extends AndroidTestCase {
* android.hardware.camera2.impl.CameraMetadataNative,
* android.hardware.camera2.CaptureResultExtras)
*/
+ @Override
public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras)
throws RemoteException {
// TODO Auto-generated method stub
@@ -193,6 +251,7 @@ public class CameraBinderTest extends AndroidTestCase {
* (non-Javadoc)
* @see android.hardware.camera2.ICameraDeviceCallbacks#onCameraIdle()
*/
+ @Override
public void onCameraIdle() throws RemoteException {
// TODO Auto-generated method stub
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
index 1be2a6261fcc..6be538ae3597 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
@@ -22,6 +22,7 @@ public class CameraBinderTestUtils {
protected static final int INVALID_OPERATION = -38;
protected static final int ALREADY_EXISTS = -17;
public static final int NO_ERROR = 0;
+ public static final int EOPNOTSUPP = -95;
private final Context mContext;
public CameraBinderTestUtils(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 20684a131293..5bc23b5e4057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -311,8 +311,27 @@ public abstract class BaseStatusBar extends SystemUI implements
mHandler.post(new Runnable() {
@Override
public void run() {
- if (mNotificationData.findByKey(sbn.getKey()) != null ||
- isHeadsUp(sbn.getKey())) {
+ Notification n = sbn.getNotification();
+ boolean isUpdate = mNotificationData.findByKey(sbn.getKey()) != null
+ || isHeadsUp(sbn.getKey());
+ boolean isGroupedChild = n.getGroup() != null
+ && (n.flags & Notification.FLAG_GROUP_SUMMARY) == 0;
+ if (isGroupedChild) {
+ if (DEBUG) {
+ Log.d(TAG, "Ignoring group child: " + sbn);
+ }
+ // Don't show grouped notifications. If this is an
+ // update, i.e. the notification existed before but
+ // wasn't a group child, remove the old instance.
+ // Otherwise just update the ranking.
+ if (isUpdate) {
+ removeNotificationInternal(sbn.getKey(), rankingMap);
+ } else {
+ updateRankingInternal(rankingMap);
+ }
+ return;
+ }
+ if (isUpdate) {
updateNotificationInternal(sbn, rankingMap);
} else {
addNotificationInternal(sbn, rankingMap);
diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java
index b22aeb7c04b7..4318b9d4d21c 100644
--- a/rs/java/android/renderscript/Font.java
+++ b/rs/java/android/renderscript/Font.java
@@ -111,10 +111,10 @@ public class Font extends BaseObj {
FontFamily serifFamily = new FontFamily();
serifFamily.mNames = sSerifNames;
- serifFamily.mNormalFileName = "DroidSerif-Regular.ttf";
- serifFamily.mBoldFileName = "DroidSerif-Bold.ttf";
- serifFamily.mItalicFileName = "DroidSerif-Italic.ttf";
- serifFamily.mBoldItalicFileName = "DroidSerif-BoldItalic.ttf";
+ serifFamily.mNormalFileName = "NotoSerif-Regular.ttf";
+ serifFamily.mBoldFileName = "NotoSerif-Bold.ttf";
+ serifFamily.mItalicFileName = "NotoSerif-Italic.ttf";
+ serifFamily.mBoldItalicFileName = "NotoSerif-BoldItalic.ttf";
addFamilyToMap(serifFamily);
FontFamily monoFamily = new FontFamily();
diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java
index bcb6e9ee9d68..215d92d8a49b 100644
--- a/services/core/java/com/android/server/MountServiceIdler.java
+++ b/services/core/java/com/android/server/MountServiceIdler.java
@@ -30,8 +30,7 @@ public class MountServiceIdler extends JobService {
private static final String TAG = "MountServiceIdler";
private static ComponentName sIdleService =
- new ComponentName(MountServiceIdler.class.getPackage().getName(),
- MountServiceIdler.class.getName());
+ new ComponentName("android", MountServiceIdler.class.getName());
private static int MOUNT_JOB_ID = 808;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 11f855e2eb46..30446c748308 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import android.app.ActivityManager.TaskDescription;
import android.os.PersistableBundle;
import android.os.Trace;
+
import com.android.internal.app.ResolverActivity;
import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
@@ -49,6 +50,7 @@ import android.util.Slog;
import android.util.TimeUtils;
import android.view.IApplicationToken;
import android.view.WindowManager;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -58,6 +60,7 @@ import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Objects;
/**
* An entry in the history stack, representing an activity.
@@ -83,6 +86,7 @@ final class ActivityRecord {
final ActivityManagerService service; // owner
final IApplicationToken.Stub appToken; // window manager token
final ActivityInfo info; // all about me
+ final ApplicationInfo appInfo; // information about activity's app
final int launchedFromUid; // always the uid who started the activity.
final String launchedFromPackage; // always the package who started the activity.
final int userId; // Which user is this running for?
@@ -103,9 +107,6 @@ final class ActivityRecord {
static final int RECENTS_ACTIVITY_TYPE = 2;
int mActivityType;
- final String baseDir; // where activity source (resources etc) located
- final String resDir; // where public activity source (public resources etc) located
- final String dataDir; // where activity data should go
CharSequence nonLocalizedLabel; // the label information from the package mgr.
int labelRes; // the label information from the package mgr.
int icon; // resource identifier of activity's icon.
@@ -184,11 +185,13 @@ final class ActivityRecord {
pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
pw.print(prefix); pw.print("realActivity=");
pw.println(realActivity.flattenToShortString());
- pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
- if (!resDir.equals(baseDir)) {
- pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+ if (appInfo != null) {
+ pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
+ if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
+ pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
+ }
+ pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
}
- pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
pw.print(" componentSpecified="); pw.print(componentSpecified);
pw.print(" mActivityType="); pw.println(mActivityType);
@@ -418,9 +421,7 @@ final class ActivityRecord {
taskAffinity = aInfo.taskAffinity;
stateNotNeeded = (aInfo.flags&
ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
- baseDir = aInfo.applicationInfo.sourceDir;
- resDir = aInfo.applicationInfo.publicSourceDir;
- dataDir = aInfo.applicationInfo.dataDir;
+ appInfo = aInfo.applicationInfo;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
if (nonLocalizedLabel == null && labelRes == 0) {
@@ -488,9 +489,7 @@ final class ActivityRecord {
realActivity = null;
taskAffinity = null;
stateNotNeeded = false;
- baseDir = null;
- resDir = null;
- dataDir = null;
+ appInfo = null;
processName = null;
packageName = null;
fullscreen = true;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index e54c95ee16fb..f79c02601c4d 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -45,6 +45,7 @@ import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* A running application service.
@@ -70,9 +71,6 @@ final class ServiceRecord extends Binder {
final String packageName; // the package implementing intent's component
final String processName; // process where this component wants to run
final String permission;// permission needed to access service
- final String baseDir; // where activity source (resources etc) located
- final String resDir; // where public activity source (public resources etc) located
- final String dataDir; // where activity data should go
final boolean exported; // from ServiceInfo.exported
final Runnable restarter; // used to schedule retries of starting the service
final long createTime; // when this service was created
@@ -209,11 +207,13 @@ final class ServiceRecord extends Binder {
}
long now = SystemClock.uptimeMillis();
long nowReal = SystemClock.elapsedRealtime();
- pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
- if (!resDir.equals(baseDir)) {
- pw.print(prefix); pw.print("resDir="); pw.println(resDir);
+ if (appInfo != null) {
+ pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
+ if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
+ pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
+ }
+ pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
}
- pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
pw.print(prefix); pw.print("app="); pw.println(app);
if (isolatedProc != null) {
pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
@@ -305,9 +305,6 @@ final class ServiceRecord extends Binder {
packageName = sInfo.applicationInfo.packageName;
processName = sInfo.processName;
permission = sInfo.permission;
- baseDir = sInfo.applicationInfo.sourceDir;
- resDir = sInfo.applicationInfo.publicSourceDir;
- dataDir = sInfo.applicationInfo.dataDir;
exported = sInfo.exported;
this.restarter = restarter;
createTime = SystemClock.elapsedRealtime();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8d943963185f..5feee50bad20 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -42,6 +42,7 @@ import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.NativeLibraryHelper.ApkHandle;
import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -2242,11 +2243,12 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
return null;
}
+ // App code is gone, so we aren't worried about split paths
pkg = new PackageParser.Package(packageName);
pkg.applicationInfo.packageName = packageName;
pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY;
- pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
pkg.applicationInfo.sourceDir = ps.codePathString;
+ pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
pkg.applicationInfo.dataDir =
getDataPathForPackage(packageName, 0).getPath();
pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
@@ -4081,6 +4083,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ // TODO: generate idmap for split APKs
if (mInstaller.idmap(pkg.codePath, opkg.codePath, sharedGid) != 0) {
Slog.e(TAG, "Failed to generate idmap for " + pkg.codePath + " and " + opkg.codePath);
return false;
@@ -4362,23 +4365,30 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- String codePath = null;
+ final String codePath = pkg.codePath;
+ final String[] splitCodePaths = pkg.splitCodePaths;
+
String resPath = null;
+ String[] splitResPaths = null;
if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) {
if (ps != null && ps.resourcePathString != null) {
resPath = ps.resourcePathString;
+ splitResPaths = deriveSplitResPaths(pkg.splitCodePaths);
} else {
// Should not happen at all. Just log an error.
Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
}
} else {
resPath = pkg.codePath;
+ splitResPaths = pkg.splitCodePaths;
}
- codePath = pkg.codePath;
// Set application objects path explicitly.
pkg.applicationInfo.sourceDir = codePath;
pkg.applicationInfo.publicSourceDir = resPath;
+ pkg.applicationInfo.splitSourceDirs = splitCodePaths;
+ pkg.applicationInfo.splitPublicSourceDirs = splitResPaths;
+
// Note that we invoke the following method only if we are about to unpack an application
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode
| SCAN_UPDATE_SIGNATURE, currentTime, user, abiOverride);
@@ -4626,52 +4636,56 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- boolean performed = false;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
- String path = pkg.codePath;
- try {
- boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
- pkg.packageName,
- instructionSet,
- defer);
- // There are three basic cases here:
- // 1.) we need to dexopt, either because we are forced or it is needed
- // 2.) we are defering a needed dexopt
- // 3.) we are skipping an unneeded dexopt
- if (forceDex || (!defer && isDexOptNeededInternal)) {
- Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, instructionSet);
- // Note that we ran dexopt, since rerunning will
- // probably just result in an error again.
- pkg.mDexOptNeeded = false;
- if (ret < 0) {
- return DEX_OPT_FAILED;
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ final ArrayList<String> paths = new ArrayList<>();
+ paths.add(pkg.codePath);
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ Collections.addAll(paths, pkg.splitCodePaths);
+ }
+
+ for (String path : paths) {
+ try {
+ boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
+ pkg.packageName, instructionSet, defer);
+ // There are three basic cases here:
+ // 1.) we need to dexopt, either because we are forced or it is needed
+ // 2.) we are defering a needed dexopt
+ // 3.) we are skipping an unneeded dexopt
+ if (forceDex || (!defer && isDexOptNeededInternal)) {
+ Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
+ pkg.packageName, instructionSet);
+ // Note that we ran dexopt, since rerunning will
+ // probably just result in an error again.
+ pkg.mDexOptNeeded = false;
+ if (ret < 0) {
+ return DEX_OPT_FAILED;
+ }
+ return DEX_OPT_PERFORMED;
}
- return DEX_OPT_PERFORMED;
- }
- if (defer && isDexOptNeededInternal) {
- if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new HashSet<PackageParser.Package>();
+ if (defer && isDexOptNeededInternal) {
+ if (mDeferredDexOpt == null) {
+ mDeferredDexOpt = new HashSet<PackageParser.Package>();
+ }
+ mDeferredDexOpt.add(pkg);
+ return DEX_OPT_DEFERRED;
}
- mDeferredDexOpt.add(pkg);
- return DEX_OPT_DEFERRED;
+ pkg.mDexOptNeeded = false;
+ return DEX_OPT_SKIPPED;
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Apk not found for dexopt: " + path);
+ return DEX_OPT_FAILED;
+ } catch (IOException e) {
+ Slog.w(TAG, "IOException reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (StaleDexCacheError e) {
+ Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+ return DEX_OPT_FAILED;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception when doing dexopt : ", e);
+ return DEX_OPT_FAILED;
}
- pkg.mDexOptNeeded = false;
- return DEX_OPT_SKIPPED;
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Apk not found for dexopt: " + path);
- return DEX_OPT_FAILED;
- } catch (IOException e) {
- Slog.w(TAG, "IOException reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (StaleDexCacheError e) {
- Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
- return DEX_OPT_FAILED;
- } catch (Exception e) {
- Slog.w(TAG, "Exception when doing dexopt : ", e);
- return DEX_OPT_FAILED;
}
}
return DEX_OPT_SKIPPED;
@@ -4819,6 +4833,9 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (p != null) {
usesLibraryFiles.add(p.codePath);
+ if (!ArrayUtils.isEmpty(p.splitCodePaths)) {
+ Collections.addAll(usesLibraryFiles, p.splitCodePaths);
+ }
}
}
@@ -4906,7 +4923,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private PackageParser.Package scanPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) {
final File scanFile = new File(pkg.codePath);
- if (scanFile == null || pkg.applicationInfo.sourceDir == null ||
+ if (pkg.applicationInfo.sourceDir == null ||
pkg.applicationInfo.publicSourceDir == null) {
// Bail out. The resource and code paths haven't been set.
Slog.w(TAG, " Code and resource paths haven't been set correctly");
@@ -5355,6 +5372,7 @@ public class PackageManagerService extends IPackageManager.Stub {
* only for non-system apps and system app upgrades.
*/
if (pkg.applicationInfo.nativeLibraryDir != null) {
+ // TODO: extend to extract native code from split APKs
final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
try {
// Enable gross and lame hacks for apps that are built with old
@@ -5908,6 +5926,8 @@ public class PackageManagerService extends IPackageManager.Stub {
a.info.packageName = pkg.applicationInfo.packageName;
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
+ a.info.splitSourceDirs = pkg.applicationInfo.splitSourceDirs;
+ a.info.splitPublicSourceDirs = pkg.applicationInfo.splitPublicSourceDirs;
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
@@ -9021,6 +9041,10 @@ public class PackageManagerService extends IPackageManager.Stub {
abstract boolean doPostDeleteLI(boolean delete);
abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException;
+ String[] getSplitCodePaths() {
+ return null;
+ }
+
/**
* Called before the source arguments are copied. This is used mostly
* for MoveParams when it needs to read the source file to put it in the
@@ -9109,10 +9133,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- String getCodePath() {
- return codeFileName;
- }
-
void createCopyFile() {
installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
codeFileName = createTempPackageFile(installDir).getPath();
@@ -9268,10 +9288,6 @@ public class PackageManagerService extends IPackageManager.Stub {
return status;
}
- String getResourcePath() {
- return resourceFileName;
- }
-
private String getResourcePathFromCodePath() {
final String codePath = getCodePath();
if (isFwdLocked()) {
@@ -9302,6 +9318,16 @@ public class PackageManagerService extends IPackageManager.Stub {
}
@Override
+ String getCodePath() {
+ return codeFileName;
+ }
+
+ @Override
+ String getResourcePath() {
+ return resourceFileName;
+ }
+
+ @Override
String getNativeLibraryPath() {
if (libraryPath == null) {
libraryPath = getLibraryPathFromCodePath();
@@ -9768,6 +9794,20 @@ public class PackageManagerService extends IPackageManager.Stub {
return codePath.substring(sidx+1, eidx);
}
+ private static String[] deriveSplitResPaths(String[] splitCodePaths) {
+ String[] splitResPaths = null;
+ if (!ArrayUtils.isEmpty(splitCodePaths)) {
+ splitResPaths = new String[splitCodePaths.length];
+ for (int i = 0; i < splitCodePaths.length; i++) {
+ final String splitCodePath = splitCodePaths[i];
+ final String resName = getApkName(splitCodePath) + ".zip";
+ splitResPaths[i] = new File(new File(splitCodePath).getParentFile(),
+ resName).getAbsolutePath();
+ }
+ }
+ return splitResPaths;
+ }
+
class PackageInstalledInfo {
String name;
int uid;
@@ -10067,6 +10107,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// Utility method used to move dex files during install.
private int moveDexFilesLI(String oldCodePath, PackageParser.Package newPackage) {
+ // TODO: extend to move split APK dex files
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
int retCode = mInstaller.movedex(oldCodePath, newPackage.codePath,
@@ -10296,6 +10337,9 @@ public class PackageManagerService extends IPackageManager.Stub {
pkg.codePath = args.getCodePath();
pkg.applicationInfo.sourceDir = args.getCodePath();
pkg.applicationInfo.publicSourceDir = args.getResourcePath();
+ pkg.applicationInfo.splitSourceDirs = args.getSplitCodePaths();
+ pkg.applicationInfo.splitPublicSourceDirs = deriveSplitResPaths(
+ pkg.applicationInfo.splitSourceDirs);
pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 24a998d24e0c..4574caf20322 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1324,7 +1324,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void manageMonitoringCertificateNotification(Intent intent) {
final NotificationManager notificationManager = getNotificationManager();
- final boolean hasCert = !(new TrustedCertificateStore().userAliases().isEmpty());
+ final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
if (! hasCert) {
if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
for (UserInfo user : mUserManager.getUsers()) {
@@ -2384,19 +2384,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return !"".equals(state);
}
- public boolean installCaCert(ComponentName who, byte[] certBuffer) throws RemoteException {
- if (who == null) {
- mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
- } else {
- synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- }
- }
-
+ public boolean installCaCert(byte[] certBuffer) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
+ KeyChainConnection keyChainConnection = null;
byte[] pemCert;
try {
X509Certificate cert = parseCert(certBuffer);
- pemCert = Credentials.convertToPem(cert);
+ pemCert = Credentials.convertToPem(cert);
} catch (CertificateException ce) {
Log.e(LOG_TAG, "Problem converting cert", ce);
return false;
@@ -2404,24 +2398,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Log.e(LOG_TAG, "Problem reading cert", ioe);
return false;
}
-
- final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = Binder.clearCallingIdentity();
try {
- final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
+ keyChainConnection = KeyChain.bind(mContext);
try {
keyChainConnection.getService().installCaCertificate(pemCert);
return true;
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "installCaCertsToKeyChain(): ", e);
} finally {
- keyChainConnection.close();
+ if (keyChainConnection != null) {
+ keyChainConnection.close();
+ keyChainConnection = null;
+ }
}
} catch (InterruptedException e1) {
Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
Thread.currentThread().interrupt();
- } finally {
- Binder.restoreCallingIdentity(id);
}
return false;
}
@@ -2433,31 +2423,34 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
certBuffer));
}
- public void uninstallCaCert(ComponentName who, String alias) {
- if (who == null) {
- mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
- } else {
- synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
- }
+ public void uninstallCaCert(final byte[] certBuffer) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
+ TrustedCertificateStore certStore = new TrustedCertificateStore();
+ String alias = null;
+ try {
+ X509Certificate cert = parseCert(certBuffer);
+ alias = certStore.getCertificateAlias(cert);
+ } catch (CertificateException ce) {
+ Log.e(LOG_TAG, "Problem creating X509Certificate", ce);
+ return;
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "Problem reading certificate", ioe);
+ return;
}
-
- final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
- final long id = Binder.clearCallingIdentity();
try {
- final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
+ KeyChainConnection keyChainConnection = KeyChain.bind(mContext);
+ IKeyChainService service = keyChainConnection.getService();
try {
- keyChainConnection.getService().deleteCaCertificate(alias);
+ service.deleteCaCertificate(alias);
} catch (RemoteException e) {
Log.e(LOG_TAG, "from CaCertUninstaller: ", e);
} finally {
keyChainConnection.close();
+ keyChainConnection = null;
}
} catch (InterruptedException ie) {
Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
Thread.currentThread().interrupt();
- } finally {
- Binder.restoreCallingIdentity(id);
}
}
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
index d97450900a95..8a4e12388c97 100644
--- a/telecomm/java/android/telecomm/ConnectionService.java
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -20,15 +20,9 @@ import android.net.Uri;
import android.os.Bundle;
import android.telephony.DisconnectCause;
-import android.os.SystemClock;
-
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* A {@link android.app.Service} that provides telephone connections to
diff --git a/telecomm/java/android/telecomm/Subscription.aidl b/telecomm/java/android/telecomm/Subscription.aidl
new file mode 100644
index 000000000000..6327fcc15dd8
--- /dev/null
+++ b/telecomm/java/android/telecomm/Subscription.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.telecomm;
+
+/**
+ * {@hide}
+ */
+parcelable Subscription;
diff --git a/telecomm/java/android/telecomm/Subscription.java b/telecomm/java/android/telecomm/Subscription.java
index f187f4d176be..964db4a5c05b 100644
--- a/telecomm/java/android/telecomm/Subscription.java
+++ b/telecomm/java/android/telecomm/Subscription.java
@@ -16,25 +16,169 @@
package android.telecomm;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.Rlog;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import java.util.MissingResourceException;
/**
* Represents a distinct subscription, line of service or call placement method that
- * a {@link ConnectionService} can use to place phone calls.
+ * the system can use to place phone calls.
*/
public class Subscription implements Parcelable {
- public Subscription() {}
+ private static final int NO_DENSITY = -1;
+
+ private static final String LOG_TAG = "Subscription";
+
+ private final ComponentName mComponentName;
+ private final String mId;
+ private final Uri mHandle;
+ private final int mLabelResId;
+ private final int mShortDescriptionResId;
+ private final int mIconResId;
+ private final boolean mIsEnabled;
+ private final boolean mIsSystemDefault;
+
+ public Subscription(
+ ComponentName componentName,
+ String id,
+ Uri handle,
+ int labelResId,
+ int shortDescriptionResId,
+ int iconResId,
+ boolean isEnabled,
+ boolean isSystemDefault) {
+ mComponentName = componentName;
+ mId = id;
+ mHandle = handle;
+ mLabelResId = labelResId;
+ mShortDescriptionResId = shortDescriptionResId;
+ mIconResId = iconResId;
+ mIsSystemDefault = isSystemDefault;
+ mIsEnabled = isEnabled;
+ }
+
+ /**
+ * The {@code ComponentName} of the {@link android.telecomm.ConnectionService} which is
+ * responsible for making phone calls using this {@code Subscription}.
+ *
+ * @return A suitable {@code ComponentName}.
+ */
+ public ComponentName getComponentName() {
+ return mComponentName;
+ }
+
+ /**
+ * A unique identifier for this {@code Subscription}, generated by and meaningful to the
+ * {@link android.telecomm.ConnectionService} that created it.
+ *
+ * @return A unique identifier for this {@code Subscription}.
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * The handle (e.g., a phone number) associated with this {@code Subscription}. This represents
+ * the destination from which outgoing calls using this {@code Subscription} will appear to come
+ * from, if applicable, and the destination to which incoming calls using this
+ * {@code Subscription} may be addressed.
+ *
+ * @return A handle expressed as a {@code Uri}, for example, a phone number.
+ */
+ public Uri getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * A short string label describing this {@code Subscription}.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ *
+ * @return A label for this {@code Subscription}.
+ */
+ public String getLabel(Context context) {
+ return getString(context, mLabelResId);
+ }
+
+ /**
+ * A short paragraph describing this {@code Subscription}.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ *
+ * @return A description for this {@code Subscription}.
+ */
+ public String getShortDescription(Context context) {
+ return getString(context, mShortDescriptionResId);
+ }
+
+ /**
+ * An icon to represent this {@code Subscription} in a user interface.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ *
+ * @return An icon for this {@code Subscription}.
+ */
+ public Drawable getIcon(Context context) {
+ return getIcon(context, mIconResId, NO_DENSITY);
+ }
+
+ /**
+ * An icon to represent this {@code Subscription} in a user interface.
+ *
+ * @param context The invoking {@code Context}, used for retrieving resources.
+ * @param density A display density from {@link DisplayMetrics}.
+ *
+ * @return An icon for this {@code Subscription}.
+ */
+ public Drawable getIcon(Context context, int density) {
+ return getIcon(context, mIconResId, density);
+ }
+
+ /**
+ * Whether this {@code Subscription} is enabled for use.
+ *
+ * @return {@code true} if this {@code Subscription} is enabled.
+ */
+ public boolean isEnabled() {
+ return mIsEnabled;
+ }
+
+ /**
+ * Whether this {@code Subscription} is the system default.
+ *
+ * @return {@code true} if this {@code Subscription} is the system default.
+ */
+ public boolean isSystemDefault() {
+ return mIsSystemDefault;
+ }
public int describeContents() {
return 0;
}
- public void writeToParcel(Parcel out, int flags) {}
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(mComponentName, flags);
+ out.writeString(mId);
+ out.writeString(mHandle != null ? mHandle.toString() : "");
+ out.writeInt(mLabelResId);
+ out.writeInt(mShortDescriptionResId);
+ out.writeInt(mIconResId);
+ out.writeInt(mIsEnabled ? 1 : 0);
+ out.writeInt(mIsSystemDefault ? 1 : 0);
+ }
- public static final Parcelable.Creator<Subscription> CREATOR
- = new Parcelable.Creator<Subscription>() {
+ public static final Creator<Subscription> CREATOR
+ = new Creator<Subscription>() {
public Subscription createFromParcel(Parcel in) {
return new Subscription(in);
}
@@ -44,5 +188,54 @@ public class Subscription implements Parcelable {
}
};
- private Subscription(Parcel in) {}
+ private Subscription(Parcel in) {
+ mComponentName = in.readParcelable(getClass().getClassLoader());
+ mId = in.readString();
+ String uriString = in.readString();
+ mHandle = uriString.length() > 0 ? Uri.parse(uriString) : null;
+ mLabelResId = in.readInt();
+ mShortDescriptionResId = in.readInt();
+ mIconResId = in.readInt();
+ mIsEnabled = in.readInt() == 1;
+ mIsSystemDefault = in.readInt() == 1;
+ }
+
+ private String getString(Context context, int resId) {
+ Context packageContext;
+ try {
+ packageContext = context.createPackageContext(mComponentName.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Rlog.isLoggable(LOG_TAG, Log.WARN)) {
+ Rlog.w(LOG_TAG, "Cannot find package " + mComponentName.getPackageName());
+ }
+ return null;
+ }
+ String result = packageContext.getString(resId);
+ if (result == null && Rlog.isLoggable(LOG_TAG, Log.WARN)) {
+ Rlog.w(LOG_TAG, "Cannot find string " + resId + " in package " +
+ mComponentName.getPackageName());
+ }
+ return result;
+ }
+
+ private Drawable getIcon(Context context, int resId, int density) {
+ Context packageContext;
+ try {
+ packageContext = context.createPackageContext(mComponentName.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Rlog.isLoggable(LOG_TAG, Log.WARN)) {
+ Rlog.w(LOG_TAG, "Cannot find package " + mComponentName.getPackageName());
+ }
+ return null;
+ }
+ try {
+ return density == NO_DENSITY ?
+ packageContext.getResources().getDrawable(resId) :
+ packageContext.getResources().getDrawableForDensity(resId, density);
+ } catch (MissingResourceException e) {
+ Rlog.e(LOG_TAG, "Cannot find icon " + resId + " in package " +
+ mComponentName.getPackageName() + ": " + e.toString());
+ return null;
+ }
+ }
}
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index 638b86aa149c..dc2b8694c66e 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -16,6 +16,7 @@
package com.android.internal.telecomm;
+import android.telecomm.Subscription;
import android.content.ComponentName;
/**
@@ -45,4 +46,19 @@ interface ITelecommService {
* Returns the component name of the phone application installed on the system partition.
*/
ComponentName getSystemPhoneApplication();
+
+ /**
+ * Gets a list of Subscriptions.
+ */
+ List<Subscription> getSubscriptions();
+
+ /**
+ * Sets the enabled state of a given Subscription.
+ */
+ void setEnabled(in Subscription subscription, boolean enabled);
+
+ /**
+ * Sets a given Subscription as the system default.
+ */
+ void setSystemDefault(in Subscription subscription);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 50bbb1edc962..3fde36e9b666 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -19,15 +19,12 @@ package android.telephony;
import android.annotation.SystemApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
-import android.telephony.Rlog;
+import android.telecomm.Subscription;
import android.util.Log;
import com.android.internal.telecomm.ITelecommService;
@@ -40,7 +37,6 @@ import com.android.internal.telephony.TelephonyProperties;
import java.io.FileInputStream;
import java.io.IOException;
-import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -302,6 +298,17 @@ public class TelephonyManager {
public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
/**
+ * The lookup key used with an {@link android.content.Intent#ACTION_CALL} or
+ * {@link android.content.Intent#ACTION_DIAL} {@code Intent} for a {@link Subscription}
+ * object indicating a preference when making a phone connection.
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getParcelableExtra(String)}.
+ */
+ public static final String EXTRA_SUBSCRIPTION = "subscription";
+
+ /**
* Broadcast intent action indicating that a precise call state
* (cellular) on the device has changed.
*
@@ -3112,4 +3119,40 @@ public class TelephonyManager {
}
return false;
}
+
+ /**
+ * Return a list of Subscriptions that can be used to indicate a preference when making
+ * a phone call.
+ *
+ * @see #EXTRA_SUBSCRIPTION
+ * @return A list of {@code Subscription} objects.
+ */
+ public List<Subscription> getSubscriptions() {
+ try {
+ return getTelecommService().getSubscriptions();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#getSubscriptions", e);
+ }
+ return null;
+ }
+
+ /** @hide */
+ @SystemApi
+ public void setEnabled(Subscription subscription, boolean enabled) {
+ try {
+ getTelecommService().setEnabled(subscription, enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setEnabled", e);
+ }
+ }
+
+ /** @hide */
+ @SystemApi
+ public void setSystemDefault(Subscription subscription) {
+ try {
+ getTelecommService().setSystemDefault(subscription);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setSystemDefault", e);
+ }
+ }
}