diff options
82 files changed, 1790 insertions, 984 deletions
diff --git a/api/current.xml b/api/current.xml index 47a8472..89d769e 100644 --- a/api/current.xml +++ b/api/current.xml @@ -4710,7 +4710,7 @@ type="int" transient="false" volatile="false" - value="16843457" + value="16843456" static="true" final="true" deprecated="not deprecated" @@ -5916,6 +5916,17 @@ visibility="public" > </field> +<field name="kraken_resource_pad64" + type="int" + transient="false" + volatile="false" + value="16843457" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="kraken_resource_pad7" type="int" transient="false" @@ -26622,17 +26633,6 @@ visibility="public" > </field> -<field name="FLAG_HIGH_PRIORITY" - type="int" - transient="false" - volatile="false" - value="128" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="FLAG_INSISTENT" type="int" transient="false" @@ -46060,17 +46060,6 @@ visibility="public" > </field> -<field name="FLAG_IMMERSIVE" - type="int" - transient="false" - volatile="false" - value="512" - static="true" - final="true" - deprecated="not deprecated" - visibility="public" -> -</field> <field name="FLAG_MULTIPROCESS" type="int" transient="false" @@ -76089,6 +76078,19 @@ visibility="public" > </method> +<method name="getPreviewFpsRange" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="range" type="int[]"> +</parameter> +</method> <method name="getPreviewFrameRate" return="int" abstract="false" @@ -76096,7 +76098,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </method> @@ -76221,6 +76223,17 @@ visibility="public" > </method> +<method name="getSupportedPreviewFpsRange" + return="java.util.List<int[]>" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getSupportedPreviewFrameRates" return="java.util.List<java.lang.Integer>" abstract="false" @@ -76228,7 +76241,7 @@ synchronized="false" static="false" final="false" - deprecated="not deprecated" + deprecated="deprecated" visibility="public" > </method> @@ -76610,7 +76623,7 @@ <parameter name="pixel_format" type="int"> </parameter> </method> -<method name="setPreviewFrameRate" +<method name="setPreviewFpsRange" return="void" abstract="false" native="false" @@ -76620,6 +76633,21 @@ deprecated="not deprecated" visibility="public" > +<parameter name="min" type="int"> +</parameter> +<parameter name="max" type="int"> +</parameter> +</method> +<method name="setPreviewFrameRate" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="deprecated" + visibility="public" +> <parameter name="fps" type="int"> </parameter> </method> @@ -77033,6 +77061,28 @@ visibility="public" > </field> +<field name="PREVIEW_FPS_MAX_INDEX" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="PREVIEW_FPS_MIN_INDEX" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="SCENE_MODE_ACTION" type="java.lang.String" transient="false" @@ -78424,7 +78474,7 @@ type="float" transient="false" volatile="false" - value="0.001f" + value="0.0010f" static="true" final="true" deprecated="not deprecated" @@ -84043,6 +84093,17 @@ visibility="public" > </field> +<field name="PROVIDERS_CHANGED_ACTION" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.location.PROVIDERS_CHANGED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> </class> <class name="LocationProvider" extends="java.lang.Object" @@ -224842,7 +224903,7 @@ deprecated="not deprecated" visibility="public" > -<parameter name="arg0" type="T"> +<parameter name="t" type="T"> </parameter> </method> </interface> diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 773ff7c..f7a9a18 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -3740,48 +3740,6 @@ public class Activity extends ContextThemeWrapper return null; } - /** - * Bit indicating that this activity is "immersive" and should not be - * interrupted by notifications if possible. - * - * This value is initially set by the manifest property - * <code>android:immersive</code> but may be changed at runtime by - * {@link #setImmersive}. - * - * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE - * @hide - */ - public boolean isImmersive() { - try { - return ActivityManagerNative.getDefault().isImmersive(mToken); - } catch (RemoteException e) { - return false; - } - } - - /** - * Adjust the current immersive mode setting. - * - * Note that changing this value will have no effect on the activity's - * {@link android.content.pm.ActivityInfo} structure; that is, if - * <code>android:immersive</code> is set to <code>true</code> - * in the application's manifest entry for this activity, the {@link - * android.content.pm.ActivityInfo#flags ActivityInfo.flags} member will - * always have its {@link android.content.pm.ActivityInfo#FLAG_IMMERSIVE - * FLAG_IMMERSIVE} bit set. - * - * @see #isImmersive - * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE - * @hide - */ - public void setImmersive(boolean i) { - try { - ActivityManagerNative.getDefault().setImmersive(mToken, i); - } catch (RemoteException e) { - // pass - } - } - // ------------------ Internal API ------------------ final void setParent(Activity parent) { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 1d1b4dc..a180837 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1261,32 +1261,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case IS_IMMERSIVE_TRANSACTION: { - data.enforceInterface(IActivityManager.descriptor); - IBinder token = data.readStrongBinder(); - boolean isit = isImmersive(token); - reply.writeNoException(); - reply.writeInt(isit ? 1 : 0); - return true; - } - - case SET_IMMERSIVE_TRANSACTION: { - data.enforceInterface(IActivityManager.descriptor); - IBinder token = data.readStrongBinder(); - boolean imm = data.readInt() == 1; - setImmersive(token, imm); - reply.writeNoException(); - return true; - } - - case IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION: { - data.enforceInterface(IActivityManager.descriptor); - boolean isit = isTopActivityImmersive(); - reply.writeNoException(); - reply.writeInt(isit ? 1 : 0); - return true; - } - case CRASH_APPLICATION_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int uid = data.readInt(); @@ -2858,46 +2832,6 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } - public void setImmersive(IBinder token, boolean immersive) - throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IActivityManager.descriptor); - data.writeStrongBinder(token); - data.writeInt(immersive ? 1 : 0); - mRemote.transact(SET_IMMERSIVE_TRANSACTION, data, reply, 0); - reply.readException(); - data.recycle(); - reply.recycle(); - } - - public boolean isImmersive(IBinder token) - throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IActivityManager.descriptor); - data.writeStrongBinder(token); - mRemote.transact(IS_IMMERSIVE_TRANSACTION, data, reply, 0); - reply.readException(); - boolean res = reply.readInt() == 1; - data.recycle(); - reply.recycle(); - return res; - } - - public boolean isTopActivityImmersive() - throws RemoteException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - data.writeInterfaceToken(IActivityManager.descriptor); - mRemote.transact(IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION, data, reply, 0); - reply.readException(); - boolean res = reply.readInt() == 1; - data.recycle(); - reply.recycle(); - return res; - } - public void crashApplication(int uid, int initialPid, String packageName, String message) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 084f637..ca6fc8a 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3181,6 +3181,7 @@ public final class ActivityThread { instrApp.sourceDir = ii.sourceDir; instrApp.publicSourceDir = ii.publicSourceDir; instrApp.dataDir = ii.dataDir; + instrApp.nativeLibraryDir = ii.nativeLibraryDir; LoadedApk pi = getPackageInfo(instrApp, appContext.getClassLoader(), false, true); ContextImpl instrContext = new ContextImpl(); diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 2e301c9..9e3cd7e 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -19,6 +19,7 @@ package android.app; import dalvik.system.PathClassLoader; import java.util.HashMap; +import java.util.Map; class ApplicationLoaders { @@ -27,8 +28,7 @@ class ApplicationLoaders return gApplicationLoaders; } - public ClassLoader getClassLoader(String zip, String appDataDir, - ClassLoader parent) + public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent) { /* * This is the parent we use if they pass "null" in. In theory @@ -49,13 +49,13 @@ class ApplicationLoaders * new ClassLoader for the zip archive. */ if (parent == baseParent) { - ClassLoader loader = (ClassLoader)mLoaders.get(zip); + ClassLoader loader = mLoaders.get(zip); if (loader != null) { return loader; } PathClassLoader pathClassloader = - new PathClassLoader(zip, appDataDir + "/lib", parent); + new PathClassLoader(zip, libPath, parent); mLoaders.put(zip, pathClassloader); return pathClassloader; @@ -65,7 +65,7 @@ class ApplicationLoaders } } - private final HashMap mLoaders = new HashMap(); + private final Map<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 664cf18..f9bd461 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -311,10 +311,6 @@ public interface IActivityManager extends IInterface { public void finishHeavyWeightApp() throws RemoteException; - public void setImmersive(IBinder token, boolean immersive) throws RemoteException; - public boolean isImmersive(IBinder token) throws RemoteException; - public boolean isTopActivityImmersive() throws RemoteException; - public void crashApplication(int uid, int initialPid, String packageName, String message) throws RemoteException; diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 0f98152..0644f96 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -72,6 +72,7 @@ final class LoadedApk { private final String mResDir; private final String[] mSharedLibraries; private final String mDataDir; + private final String mLibDir; private final File mDataDirFile; private final ClassLoader mBaseClassLoader; private final boolean mSecurityViolation; @@ -108,6 +109,7 @@ final class LoadedApk { mSharedLibraries = aInfo.sharedLibraryFiles; mDataDir = aInfo.dataDir; mDataDirFile = mDataDir != null ? new File(mDataDir) : null; + mLibDir = aInfo.nativeLibraryDir; mBaseClassLoader = baseLoader; mSecurityViolation = securityViolation; mIncludeCode = includeCode; @@ -140,6 +142,7 @@ final class LoadedApk { mSharedLibraries = null; mDataDir = null; mDataDirFile = null; + mLibDir = null; mBaseClassLoader = null; mSecurityViolation = false; mIncludeCode = true; @@ -279,11 +282,12 @@ final class LoadedApk { * create the class loader. */ - if (ActivityThread.localLOGV) Slog.v(ActivityThread.TAG, "Class path: " + zip); + if (ActivityThread.localLOGV) + Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + mLibDir); mClassLoader = ApplicationLoaders.getDefault().getClassLoader( - zip, mDataDir, mBaseClassLoader); + zip, mLibDir, mBaseClassLoader); initializeJavaContextClassLoader(); } else { if (mBaseClassLoader == null) { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 83a2024..5525ce3 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -112,8 +112,6 @@ public class Notification implements Parcelable * An intent to launch instead of posting the notification to the status bar. Only for use with * extremely high-priority notifications demanding the user's attention, such as an incoming * call (handled in the core Android Phone app with a full-screen Activity). - * Use with {@link #FLAG_HIGH_PRIORITY} to ensure that this notification will reach the user - * even when other notifications are suppressed. */ public PendingIntent fullScreenIntent; @@ -273,14 +271,6 @@ public class Notification implements Parcelable */ public static final int FLAG_FOREGROUND_SERVICE = 0x00000040; - /** - * Bit to be bitwise-ored into the {@link #flags} field that should be set if this notification - * represents a high-priority event that may be shown to the user even if notifications are - * otherwise unavailable (that is, when the status bar is hidden). This flag is ideally used - * in conjunction with {@link #fullScreenIntent}. - */ - public static final int FLAG_HIGH_PRIORITY = 0x00000080; - public int flags; /** @@ -549,9 +539,6 @@ public class Notification implements Parcelable sb.append(Integer.toHexString(this.defaults)); sb.append(",flags=0x"); sb.append(Integer.toHexString(this.flags)); - if ((this.flags & FLAG_HIGH_PRIORITY) != 0) { - sb.append("!!!1!one!"); - } sb.append(")"); return sb.toString(); } diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 364c91e..395c392 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -149,22 +149,6 @@ public class ActivityInfo extends ComponentInfo * {@link android.R.attr#finishOnCloseSystemDialogs} attribute. */ public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 0x0100; - /** - * Bit in {@link #flags} corresponding to an immersive activity - * that wishes not to be interrupted by notifications. - * Applications that hide the system notification bar with - * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN} - * may still be interrupted by high-priority notifications; for example, an - * incoming phone call may use - * {@link android.app.Notification#fullScreenIntent fullScreenIntent} - * to present a full-screen in-call activity to the user, pausing the - * current activity as a side-effect. An activity with - * {@link #FLAG_IMMERSIVE} set, however, will not be interrupted; the - * notification may be shown in some other way (such as a small floating - * "toast" window). - * {@see android.app.Notification#FLAG_HIGH_PRIORITY} - */ - public static final int FLAG_IMMERSIVE = 0x0200; /** * Options that have been set in the activity declaration in the * manifest. @@ -175,7 +159,6 @@ public class ActivityInfo extends ComponentInfo * {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS}, * {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY}, * {@link #FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS}, - * {@link #FLAG_IMMERSIVE} */ public int flags; diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index c812f36..ae6a311 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -291,14 +291,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_FORWARD_LOCK = 1<<29; /** - * Value for {@link #flags}: Set to true if the application is - * native-debuggable, i.e. embeds a gdbserver binary in its .apk - * - * {@hide} - */ - public static final int FLAG_NATIVE_DEBUGGABLE = 1<<28; - - /** * Value for {@link #flags}: set to <code>true</code> if the application * has reported that it is heavy-weight, and thus can not participate in * the normal application lifecycle. @@ -359,7 +351,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * data. */ public String dataDir; - + + /** + * Full path to the directory where native JNI libraries are stored. + * + * {@hide} + */ + public String nativeLibraryDir; + /** * The kernel user-ID that has been assigned to this application; * currently this is not a unique ID (multiple applications can have @@ -452,6 +451,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { flags = orig.flags; sourceDir = orig.sourceDir; publicSourceDir = orig.publicSourceDir; + nativeLibraryDir = orig.nativeLibraryDir; resourceDirs = orig.resourceDirs; sharedLibraryFiles = orig.sharedLibraryFiles; dataDir = orig.dataDir; @@ -483,6 +483,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(flags); dest.writeString(sourceDir); dest.writeString(publicSourceDir); + dest.writeString(nativeLibraryDir); dest.writeStringArray(resourceDirs); dest.writeStringArray(sharedLibraryFiles); dest.writeString(dataDir); @@ -514,6 +515,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { flags = source.readInt(); sourceDir = source.readString(); publicSourceDir = source.readString(); + nativeLibraryDir = source.readString(); resourceDirs = source.readStringArray(); sharedLibraryFiles = source.readStringArray(); dataDir = source.readString(); diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java index 3e868a7..ea47e8e 100644 --- a/core/java/android/content/pm/InstrumentationInfo.java +++ b/core/java/android/content/pm/InstrumentationInfo.java @@ -50,7 +50,14 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { * data. */ public String dataDir; - + + /** + * Full path to the directory where the native JNI libraries are stored. + * + * {@hide} + */ + public String nativeLibraryDir; + /** * Specifies whether or not this instrumentation will handle profiling. */ @@ -68,6 +75,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { sourceDir = orig.sourceDir; publicSourceDir = orig.publicSourceDir; dataDir = orig.dataDir; + nativeLibraryDir = orig.nativeLibraryDir; handleProfiling = orig.handleProfiling; functionalTest = orig.functionalTest; } @@ -88,6 +96,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { dest.writeString(sourceDir); dest.writeString(publicSourceDir); dest.writeString(dataDir); + dest.writeString(nativeLibraryDir); dest.writeInt((handleProfiling == false) ? 0 : 1); dest.writeInt((functionalTest == false) ? 0 : 1); } @@ -108,6 +117,7 @@ public class InstrumentationInfo extends PackageItemInfo implements Parcelable { sourceDir = source.readString(); publicSourceDir = source.readString(); dataDir = source.readString(); + nativeLibraryDir = source.readString(); handleProfiling = source.readInt() != 0; functionalTest = source.readInt() != 0; } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 2a39dc0..e20cb5e 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1883,12 +1883,6 @@ public class PackageParser { a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS; } - if (sa.getBoolean( - com.android.internal.R.styleable.AndroidManifestActivity_immersive, - false)) { - a.info.flags |= ActivityInfo.FLAG_IMMERSIVE; - } - if (!receiver) { a.info.launchMode = sa.getInt( com.android.internal.R.styleable.AndroidManifestActivity_launchMode, diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index e432a47..21cb3a8 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -1224,7 +1224,6 @@ public class Camera { * The array index of minimum preview fps for use with {@link * #getPreviewFpsRange(int[])} or {@link * #getSupportedPreviewFpsRange()}. - * @hide */ public static final int PREVIEW_FPS_MIN_INDEX = 0; @@ -1232,7 +1231,6 @@ public class Camera { * The array index of maximum preview fps for use with {@link * #getPreviewFpsRange(int[])} or {@link * #getSupportedPreviewFpsRange()}. - * @hide */ public static final int PREVIEW_FPS_MAX_INDEX = 1; @@ -1471,7 +1469,9 @@ public class Camera { * target frame rate. The actual frame rate depends on the driver. * * @param fps the frame rate (frames per second) + * @deprecated replaced by {@link #setPreviewFpsRange(int,int)} */ + @Deprecated public void setPreviewFrameRate(int fps) { set(KEY_PREVIEW_FRAME_RATE, fps); } @@ -1482,7 +1482,9 @@ public class Camera { * depends on the driver. * * @return the frame rate setting (frames per second) + * @deprecated replaced by {@link #getPreviewFpsRange(int[])} */ + @Deprecated public int getPreviewFrameRate() { return getInt(KEY_PREVIEW_FRAME_RATE); } @@ -1492,7 +1494,9 @@ public class Camera { * * @return a list of supported preview frame rates. null if preview * frame rate setting is not supported. + * @deprecated replaced by {@link #getSupportedPreviewFpsRange()} */ + @Deprecated public List<Integer> getSupportedPreviewFrameRates() { String str = get(KEY_PREVIEW_FRAME_RATE + SUPPORTED_VALUES_SUFFIX); return splitInt(str); @@ -1500,7 +1504,7 @@ public class Camera { /** * Sets the maximum and maximum preview fps. This controls the rate of - * preview frames received in {@link #PreviewCallback}. The minimum and + * preview frames received in {@link PreviewCallback}. The minimum and * maximum preview fps must be one of the elements from {@link * #getSupportedPreviewFpsRange}. * @@ -1509,7 +1513,6 @@ public class Camera { * @throws RuntimeException if fps range is invalid. * @see #setPreviewCallbackWithBuffer(Camera.PreviewCallback) * @see #getSupportedPreviewFpsRange() - * @hide */ public void setPreviewFpsRange(int min, int max) { set(KEY_PREVIEW_FPS_RANGE, "" + min + "," + max); @@ -1523,12 +1526,11 @@ public class Camera { * @see #PREVIEW_FPS_MIN_INDEX * @see #PREVIEW_FPS_MAX_INDEX * @see #getSupportedPreviewFpsRange() - * @hide */ public void getPreviewFpsRange(int[] range) { if (range == null || range.length != 2) { throw new IllegalArgumentException( - "range must be an float array with two elements."); + "range must be an array with two elements."); } splitInt(get(KEY_PREVIEW_FPS_RANGE), range); } @@ -1549,7 +1551,6 @@ public class Camera { * minimum fps). * @see #PREVIEW_FPS_MIN_INDEX * @see #PREVIEW_FPS_MAX_INDEX - * @hide */ public List<int[]> getSupportedPreviewFpsRange() { String str = get(KEY_PREVIEW_FPS_RANGE + SUPPORTED_VALUES_SUFFIX); diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java index cdcb662..e5eeb8c 100644 --- a/core/java/android/webkit/PluginManager.java +++ b/core/java/android/webkit/PluginManager.java @@ -21,9 +21,9 @@ import java.util.List; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.app.Service; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -59,7 +59,9 @@ public class PluginManager { */ public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN"; - private static final String LOGTAG = "webkit"; + private static final String LOGTAG = "PluginManager"; + + private static final String PLUGIN_SYSTEM_LIB = "/system/lib/plugins/"; private static final String PLUGIN_TYPE = "type"; private static final String TYPE_NATIVE = "native"; @@ -111,9 +113,8 @@ public class PluginManager { ArrayList<String> directories = new ArrayList<String>(); PackageManager pm = mContext.getPackageManager(); - List<ResolveInfo> plugins = pm.queryIntentServices(new Intent( - PLUGIN_ACTION), PackageManager.GET_SERVICES - | PackageManager.GET_META_DATA); + List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION), + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); synchronized(mPackageInfoCache) { @@ -143,10 +144,19 @@ public class PluginManager { continue; } - // check if their is a conflict in the lib directory names + /* + * find the location of the plugin's shared library. The default + * is to assume the app is either a user installed app or an + * updated system app. In both of these cases the library is + * stored in the app's data directory. + */ String directory = pkgInfo.applicationInfo.dataDir + "/lib"; - if (directories.contains(directory)) { - continue; + final int appFlags = pkgInfo.applicationInfo.flags; + final int updatedSystemFlags = ApplicationInfo.FLAG_SYSTEM | + ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; + // preloaded system app with no user updates + if ((appFlags & updatedSystemFlags) == ApplicationInfo.FLAG_SYSTEM) { + directory = PLUGIN_SYSTEM_LIB + pkgInfo.packageName; } // check if the plugin has the required permissions @@ -236,7 +246,7 @@ public class PluginManager { // must be synchronized to ensure the consistency of the cache synchronized(mPackageInfoCache) { for (PackageInfo pkgInfo : mPackageInfoCache) { - if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) { + if (pluginLib.contains(pkgInfo.packageName)) { return pkgInfo.packageName; } } diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java new file mode 100644 index 0000000..8b618c7 --- /dev/null +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -0,0 +1,296 @@ +package com.android.internal.content; + +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.FileUtils; +import android.os.SystemProperties; +import android.util.Config; +import android.util.Log; +import android.util.Pair; +import android.util.Slog; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +/** + * Native libraries helper. + * + * @hide + */ +public class NativeLibraryHelper { + private static final String TAG = "NativeHelper"; + + private static final boolean DEBUG_NATIVE = false; + + /* + * The following constants are returned by listPackageSharedLibsForAbiLI + * to indicate if native shared libraries were found in the package. + * Values are: + * PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed + * PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package + * PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found + * in package (and not installed) + * + */ + private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0; + private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1; + private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2; + + // Directory in the APK that holds all the native shared libraries. + private static final String APK_LIB = "lib/"; + private static final int APK_LIB_LENGTH = APK_LIB.length(); + + // Prefix that native shared libraries must have. + private static final String LIB_PREFIX = "lib"; + private static final int LIB_PREFIX_LENGTH = LIB_PREFIX.length(); + + // Suffix that the native shared libraries must have. + private static final String LIB_SUFFIX = ".so"; + private static final int LIB_SUFFIX_LENGTH = LIB_SUFFIX.length(); + + // Name of the GDB binary. + private static final String GDBSERVER = "gdbserver"; + + // the minimum length of a valid native shared library of the form + // lib/<something>/lib<name>.so. + private static final int MIN_ENTRY_LENGTH = APK_LIB_LENGTH + 2 + LIB_PREFIX_LENGTH + 1 + + LIB_SUFFIX_LENGTH; + + /* + * Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk + * and add them to a list to be installed later. + * + * NOTE: this method may throw an IOException if the library cannot + * be copied to its final destination, e.g. if there isn't enough + * room left on the data partition, or a ZipException if the package + * file is malformed. + */ + private static int listPackageSharedLibsForAbiLI(ZipFile zipFile, + String cpuAbi, List<Pair<ZipEntry, String>> libEntries) throws IOException, + ZipException { + final int cpuAbiLen = cpuAbi.length(); + boolean hasNativeLibraries = false; + boolean installedNativeLibraries = false; + + if (DEBUG_NATIVE) { + Slog.d(TAG, "Checking " + zipFile.getName() + " for shared libraries of CPU ABI type " + + cpuAbi); + } + + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + + // skip directories + if (entry.isDirectory()) { + continue; + } + String entryName = entry.getName(); + + /* + * Check that the entry looks like lib/<something>/lib<name>.so + * here, but don't check the ABI just yet. + * + * - must be sufficiently long + * - must end with LIB_SUFFIX, i.e. ".so" + * - must start with APK_LIB, i.e. "lib/" + */ + if (entryName.length() < MIN_ENTRY_LENGTH || !entryName.endsWith(LIB_SUFFIX) + || !entryName.startsWith(APK_LIB)) { + continue; + } + + // file name must start with LIB_PREFIX, i.e. "lib" + int lastSlash = entryName.lastIndexOf('/'); + + if (lastSlash < 0 + || !entryName.regionMatches(lastSlash + 1, LIB_PREFIX, 0, LIB_PREFIX_LENGTH)) { + continue; + } + + hasNativeLibraries = true; + + // check the cpuAbi now, between lib/ and /lib<name>.so + if (lastSlash != APK_LIB_LENGTH + cpuAbiLen + || !entryName.regionMatches(APK_LIB_LENGTH, cpuAbi, 0, cpuAbiLen)) + continue; + + /* + * Extract the library file name, ensure it doesn't contain + * weird characters. we're guaranteed here that it doesn't contain + * a directory separator though. + */ + String libFileName = entryName.substring(lastSlash+1); + if (!FileUtils.isFilenameSafe(new File(libFileName))) { + continue; + } + + installedNativeLibraries = true; + + if (DEBUG_NATIVE) { + Log.d(TAG, "Caching shared lib " + entry.getName()); + } + + libEntries.add(Pair.create(entry, libFileName)); + } + if (!hasNativeLibraries) + return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; + + if (!installedNativeLibraries) + return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH; + + return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; + } + + /* + * Find the gdbserver executable program in a package at + * lib/<cpuAbi>/gdbserver and add it to the list of binaries + * to be copied out later. + * + * Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success, + * or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise. + */ + private static int listPackageGdbServerLI(ZipFile zipFile, String cpuAbi, + List<Pair<ZipEntry, String>> nativeFiles) throws IOException, ZipException { + final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER; + + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + // skip directories + if (entry.isDirectory()) { + continue; + } + String entryName = entry.getName(); + + if (!entryName.equals(apkGdbServerPath)) { + continue; + } + + if (Config.LOGD) { + Log.d(TAG, "Found gdbserver: " + entry.getName()); + } + + final String installGdbServerPath = APK_LIB + GDBSERVER; + nativeFiles.add(Pair.create(entry, installGdbServerPath)); + + return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; + } + return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; + } + + /* + * Examine shared libraries stored in the APK as + * lib/<cpuAbi>/lib<name>.so and add them to a list to be copied + * later. + * + * This function will first try the main CPU ABI defined by Build.CPU_ABI + * (which corresponds to ro.product.cpu.abi), and also try an alternate + * one if ro.product.cpu.abi2 is defined. + */ + public static int listPackageNativeBinariesLI(ZipFile zipFile, + List<Pair<ZipEntry, String>> nativeFiles) throws ZipException, IOException { + String cpuAbi = Build.CPU_ABI; + + int result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi, nativeFiles); + + /* + * Some architectures are capable of supporting several CPU ABIs + * for example, 'armeabi-v7a' also supports 'armeabi' native code + * this is indicated by the definition of the ro.product.cpu.abi2 + * system property. + * + * only scan the package twice in case of ABI mismatch + */ + if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { + final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2", null); + if (cpuAbi2 != null) { + result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi2, nativeFiles); + } + + if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { + Slog.w(TAG, "Native ABI mismatch from package file"); + return PackageManager.INSTALL_FAILED_INVALID_APK; + } + + if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { + cpuAbi = cpuAbi2; + } + } + + /* + * Debuggable packages may have gdbserver embedded, so add it to + * the list to the list of items to be extracted (as lib/gdbserver) + * into the application's native library directory later. + */ + if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { + listPackageGdbServerLI(zipFile, cpuAbi, nativeFiles); + } + return PackageManager.INSTALL_SUCCEEDED; + } + + public static int copyNativeBinariesLI(File scanFile, File sharedLibraryDir) { + /* + * Check all the native files that need to be copied and add + * that to the container size. + */ + ZipFile zipFile; + try { + zipFile = new ZipFile(scanFile); + + List<Pair<ZipEntry, String>> nativeFiles = new LinkedList<Pair<ZipEntry, String>>(); + + NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + + final int N = nativeFiles.size(); + + for (int i = 0; i < N; i++) { + final Pair<ZipEntry, String> entry = nativeFiles.get(i); + + File destFile = new File(sharedLibraryDir, entry.second); + copyNativeBinaryLI(zipFile, entry.first, sharedLibraryDir, destFile); + } + } catch (ZipException e) { + Slog.w(TAG, "Failed to extract data from package file", e); + return PackageManager.INSTALL_FAILED_INVALID_APK; + } catch (IOException e) { + Slog.w(TAG, "Failed to cache package shared libs", e); + return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } + + return PackageManager.INSTALL_SUCCEEDED; + } + + private static void copyNativeBinaryLI(ZipFile zipFile, ZipEntry entry, + File binaryDir, File binaryFile) throws IOException { + InputStream inputStream = zipFile.getInputStream(entry); + try { + File tempFile = File.createTempFile("tmp", "tmp", binaryDir); + String tempFilePath = tempFile.getPath(); + // XXX package manager can't change owner, so the executable files for + // now need to be left as world readable and owned by the system. + if (!FileUtils.copyToFile(inputStream, tempFile) + || !tempFile.setLastModified(entry.getTime()) + || FileUtils.setPermissions(tempFilePath, FileUtils.S_IRUSR | FileUtils.S_IWUSR + | FileUtils.S_IRGRP | FileUtils.S_IXUSR | FileUtils.S_IXGRP + | FileUtils.S_IXOTH | FileUtils.S_IROTH, -1, -1) != 0 + || !tempFile.renameTo(binaryFile)) { + // Failed to properly write file. + tempFile.delete(); + throw new IOException("Couldn't create cached binary " + binaryFile + " in " + + binaryDir); + } + } finally { + inputStream.close(); + } + } +} diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java index 4d0a9e0..d6c43f9 100644 --- a/core/java/com/android/internal/content/PackageHelper.java +++ b/core/java/com/android/internal/content/PackageHelper.java @@ -56,22 +56,22 @@ public class PackageHelper { return null; } - public static String createSdDir(File tmpPackageFile, String cid, + public static String createSdDir(long sizeBytes, String cid, String sdEncKey, int uid) { // Create mount point via MountService IMountService mountService = getMountService(); - long len = tmpPackageFile.length(); - int mbLen = (int) (len >> 20); - if ((len - (mbLen * 1024 * 1024)) > 0) { - mbLen++; + int sizeMb = (int) (sizeBytes >> 20); + if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) { + sizeMb++; } // Add buffer size - mbLen++; - if (localLOGV) Log.i(TAG, "Size of container " + mbLen + " MB " + len + " bytes"); + sizeMb++; + if (localLOGV) + Log.i(TAG, "Size of container " + sizeMb + " MB " + sizeBytes + " bytes"); try { int rc = mountService.createSecureContainer( - cid, mbLen, "fat", sdEncKey, uid); + cid, sizeMb, "fat", sdEncKey, uid); if (rc != StorageResultCode.OperationSucceeded) { Log.e(TAG, "Failed to create secure container " + cid); return null; diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 245643b..7942c56 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Vybrat vše"</string> - <string name="selectText" msgid="3889149123626888637">"Označit text"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Zastavit označování textu"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Vyjmout"</string> <string name="copy" msgid="2681946229533511987">"Kopírovat"</string> <string name="paste" msgid="5629880836805036433">"Vložit"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index e7e8019..bab18f2 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Vælg alle"</string> - <string name="selectText" msgid="3889149123626888637">"Marker tekst"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Hold op med at markere tekst"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Klip"</string> <string name="copy" msgid="2681946229533511987">"Kopier"</string> <string name="paste" msgid="5629880836805036433">"Indsæt"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index edbe4c4..c20aa16 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Alles auswählen"</string> - <string name="selectText" msgid="3889149123626888637">"Text auswählen"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Textauswahl beenden"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Ausschneiden"</string> <string name="copy" msgid="2681946229533511987">"Kopieren"</string> <string name="paste" msgid="5629880836805036433">"Einfügen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index cfa36d2..ab29601 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Επιλογή όλων"</string> - <string name="selectText" msgid="3889149123626888637">"Επιλογή κειμένου"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Διακοπή επιλογής κειμένου"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Αποκοπή"</string> <string name="copy" msgid="2681946229533511987">"Αντιγραφή"</string> <string name="paste" msgid="5629880836805036433">"Επικόλληση"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index dbf32b6..fce56cd 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar todos"</string> - <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Detener la selección de texto"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Pegar"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 425fca3..4fdaf3c 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar todo"</string> - <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Detener selección de texto"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Pegar"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 2dacb30..9f0fa0b 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Tout sélectionner"</string> - <string name="selectText" msgid="3889149123626888637">"Sélectionner le texte"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Arrêter sélection de texte"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Couper"</string> <string name="copy" msgid="2681946229533511987">"Copier"</string> <string name="paste" msgid="5629880836805036433">"Coller"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index c7aac82..4731f39 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleziona tutto"</string> - <string name="selectText" msgid="3889149123626888637">"Seleziona testo"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Termina selezione testo"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Taglia"</string> <string name="copy" msgid="2681946229533511987">"Copia"</string> <string name="paste" msgid="5629880836805036433">"Incolla"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 25e977d..a9613f4 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"すべて選択"</string> - <string name="selectText" msgid="3889149123626888637">"テキストを選択"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"テキストの選択を終了"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"切り取り"</string> <string name="copy" msgid="2681946229533511987">"コピー"</string> <string name="paste" msgid="5629880836805036433">"貼り付け"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index faf589e..d6ab5ad 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"모두 선택"</string> - <string name="selectText" msgid="3889149123626888637">"텍스트 선택"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"텍스트 선택 중지"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"잘라내기"</string> <string name="copy" msgid="2681946229533511987">"복사"</string> <string name="paste" msgid="5629880836805036433">"붙여넣기"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 2c23d53..021b20e 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Merk alt"</string> - <string name="selectText" msgid="3889149123626888637">"Merk tekst"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Slutt å merke tekst"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Klipp ut"</string> <string name="copy" msgid="2681946229533511987">"Kopier"</string> <string name="paste" msgid="5629880836805036433">"Lim inn"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 10a8e74..a74db2b 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Alles selecteren"</string> - <string name="selectText" msgid="3889149123626888637">"Tekst selecteren"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Stoppen met tekst selecteren"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Knippen"</string> <string name="copy" msgid="2681946229533511987">"Kopiëren"</string> <string name="paste" msgid="5629880836805036433">"Plakken"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 70c3170..f5ed50c 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Zaznacz wszystko"</string> - <string name="selectText" msgid="3889149123626888637">"Zaznacz tekst"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Zatrzymaj wybieranie tekstu"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Wytnij"</string> <string name="copy" msgid="2681946229533511987">"Kopiuj"</string> <string name="paste" msgid="5629880836805036433">"Wklej"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 9a8c6e9..7914a3d 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Seleccionar tudo"</string> - <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Parar selecção de texto"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Cortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Colar"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 2119539..c9c792e 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string> - <string name="selectText" msgid="3889149123626888637">"Selecionar texto"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Parar seleção de texto"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Recortar"</string> <string name="copy" msgid="2681946229533511987">"Copiar"</string> <string name="paste" msgid="5629880836805036433">"Colar"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index a99107e..786571b 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Выбрать все"</string> - <string name="selectText" msgid="3889149123626888637">"Выбрать текст"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Остановить выделение текста"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Вырезать"</string> <string name="copy" msgid="2681946229533511987">"Копировать"</string> <string name="paste" msgid="5629880836805036433">"Вставить"</string> @@ -782,11 +782,11 @@ <string name="perms_hide" msgid="7283915391320676226"><b>"Скрыть"</b></string> <string name="perms_show_all" msgid="2671791163933091180"><b>"Показать все"</b></string> <string name="usb_storage_activity_title" msgid="2399289999608900443">"Запоминающее устройство USB"</string> - <string name="usb_storage_title" msgid="5901459041398751495">"устройство USB подключено"</string> + <string name="usb_storage_title" msgid="5901459041398751495">"USB-подключение установлено"</string> <string name="usb_storage_message" msgid="4796759646167247178">"Телефон подключен к компьютеру через порт USB. Нажмите кнопку ниже, если необходимо копировать файлы с компьютера на SD-карту устройства Android (или наоборот)."</string> <string name="usb_storage_button_mount" msgid="1052259930369508235">"Включить USB-накопитель"</string> <string name="usb_storage_error_message" msgid="2534784751603345363">"При использовании SD-карты как USB-накопителя возникла неполадка."</string> - <string name="usb_storage_notification_title" msgid="8175892554757216525">"устройство USB подключено"</string> + <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-подключение установлено"</string> <string name="usb_storage_notification_message" msgid="7380082404288219341">"Выберите копирование файлов на компьютер или с компьютера."</string> <string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Выключить USB-накопитель"</string> <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Выберите, чтобы выключить USB-накопитель."</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index b3e415d..8a115697 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string> - <string name="selectText" msgid="3889149123626888637">"Markera text"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Sluta välja text"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Klipp ut"</string> <string name="copy" msgid="2681946229533511987">"Kopiera"</string> <string name="paste" msgid="5629880836805036433">"Klistra in"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index a6bc41e..b45d5bb 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"Tümünü seç"</string> - <string name="selectText" msgid="3889149123626888637">"Metin seç"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"Metin seçmeyi durdur"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"Kes"</string> <string name="copy" msgid="2681946229533511987">"Kopyala"</string> <string name="paste" msgid="5629880836805036433">"Yapıştır"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index aa3f12d..88c38e5 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"全选"</string> - <string name="selectText" msgid="3889149123626888637">"选择文字"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"停止选择文字"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"剪切"</string> <string name="copy" msgid="2681946229533511987">"复制"</string> <string name="paste" msgid="5629880836805036433">"粘贴"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 5bf0342..7d3c27a 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -703,8 +703,8 @@ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string> <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="6876518925844129331">"全部選取"</string> - <string name="selectText" msgid="3889149123626888637">"選取文字"</string> - <string name="stopSelectingText" msgid="4157931463872320996">"停止選取文字"</string> + <!-- no translation found for selectText (4862359311088898878) --> + <skip /> <string name="cut" msgid="3092569408438626261">"剪下"</string> <string name="copy" msgid="2681946229533511987">"複製"</string> <string name="paste" msgid="5629880836805036433">"貼上"</string> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 5b7e88f..3af12b7 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1250,8 +1250,7 @@ <public type="attr" name="logo" id="0x010102be" /> <public type="attr" name="xlargeScreens" id="0x010102bf" /> - <public type="attr" name="cantSaveState" id="0x010102c0" /> - <public type="attr" name="immersive" id="0x010102c1" /> + <public type="attr" name="immersive" id="0x010102c0" /> <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" /> <public-padding type="id" name="kraken_resource_pad" end="0x01020040" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 09fc0f0..03b721c 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1853,7 +1853,7 @@ <!-- Item on EditText context menu. This action is used to select all text in the edit field. --> <string name="selectAll">Select all</string> - <!-- Item on EditText context menu. This action is used to start selecting text in the edit field. --> + <!-- Item on EditText context menu. This action is used to start selecting text in the edit field. [CHAR LIMIT=20] --> <string name="selectText">Select word</string> <!-- Item on EditText context menu. This action is used to cut selected the text into the clipboard. --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 02a601a..af04117 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -88,13 +88,6 @@ <item name="windowExitAnimation">@anim/status_bar_exit</item> </style> - <!-- {@hide} --> - <style name="Animation.StatusBar.IntruderAlert" - parent="@android:style/Animation.StatusBar"> - <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item> - <item name="android:windowExitAnimation">@anim/priority_alert_exit</item> - </style> - <!-- Standard animations for a translucent window or activity. This style is <em>not<em> used by default for the translucent theme (since translucent activities are a special case that have no diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java index 7a6ee8e..ca6ece0 100644 --- a/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java +++ b/core/tests/coretests/src/android/bluetooth/BluetoothStressTest.java @@ -20,8 +20,10 @@ import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.util.Set; import android.app.Instrumentation; +import android.bluetooth.BluetoothHeadset.ServiceListener; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -59,6 +61,36 @@ public class BluetoothStressTest extends InstrumentationTestCase { */ private static final int CANCEL_DISCOVERY_TIMEOUT = 5000; + /** + * Timeout for {@link BluetoothDevice#createBond()} in ms. + */ + private static final int PAIR_TIMEOUT = 20000; + + /** + * Timeout for {@link BluetoothDevice#removeBond()} in ms. + */ + private static final int UNPAIR_TIMEOUT = 20000; + + /** + * Timeout for {@link BluetoothA2dp#connectSink(BluetoothDevice)} in ms. + */ + private static final int CONNECT_A2DP_TIMEOUT = 20000; + + /** + * Timeout for {@link BluetoothA2dp#disconnectSink(BluetoothDevice)} in ms. + */ + private static final int DISCONNECT_A2DP_TIMEOUT = 20000; + + /** + * Timeout for {@link BluetoothHeadset#connectHeadset(BluetoothDevice)} in ms. + */ + private static final int CONNECT_HEADSET_TIMEOUT = 20000; + + /** + * Timeout for {@link BluetoothHeadset#disconnectHeadset(BluetoothDevice)} in ms. + */ + private static final int DISCONNECT_HEADSET_TIMEOUT = 20000; + private static final int DISCOVERY_STARTED_FLAG = 1; private static final int DISCOVERY_FINISHED_FLAG = 1 << 1; private static final int SCAN_MODE_NONE_FLAG = 1 << 2; @@ -68,6 +100,23 @@ public class BluetoothStressTest extends InstrumentationTestCase { private static final int STATE_TURNING_ON_FLAG = 1 << 6; private static final int STATE_ON_FLAG = 1 << 7; private static final int STATE_TURNING_OFF_FLAG = 1 << 8; + private static final int PAIR_STATE_FLAG = 1 << 9; + private static final int PROFILE_A2DP_FLAG = 1 << 10; + private static final int PROFILE_HEADSET_FLAG = 1 << 11; + + private static final int PAIR_STATE_BONDED = 1; + private static final int PAIR_STATE_BONDING = 1 << 1; + private static final int PAIR_STATE_NONE = 1 << 2; + + private static final int A2DP_STATE_DISCONNECTED = 1; + private static final int A2DP_STATE_CONNECTING = 1 << 1; + private static final int A2DP_STATE_CONNECTED = 1 << 2; + private static final int A2DP_STATE_DISCONNECTING = 1 << 3; + private static final int A2DP_STATE_PLAYING = 1 << 4; + + private static final int HEADSET_STATE_DISCONNECTED = 1; + private static final int HEADSET_STATE_CONNECTING = 1 << 1; + private static final int HEADSET_STATE_CONNECTED = 1 << 2; /** * Time between polls in ms. @@ -80,8 +129,41 @@ public class BluetoothStressTest extends InstrumentationTestCase { private BufferedWriter mOutputWriter; + private BluetoothA2dp mA2dp; + + private BluetoothHeadset mHeadset; + + private class HeadsetServiceListener implements ServiceListener { + private boolean mConnected = false; + + @Override + public void onServiceConnected() { + synchronized (this) { + mConnected = true; + } + } + + @Override + public void onServiceDisconnected() { + synchronized (this) { + mConnected = false; + } + } + + public boolean isConnected() { + synchronized (this) { + return mConnected; + } + } + } + + private HeadsetServiceListener mHeadsetServiceListener = new HeadsetServiceListener(); + private class BluetoothReceiver extends BroadcastReceiver { private int mFiredFlags = 0; + private int mPairFiredFlags = 0; + private int mA2dpFiredFlags = 0; + private int mHeadsetFiredFlags = 0; @Override public void onReceive(Context context, Intent intent) { @@ -123,6 +205,58 @@ public class BluetoothStressTest extends InstrumentationTestCase { mFiredFlags |= STATE_TURNING_OFF_FLAG; break; } + } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) { + mFiredFlags |= PAIR_STATE_FLAG; + int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); + assertNotSame(state, -1); + switch (state) { + case BluetoothDevice.BOND_BONDED: + mPairFiredFlags |= PAIR_STATE_BONDED; + break; + case BluetoothDevice.BOND_BONDING: + mPairFiredFlags |= PAIR_STATE_BONDING; + break; + case BluetoothDevice.BOND_NONE: + mPairFiredFlags |= PAIR_STATE_NONE; + break; + } + } else if (BluetoothA2dp.ACTION_SINK_STATE_CHANGED.equals(intent.getAction())) { + mFiredFlags |= PROFILE_A2DP_FLAG; + int state = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE, -1); + assertNotSame(state, -1); + switch (state) { + case BluetoothA2dp.STATE_DISCONNECTED: + mA2dpFiredFlags |= A2DP_STATE_DISCONNECTED; + break; + case BluetoothA2dp.STATE_CONNECTING: + mA2dpFiredFlags |= A2DP_STATE_CONNECTING; + break; + case BluetoothA2dp.STATE_CONNECTED: + mA2dpFiredFlags |= A2DP_STATE_CONNECTED; + break; + case BluetoothA2dp.STATE_DISCONNECTING: + mA2dpFiredFlags |= A2DP_STATE_DISCONNECTING; + break; + case BluetoothA2dp.STATE_PLAYING: + mA2dpFiredFlags |= A2DP_STATE_PLAYING; + break; + } + } else if (BluetoothHeadset.ACTION_STATE_CHANGED.equals(intent.getAction())) { + mFiredFlags |= PROFILE_HEADSET_FLAG; + int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, + BluetoothHeadset.STATE_ERROR); + assertNotSame(state, BluetoothHeadset.STATE_ERROR); + switch (state) { + case BluetoothHeadset.STATE_DISCONNECTED: + mHeadsetFiredFlags |= HEADSET_STATE_DISCONNECTED; + break; + case BluetoothHeadset.STATE_CONNECTING: + mHeadsetFiredFlags |= HEADSET_STATE_CONNECTING; + break; + case BluetoothHeadset.STATE_CONNECTED: + mHeadsetFiredFlags |= HEADSET_STATE_CONNECTED; + break; + } } } } @@ -133,9 +267,30 @@ public class BluetoothStressTest extends InstrumentationTestCase { } } + public int getPairFiredFlags() { + synchronized (this) { + return mPairFiredFlags; + } + } + + public int getA2dpFiredFlags() { + synchronized (this) { + return mA2dpFiredFlags; + } + } + + public int getHeadsetFiredFlags() { + synchronized (this) { + return mHeadsetFiredFlags; + } + } + public void resetFiredFlags() { synchronized (this) { mFiredFlags = 0; + mPairFiredFlags = 0; + mA2dpFiredFlags = 0; + mHeadsetFiredFlags = 0; } } } @@ -162,7 +317,13 @@ public class BluetoothStressTest extends InstrumentationTestCase { filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); + filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED); + filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED); mContext.registerReceiver(mReceiver, filter); + + mA2dp = new BluetoothA2dp(mContext); + mHeadset = new BluetoothHeadset(mContext, mHeadsetServiceListener); } @Override @@ -219,6 +380,51 @@ public class BluetoothStressTest extends InstrumentationTestCase { disable(adapter); } + public void testPair() { + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress); + + enable(adapter); + pair(adapter, device); + unpair(adapter, device); + disable(adapter); + } + + public void testConnectA2dp() { + int iterations = BluetoothTestRunner.sConnectA2dpIterations; + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sA2dpAddress); + + enable(adapter); + pair(adapter, device); + + for (int i = 0; i < iterations; i++) { + writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations); + connectA2dp(adapter, device); + disconnectA2dp(adapter, device); + } + + // TODO: Unpair from device if device can accept pairing after unpairing + disable(adapter); + } + + public void testConnectHeadset() { + int iterations = BluetoothTestRunner.sConnectHeadsetIterations; + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sHeadsetAddress); + + enable(adapter); + pair(adapter, device); + + for (int i = 0; i < iterations; i++) { + writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations); + connectHeadset(adapter, device); + disconnectHeadset(adapter, device); + } + + disable(adapter); + } + private void disable(BluetoothAdapter adapter) { int mask = STATE_TURNING_OFF_FLAG | STATE_OFF_FLAG | SCAN_MODE_NONE_FLAG; mReceiver.resetFiredFlags(); @@ -457,6 +663,351 @@ public class BluetoothStressTest extends InstrumentationTestCase { } + private void pair(BluetoothAdapter adapter, BluetoothDevice device) { + int mask = PAIR_STATE_FLAG; + int pairMask = PAIR_STATE_BONDING | PAIR_STATE_BONDED; + mReceiver.resetFiredFlags(); + + if (!adapter.isEnabled()) { + fail("pair() bluetooth not enabled"); + } + + int state = device.getBondState(); + switch (state) { + case BluetoothDevice.BOND_BONDED: + assertTrue(adapter.getBondedDevices().contains(device)); + return; + case BluetoothDevice.BOND_BONDING: + // Don't check for received intents since we might have missed them. + mask = pairMask = 0; + break; + case BluetoothDevice.BOND_NONE: + assertFalse(adapter.getBondedDevices().contains(device)); + assertTrue(device.createBond()); + break; + default: + fail("pair() invalide state: state=" + state); + } + + long s = System.currentTimeMillis(); + while (System.currentTimeMillis() - s < PAIR_TIMEOUT) { + state = device.getBondState(); + if (state == BluetoothDevice.BOND_BONDED) { + assertTrue(adapter.getBondedDevices().contains(device)); + if ((mReceiver.getFiredFlags() & mask) == mask + && (mReceiver.getPairFiredFlags() & pairMask) == pairMask) { + writeOutput(String.format("pair() completed in %d ms: device=%s", + (System.currentTimeMillis() - s), device)); + return; + } + } + sleep(POLL_TIME); + } + + int firedFlags = mReceiver.getFiredFlags(); + int pairFiredFlags = mReceiver.getPairFiredFlags(); + mReceiver.resetFiredFlags(); + fail(String.format("pair() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x), " + + "pairFlags=0x%x (expected 0x%x)", state, BluetoothDevice.BOND_BONDED, firedFlags, + mask, pairFiredFlags, pairMask)); + } + + private void unpair(BluetoothAdapter adapter, BluetoothDevice device) { + int mask = PAIR_STATE_FLAG; + int pairMask = PAIR_STATE_NONE; + mReceiver.resetFiredFlags(); + + if (!adapter.isEnabled()) { + fail("unpair() bluetooth not enabled"); + } + + int state = device.getBondState(); + switch (state) { + case BluetoothDevice.BOND_BONDED: + assertTrue(adapter.getBondedDevices().contains(device)); + assertTrue(device.removeBond()); + break; + case BluetoothDevice.BOND_BONDING: + assertTrue(device.removeBond()); + break; + case BluetoothDevice.BOND_NONE: + assertFalse(adapter.getBondedDevices().contains(device)); + return; + default: + fail("unpair() invalid state: state=" + state); + } + + assertTrue(device.removeBond()); + + long s = System.currentTimeMillis(); + while (System.currentTimeMillis() - s < UNPAIR_TIMEOUT) { + if (device.getBondState() == BluetoothDevice.BOND_NONE) { + assertFalse(adapter.getBondedDevices().contains(device)); + if ((mReceiver.getFiredFlags() & mask) == mask + && (mReceiver.getPairFiredFlags() & pairMask) == pairMask) { + writeOutput(String.format("unpair() completed in %d ms: device=%s", + (System.currentTimeMillis() - s), device)); + return; + } + } + } + + int firedFlags = mReceiver.getFiredFlags(); + int pairFiredFlags = mReceiver.getPairFiredFlags(); + mReceiver.resetFiredFlags(); + fail(String.format("unpair() timeout: state=%d (expected %d), flags=0x%x (expected 0x%x), " + + "pairFlags=0x%x (expected 0x%x)", state, BluetoothDevice.BOND_BONDED, firedFlags, + mask, pairFiredFlags, pairMask)); + } + + private void connectA2dp(BluetoothAdapter adapter, BluetoothDevice device) { + int mask = PROFILE_A2DP_FLAG; + int a2dpMask1 = A2DP_STATE_CONNECTING | A2DP_STATE_CONNECTED | A2DP_STATE_PLAYING; + int a2dpMask2 = a2dpMask1 ^ A2DP_STATE_CONNECTED; + int a2dpMask3 = a2dpMask1 ^ A2DP_STATE_PLAYING; + mReceiver.resetFiredFlags(); + + if (!adapter.isEnabled()) { + fail("connectA2dp() bluetooth not enabled"); + } + + if (!adapter.getBondedDevices().contains(device)) { + fail("connectA2dp() device not paired: device=" + device); + } + + int state = mA2dp.getSinkState(device); + switch (state) { + case BluetoothA2dp.STATE_CONNECTED: + case BluetoothA2dp.STATE_PLAYING: + assertTrue(mA2dp.isSinkConnected(device)); + return; + case BluetoothA2dp.STATE_DISCONNECTING: + case BluetoothA2dp.STATE_DISCONNECTED: + assertFalse(mA2dp.isSinkConnected(device)); + assertTrue(mA2dp.connectSink(device)); + break; + case BluetoothA2dp.STATE_CONNECTING: + assertFalse(mA2dp.isSinkConnected(device)); + // Don't check for received intents since we might have missed them. + mask = a2dpMask1 = a2dpMask2 = a2dpMask3 = 0; + break; + default: + fail("connectA2dp() invalid state: state=" + state); + } + + long s = System.currentTimeMillis(); + while (System.currentTimeMillis() - s < CONNECT_A2DP_TIMEOUT) { + state = mA2dp.getSinkState(device); + if (state == BluetoothA2dp.STATE_CONNECTED || state == BluetoothA2dp.STATE_PLAYING) { + assertTrue(mA2dp.isSinkConnected(device)); + // Check whether STATE_CONNECTING and (STATE_CONNECTED or STATE_PLAYING) intents + // have fired if we are checking if intents should be fired. + int firedFlags = mReceiver.getFiredFlags(); + int a2dpFiredFlags = mReceiver.getA2dpFiredFlags(); + if ((mReceiver.getFiredFlags() & mask) == mask + && ((a2dpFiredFlags & a2dpMask1) == a2dpMask1 + || (a2dpFiredFlags & a2dpMask2) == a2dpMask2 + || (a2dpFiredFlags & a2dpMask3) == a2dpMask3)) { + mReceiver.resetFiredFlags(); + writeOutput(String.format("connectA2dp() completed in %d ms: device=%s", + (System.currentTimeMillis() - s), device)); + return; + } + } + sleep(POLL_TIME); + } + + int firedFlags = mReceiver.getFiredFlags(); + int a2dpFiredFlags = mReceiver.getA2dpFiredFlags(); + mReceiver.resetFiredFlags(); + fail(String.format("connectA2dp() timeout: state=%d (expected %d or %d), " + + "flags=0x%x (expected 0x%x), a2dpFlags=0x%x (expected 0x%x or 0x%x or 0x%x)", + state, BluetoothHeadset.STATE_CONNECTED, BluetoothA2dp.STATE_PLAYING, firedFlags, + mask, a2dpFiredFlags, a2dpMask1, a2dpMask2, a2dpMask3)); + } + + private void disconnectA2dp(BluetoothAdapter adapter, BluetoothDevice device) { + int mask = PROFILE_A2DP_FLAG; + int a2dpMask = A2DP_STATE_DISCONNECTING | A2DP_STATE_DISCONNECTED; + mReceiver.resetFiredFlags(); + + if (!adapter.isEnabled()) { + fail("disconnectA2dp() bluetooth not enabled"); + } + + if (!adapter.getBondedDevices().contains(device)) { + fail("disconnectA2dp() device not paired: device=" + device); + } + + int state = mA2dp.getSinkState(device); + switch (state) { + case BluetoothA2dp.STATE_DISCONNECTED: + assertFalse(mA2dp.isSinkConnected(device)); + return; + case BluetoothA2dp.STATE_CONNECTED: + case BluetoothA2dp.STATE_PLAYING: + assertTrue(mA2dp.isSinkConnected(device)); + assertTrue(mA2dp.disconnectSink(device)); + break; + case BluetoothA2dp.STATE_CONNECTING: + assertFalse(mA2dp.isSinkConnected(device)); + assertTrue(mA2dp.disconnectSink(device)); + break; + case BluetoothA2dp.STATE_DISCONNECTING: + assertFalse(mA2dp.isSinkConnected(device)); + // Don't check for received intents since we might have missed them. + mask = a2dpMask = 0; + break; + default: + fail("disconnectA2dp() invalid state: state=" + state); + } + + long s = System.currentTimeMillis(); + while (System.currentTimeMillis() - s < DISCONNECT_A2DP_TIMEOUT) { + state = mA2dp.getSinkState(device); + if (state == BluetoothA2dp.STATE_DISCONNECTED) { + assertFalse(mA2dp.isSinkConnected(device)); + if ((mReceiver.getFiredFlags() & mask) == mask + && (mReceiver.getA2dpFiredFlags() & a2dpMask) == a2dpMask) { + mReceiver.resetFiredFlags(); + writeOutput(String.format("disconnectA2dp() completed in %d ms: device=%s", + (System.currentTimeMillis() - s), device)); + return; + } + } + sleep(POLL_TIME); + } + + int firedFlags = mReceiver.getFiredFlags(); + int a2dpFiredFlags = mReceiver.getA2dpFiredFlags(); + mReceiver.resetFiredFlags(); + fail(String.format("disconnectA2dp() timeout: state=%d (expected %d), " + + "flags=0x%x (expected 0x%x), a2dpFlags=0x%x (expected 0x%x)", state, + BluetoothA2dp.STATE_DISCONNECTED, firedFlags, mask, a2dpFiredFlags, a2dpMask)); + } + + private void connectHeadset(BluetoothAdapter adapter, BluetoothDevice device) { + int mask = PROFILE_HEADSET_FLAG; + int headsetMask = HEADSET_STATE_CONNECTING | HEADSET_STATE_CONNECTED; + mReceiver.resetFiredFlags(); + + if (!adapter.isEnabled()) { + fail("connectHeadset() bluetooth not enabled"); + } + + if (!adapter.getBondedDevices().contains(device)) { + fail("connectHeadset() device not paired: device=" + device); + } + + while (!mHeadsetServiceListener.isConnected()) { + sleep(POLL_TIME); + } + + int state = mHeadset.getState(device); + switch (state) { + case BluetoothHeadset.STATE_CONNECTED: + assertTrue(mHeadset.isConnected(device)); + return; + case BluetoothHeadset.STATE_DISCONNECTED: + assertFalse(mHeadset.isConnected(device)); + mHeadset.connectHeadset(device); + break; + case BluetoothHeadset.STATE_CONNECTING: + assertFalse(mHeadset.isConnected(device)); + // Don't check for received intents since we might have missed them. + mask = headsetMask = 0; + break; + case BluetoothHeadset.STATE_ERROR: + fail("connectHeadset() error state"); + break; + default: + fail("connectHeadset() invalid state: state=" + state); + } + + long s = System.currentTimeMillis(); + while (System.currentTimeMillis() - s < CONNECT_HEADSET_TIMEOUT) { + state = mHeadset.getState(device); + if (state == BluetoothHeadset.STATE_CONNECTED) { + assertTrue(mHeadset.isConnected(device)); + if ((mReceiver.getFiredFlags() & mask) == mask + && (mReceiver.getHeadsetFiredFlags() & headsetMask) == headsetMask) { + mReceiver.resetFiredFlags(); + writeOutput(String.format("connectHeadset() completed in %d ms: device=%s", + (System.currentTimeMillis() - s), device)); + return; + } + } + sleep(POLL_TIME); + } + + int firedFlags = mReceiver.getFiredFlags(); + int headsetFiredFlags = mReceiver.getHeadsetFiredFlags(); + mReceiver.resetFiredFlags(); + fail(String.format("connectHeadset() timeout: state=%d (expected %d), " + + "flags=0x%x (expected 0x%x), headsetFlags=0x%s (expected 0x%x)", state, + BluetoothHeadset.STATE_CONNECTED, firedFlags, mask, headsetFiredFlags, + headsetMask)); + } + + private void disconnectHeadset(BluetoothAdapter adapter, BluetoothDevice device) { + int mask = PROFILE_HEADSET_FLAG; + int headsetMask = HEADSET_STATE_DISCONNECTED; + mReceiver.resetFiredFlags(); + + if (!adapter.isEnabled()) { + fail("disconnectHeadset() bluetooth not enabled"); + } + + if (!adapter.getBondedDevices().contains(device)) { + fail("disconnectHeadset() device not paired: device=" + device); + } + + while (!mHeadsetServiceListener.isConnected()) { + sleep(POLL_TIME); + } + + int state = mHeadset.getState(device); + switch (state) { + case BluetoothHeadset.STATE_CONNECTED: + mHeadset.disconnectHeadset(device); + break; + case BluetoothHeadset.STATE_CONNECTING: + mHeadset.disconnectHeadset(device); + break; + case BluetoothHeadset.STATE_DISCONNECTED: + return; + case BluetoothHeadset.STATE_ERROR: + fail("disconnectHeadset() error state"); + break; + default: + fail("disconnectHeadset() invalid state: state=" + state); + } + + long s = System.currentTimeMillis(); + while (System.currentTimeMillis() - s < DISCONNECT_HEADSET_TIMEOUT) { + state = mHeadset.getState(device); + if (state == BluetoothHeadset.STATE_DISCONNECTED) { + assertFalse(mHeadset.isConnected(device)); + if ((mReceiver.getFiredFlags() & mask) == mask + && (mReceiver.getHeadsetFiredFlags() & headsetMask) == headsetMask) { + mReceiver.resetFiredFlags(); + writeOutput(String.format("disconnectHeadset() completed in %d ms: device=%s", + (System.currentTimeMillis() - s), device)); + return; + } + } + sleep(POLL_TIME); + } + + int firedFlags = mReceiver.getFiredFlags(); + int headsetFiredFlags = mReceiver.getHeadsetFiredFlags(); + mReceiver.resetFiredFlags(); + fail(String.format("disconnectHeadset() timeout: state=%d (expected %d), " + + "flags=0x%x (expected 0x%x), headsetFlags=0x%s (expected 0x%x)", state, + BluetoothHeadset.STATE_DISCONNECTED, firedFlags, mask, headsetFiredFlags, + headsetMask)); + } + private void writeOutput(String s) { if (mOutputWriter == null) { return; diff --git a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java index cf0ff99..e3d2eb6 100644 --- a/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java +++ b/core/tests/coretests/src/android/bluetooth/BluetoothTestRunner.java @@ -26,6 +26,11 @@ public class BluetoothTestRunner extends InstrumentationTestRunner { public static int sEnableIterations = 100; public static int sDiscoverableIterations = 1000; public static int sScanIterations = 1000; + public static int sConnectHeadsetIterations = 1000; + public static int sConnectA2dpIterations = 1000; + + public static String sHeadsetAddress = ""; + public static String sA2dpAddress = ""; @Override public TestSuite getAllTests() { @@ -69,5 +74,33 @@ public class BluetoothTestRunner extends InstrumentationTestRunner { // Invalid argument, fall back to default value } } + + val = arguments.getString("connect_a2dp_iterations"); + if (val != null) { + try { + sConnectA2dpIterations = Integer.parseInt(val); + } catch (NumberFormatException e) { + // Invalid argument, fall back to default value + } + } + + val = arguments.getString("connect_headset_iterations"); + if (val != null) { + try { + sConnectHeadsetIterations = Integer.parseInt(val); + } catch (NumberFormatException e) { + // Invalid argument, fall back to default value + } + } + + val = arguments.getString("headset_address"); + if (val != null) { + sHeadsetAddress = val; + } + + val = arguments.getString("a2dp_address"); + if (val != null) { + sA2dpAddress = val; + } } } diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index cbf8c87..de3d153 100755 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -358,6 +358,7 @@ public class PackageManagerTests extends AndroidTestCase { assertTrue((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); assertEquals(srcPath, drmInstallPath); assertEquals(publicSrcPath, appInstallPath); + assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath())); } else { assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); int rLoc = getInstallLoc(flags, expInstallLocation, pkgLen); @@ -365,10 +366,12 @@ public class PackageManagerTests extends AndroidTestCase { assertEquals(srcPath, appInstallPath); assertEquals(publicSrcPath, appInstallPath); assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath())); } else if (rLoc == INSTALL_LOC_SD){ assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX)); assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX)); + assertTrue(info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX)); } else { // TODO handle error. Install should have failed. } diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h index 2597e9e..1af4254 100644 --- a/include/media/stagefright/AudioSource.h +++ b/include/media/stagefright/AudioSource.h @@ -49,7 +49,17 @@ protected: virtual ~AudioSource(); private: - enum { kMaxBufferSize = 2048 }; + enum { + kMaxBufferSize = 2048, + + // After the initial mute, we raise the volume linearly + // over kAutoRampDurationUs. + kAutoRampDurationUs = 300000, + + // This is the initial mute duration to suppress + // the video recording signal tone + kAutoRampStartUs = 700000, + }; AudioRecord *mRecord; status_t mInitCheck; @@ -67,6 +77,12 @@ private: void trackMaxAmplitude(int16_t *data, int nSamples); + // This is used to raise the volume from mute to the + // actual level linearly. + void rampVolume( + int32_t startFrame, int32_t rampDurationFrames, + uint8_t *data, size_t bytes); + AudioSource(const AudioSource &); AudioSource &operator=(const AudioSource &); }; diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 010ded1..875bc5b 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -102,6 +102,7 @@ private: kInputBufferSizesAreBogus = 512, kSupportsMultipleFramesPerInputBuffer = 1024, kAvoidMemcopyInputRecordingFrames = 2048, + kRequiresLargerEncoderOutputBuffer = 4096, }; struct BufferInfo { diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h index 153ead9..70e0c5e 100644 --- a/include/media/stagefright/foundation/ALooper.h +++ b/include/media/stagefright/foundation/ALooper.h @@ -19,6 +19,7 @@ #define A_LOOPER_H_ #include <media/stagefright/foundation/ABase.h> +#include <media/stagefright/foundation/AString.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/List.h> @@ -36,6 +37,9 @@ struct ALooper : public RefBase { ALooper(); + // Takes effect in a subsequent call to start(). + void setName(const char *name); + handler_id registerHandler(const sp<AHandler> &handler); void unregisterHandler(handler_id handlerID); @@ -63,6 +67,8 @@ private: Mutex mLock; Condition mQueueChangedCondition; + AString mName; + List<Event> mEventQueue; struct LooperThread; diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index 604f558..a0e01c6 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -508,8 +508,8 @@ bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, } if (get4LE(lfhBuf) != kLFHSignature) { - LOGW("didn't find signature at start of lfh, offset=%ld\n", - localHdrOffset); + LOGW("didn't find signature at start of lfh, offset=%ld (got 0x%08lx, expected 0x%08x)\n", + localHdrOffset, get4LE(lfhBuf), kLFHSignature); return false; } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 9ceda7e..9aa84a03 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -127,6 +127,13 @@ public class LocationManager { "android.location.GPS_ENABLED_CHANGE"; /** + * Broadcast intent action when the configured location providers + * change. + */ + public static final String PROVIDERS_CHANGED_ACTION = + "android.location.PROVIDERS_CHANGED"; + + /** * Broadcast intent action indicating that the GPS has either started or * stopped receiving GPS fixes. An intent extra provides this state as a * boolean, where {@code true} means that the GPS is actively receiving fixes. diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index c8dfede..4c729e4 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -40,6 +40,7 @@ AudioSource::AudioSource( mGroup(NULL) { LOGV("sampleRate: %d, channels: %d", sampleRate, channels); + CHECK(channels == 1 || channels == 2); uint32_t flags = AudioRecord::RECORD_AGC_ENABLE | AudioRecord::RECORD_NS_ENABLE | AudioRecord::RECORD_IIR_ENABLE; @@ -158,6 +159,38 @@ static int skipFrame(int64_t timestampUs, } +void AudioSource::rampVolume( + int32_t startFrame, int32_t rampDurationFrames, + uint8_t *data, size_t bytes) { + + const int32_t kShift = 14; + int32_t fixedMultiplier = (startFrame << kShift) / rampDurationFrames; + const int32_t nChannels = mRecord->channelCount(); + int32_t stopFrame = startFrame + bytes / sizeof(int16_t); + int16_t *frame = (int16_t *) data; + if (stopFrame > rampDurationFrames) { + stopFrame = rampDurationFrames; + } + + while (startFrame < stopFrame) { + if (nChannels == 1) { // mono + frame[0] = (frame[0] * fixedMultiplier) >> kShift; + ++frame; + ++startFrame; + } else { // stereo + frame[0] = (frame[0] * fixedMultiplier) >> kShift; + frame[1] = (frame[1] * fixedMultiplier) >> kShift; + frame += 2; + startFrame += 2; + } + + // Update the multiplier every 4 frames + if ((startFrame & 3) == 0) { + fixedMultiplier = (startFrame << kShift) / rampDurationFrames; + } + } +} + status_t AudioSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; @@ -242,6 +275,19 @@ status_t AudioSource::read( continue; } + if (mPrevSampleTimeUs - mStartTimeUs < kAutoRampStartUs) { + // Mute the initial video recording signal + memset((uint8_t *) buffer->data(), 0, n); + } else if (mPrevSampleTimeUs - mStartTimeUs < kAutoRampStartUs + kAutoRampDurationUs) { + int32_t autoRampDurationFrames = + (kAutoRampDurationUs * sampleRate + 500000LL) / 1000000LL; + + int32_t autoRampStartFrames = + (kAutoRampStartUs * sampleRate + 500000LL) / 1000000LL; + + int32_t nFrames = numFramesRecorded - autoRampStartFrames; + rampVolume(nFrames, autoRampDurationFrames, (uint8_t *) buffer->data(), n); + } if (mTrackMaxAmplitude) { trackMaxAmplitude((int16_t *) buffer->data(), n >> 1); } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index a0cd5c3..7daac96 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -196,7 +196,6 @@ AwesomePlayer::AwesomePlayer() mExtractorFlags(0), mLastVideoBuffer(NULL), mVideoBuffer(NULL), - mRTSPTimeOffset(0), mSuspensionState(NULL) { CHECK_EQ(mClient.connect(), OK); @@ -739,7 +738,10 @@ status_t AwesomePlayer::getDuration(int64_t *durationUs) { } status_t AwesomePlayer::getPosition(int64_t *positionUs) { - if (mSeeking) { + if (mRTSPController != NULL) { + *positionUs = mRTSPController->getNormalPlayTimeUs(); + } + else if (mSeeking) { *positionUs = mSeekTimeUs; } else if (mVideoSource != NULL) { Mutex::Autolock autoLock(mMiscStateLock); @@ -750,10 +752,6 @@ status_t AwesomePlayer::getPosition(int64_t *positionUs) { *positionUs = 0; } - if (mRTSPController != NULL) { - *positionUs += mRTSPTimeOffset; - } - return OK; } @@ -770,13 +768,10 @@ status_t AwesomePlayer::seekTo(int64_t timeUs) { status_t AwesomePlayer::seekTo_l(int64_t timeUs) { if (mRTSPController != NULL) { - pause_l(); mRTSPController->seek(timeUs); - play_l(); notifyListener_l(MEDIA_SEEK_COMPLETE); mSeekNotificationSent = true; - mRTSPTimeOffset = timeUs; return OK; } @@ -1246,6 +1241,7 @@ status_t AwesomePlayer::finishSetDataSource_l() { } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) { if (mLooper == NULL) { mLooper = new ALooper; + mLooper->setName("gtalk rtp"); mLooper->start( false /* runOnCallingThread */, false /* canCallJava */, @@ -1357,6 +1353,7 @@ status_t AwesomePlayer::finishSetDataSource_l() { } else if (!strncasecmp("rtsp://", mUri.string(), 7)) { if (mLooper == NULL) { mLooper = new ALooper; + mLooper->setName("rtsp"); mLooper->start(); } mRTSPController = new ARTSPController(mLooper); diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp index c02b7f3..9171aab 100644 --- a/media/libstagefright/NuCachedSource2.cpp +++ b/media/libstagefright/NuCachedSource2.cpp @@ -180,6 +180,7 @@ NuCachedSource2::NuCachedSource2(const sp<DataSource> &source) mLastAccessPos(0), mFetching(true), mLastFetchTimeUs(-1) { + mLooper->setName("NuCachedSource2"); mLooper->registerHandler(mReflector); mLooper->start(); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 4741b1d..165cec9 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -353,6 +353,15 @@ uint32_t OMXCodec::getComponentQuirks(const char *componentName) { quirks |= kRequiresLoadedToIdleAfterAllocation; quirks |= kRequiresAllocateBufferOnInputPorts; quirks |= kRequiresAllocateBufferOnOutputPorts; + if (!strncmp(componentName, "OMX.qcom.video.encoder.avc", 26)) { + + // The AVC encoder advertises the size of output buffers + // based on the input video resolution and assumes + // the worst/least compression ratio is 0.5. It is found that + // sometimes, the output buffer size is larger than + // size advertised by the encoder. + quirks |= kRequiresLargerEncoderOutputBuffer; + } } if (!strncmp(componentName, "OMX.qcom.7x30.video.encoder.", 28)) { } @@ -906,6 +915,10 @@ void OMXCodec::setVideoInputFormat( video_def->nBitrate = bitRate; // Q16 format video_def->eCompressionFormat = compressionFormat; video_def->eColorFormat = OMX_COLOR_FormatUnused; + if (mQuirks & kRequiresLargerEncoderOutputBuffer) { + // Increases the output buffer size + def.nBufferSize = ((def.nBufferSize * 3) >> 1); + } err = mOMX->setParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp index 77afb01..b7087f8 100644 --- a/media/libstagefright/foundation/ALooper.cpp +++ b/media/libstagefright/foundation/ALooper.cpp @@ -65,6 +65,10 @@ ALooper::~ALooper() { stop(); } +void ALooper::setName(const char *name) { + mName = name; +} + ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) { return gLooperRoster.registerHandler(this, handler); } @@ -100,7 +104,8 @@ status_t ALooper::start( mThread = new LooperThread(this, canCallJava); - status_t err = mThread->run("ALooper", priority); + status_t err = mThread->run( + mName.empty() ? "ALooper" : mName.c_str(), priority); if (err != OK) { mThread.clear(); } diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h index 7020564..7016880 100644 --- a/media/libstagefright/include/ARTSPController.h +++ b/media/libstagefright/include/ARTSPController.h @@ -41,6 +41,8 @@ struct ARTSPController : public MediaExtractor { virtual sp<MetaData> getTrackMetaData( size_t index, uint32_t flags); + int64_t getNormalPlayTimeUs(); + void onMessageReceived(const sp<AMessage> &msg); protected: diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 49b5c78..55e2c36 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -180,7 +180,6 @@ private: sp<ALooper> mLooper; sp<ARTSPController> mRTSPController; - int64_t mRTSPTimeOffset; sp<ARTPSession> mRTPSession; sp<UDPPusher> mRTPPusher, mRTCPPusher; diff --git a/media/libstagefright/rtsp/AAMRAssembler.cpp b/media/libstagefright/rtsp/AAMRAssembler.cpp index c56578b..154ba31 100644 --- a/media/libstagefright/rtsp/AAMRAssembler.cpp +++ b/media/libstagefright/rtsp/AAMRAssembler.cpp @@ -178,12 +178,8 @@ ARTPAssembler::AssemblyStatus AAMRAssembler::addPacket( } } - uint64_t ntpTime; - CHECK(buffer->meta()->findInt64( - "ntp-time", (int64_t *)&ntpTime)); - sp<ABuffer> accessUnit = new ABuffer(totalSize); - accessUnit->meta()->setInt64("ntp-time", ntpTime); + CopyTimes(accessUnit, buffer); size_t dstOffset = 0; for (size_t i = 0; i < tableOfContents.size(); ++i) { diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp index b22de2c..6b1e292 100644 --- a/media/libstagefright/rtsp/AAVCAssembler.cpp +++ b/media/libstagefright/rtsp/AAVCAssembler.cpp @@ -155,7 +155,7 @@ bool AAVCAssembler::addSingleTimeAggregationPacket(const sp<ABuffer> &buffer) { sp<ABuffer> unit = new ABuffer(nalSize); memcpy(unit->data(), &data[2], nalSize); - PropagateTimes(buffer, unit); + CopyTimes(unit, buffer); addSingleNALUnit(unit); @@ -287,7 +287,7 @@ ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit( ++totalSize; sp<ABuffer> unit = new ABuffer(totalSize); - PropagateTimes(buffer, unit); + CopyTimes(unit, *queue->begin()); unit->data()[0] = (nri << 5) | nalType; @@ -325,10 +325,6 @@ void AAVCAssembler::submitAccessUnit() { LOG(VERBOSE) << "Access unit complete (" << mNALUnits.size() << " nal units)"; #endif - uint64_t ntpTime; - CHECK((*mNALUnits.begin())->meta()->findInt64( - "ntp-time", (int64_t *)&ntpTime)); - size_t totalSize = 0; for (List<sp<ABuffer> >::iterator it = mNALUnits.begin(); it != mNALUnits.end(); ++it) { @@ -347,7 +343,7 @@ void AAVCAssembler::submitAccessUnit() { offset += nal->size(); } - accessUnit->meta()->setInt64("ntp-time", ntpTime); + CopyTimes(accessUnit, *mNALUnits.begin()); #if 0 printf(mAccessUnitDamaged ? "X" : "."); diff --git a/media/libstagefright/rtsp/AH263Assembler.cpp b/media/libstagefright/rtsp/AH263Assembler.cpp index 2818041..498295c 100644 --- a/media/libstagefright/rtsp/AH263Assembler.cpp +++ b/media/libstagefright/rtsp/AH263Assembler.cpp @@ -128,10 +128,6 @@ void AH263Assembler::submitAccessUnit() { LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)"; #endif - uint64_t ntpTime; - CHECK((*mPackets.begin())->meta()->findInt64( - "ntp-time", (int64_t *)&ntpTime)); - size_t totalSize = 0; List<sp<ABuffer> >::iterator it = mPackets.begin(); while (it != mPackets.end()) { @@ -155,7 +151,7 @@ void AH263Assembler::submitAccessUnit() { ++it; } - accessUnit->meta()->setInt64("ntp-time", ntpTime); + CopyTimes(accessUnit, *mPackets.begin()); #if 0 printf(mAccessUnitDamaged ? "X" : "."); diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp index 6e46361..b0d2c64 100644 --- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp @@ -103,10 +103,6 @@ void AMPEG4AudioAssembler::submitAccessUnit() { LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)"; #endif - uint64_t ntpTime; - CHECK((*mPackets.begin())->meta()->findInt64( - "ntp-time", (int64_t *)&ntpTime)); - size_t totalSize = 0; List<sp<ABuffer> >::iterator it = mPackets.begin(); while (it != mPackets.end()) { @@ -142,7 +138,7 @@ void AMPEG4AudioAssembler::submitAccessUnit() { ++it; } - accessUnit->meta()->setInt64("ntp-time", ntpTime); + CopyTimes(accessUnit, *mPackets.begin()); #if 0 printf(mAccessUnitDamaged ? "X" : "."); diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp index 7e633d7..7dd3e3f 100644 --- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp @@ -101,10 +101,6 @@ void AMPEG4ElementaryAssembler::submitAccessUnit() { LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " nal units)"; #endif - uint64_t ntpTime; - CHECK((*mPackets.begin())->meta()->findInt64( - "ntp-time", (int64_t *)&ntpTime)); - size_t totalSize = 0; for (List<sp<ABuffer> >::iterator it = mPackets.begin(); it != mPackets.end(); ++it) { @@ -120,7 +116,7 @@ void AMPEG4ElementaryAssembler::submitAccessUnit() { offset += nal->size(); } - accessUnit->meta()->setInt64("ntp-time", ntpTime); + CopyTimes(accessUnit, *mPackets.begin()); #if 0 printf(mAccessUnitDamaged ? "X" : "."); diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp index b930184..2d7738b 100644 --- a/media/libstagefright/rtsp/APacketSource.cpp +++ b/media/libstagefright/rtsp/APacketSource.cpp @@ -402,16 +402,41 @@ sp<ABuffer> MakeMPEG4VideoCodecSpecificData( return csd; } +static bool GetClockRate(const AString &desc, uint32_t *clockRate) { + ssize_t slashPos = desc.find("/"); + if (slashPos < 0) { + return false; + } + + const char *s = desc.c_str() + slashPos + 1; + + char *end; + unsigned long x = strtoul(s, &end, 10); + + if (end == s || (*end != '\0' && *end != '/')) { + return false; + } + + *clockRate = x; + + return true; +} + APacketSource::APacketSource( const sp<ASessionDescription> &sessionDesc, size_t index) : mInitCheck(NO_INIT), mFormat(new MetaData), - mEOSResult(OK) { + mEOSResult(OK), + mRTPTimeBase(0), + mNormalPlayTimeBaseUs(0), + mLastNormalPlayTimeUs(0) { unsigned long PT; AString desc; AString params; sessionDesc->getFormatType(index, &PT, &desc, ¶ms); + CHECK(GetClockRate(desc, &mClockRate)); + int64_t durationUs; if (sessionDesc->getDurationUs(&durationUs)) { mFormat->setInt64(kKeyDuration, durationUs); @@ -571,6 +596,8 @@ status_t APacketSource::read( if (!mBuffers.empty()) { const sp<ABuffer> buffer = *mBuffers.begin(); + updateNormalPlayTime_l(buffer); + MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size()); int64_t timeUs; @@ -588,6 +615,16 @@ status_t APacketSource::read( return mEOSResult; } +void APacketSource::updateNormalPlayTime_l(const sp<ABuffer> &buffer) { + uint32_t rtpTime; + CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); + + mLastNormalPlayTimeUs = + (((double)rtpTime - (double)mRTPTimeBase) / mClockRate) + * 1000000ll + + mNormalPlayTimeBaseUs; +} + void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { int32_t damaged; if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { @@ -613,4 +650,17 @@ void APacketSource::flushQueue() { mBuffers.clear(); } +int64_t APacketSource::getNormalPlayTimeUs() { + Mutex::Autolock autoLock(mLock); + return mLastNormalPlayTimeUs; +} + +void APacketSource::setNormalPlayTimeMapping( + uint32_t rtpTime, int64_t normalPlayTimeUs) { + Mutex::Autolock autoLock(mLock); + + mRTPTimeBase = rtpTime; + mNormalPlayTimeBaseUs = normalPlayTimeUs; +} + } // namespace android diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h index 197af3e..3833ab1 100644 --- a/media/libstagefright/rtsp/APacketSource.h +++ b/media/libstagefright/rtsp/APacketSource.h @@ -45,6 +45,11 @@ struct APacketSource : public MediaSource { void flushQueue(); + int64_t getNormalPlayTimeUs(); + + void setNormalPlayTimeMapping( + uint32_t rtpTime, int64_t normalPlayTimeUs); + protected: virtual ~APacketSource(); @@ -58,6 +63,15 @@ private: List<sp<ABuffer> > mBuffers; status_t mEOSResult; + uint32_t mClockRate; + + uint32_t mRTPTimeBase; + int64_t mNormalPlayTimeBaseUs; + + int64_t mLastNormalPlayTimeUs; + + void updateNormalPlayTime_l(const sp<ABuffer> &buffer); + DISALLOW_EVIL_CONSTRUCTORS(APacketSource); }; diff --git a/media/libstagefright/rtsp/ARTPAssembler.cpp b/media/libstagefright/rtsp/ARTPAssembler.cpp index 24225b8..9ba2b37 100644 --- a/media/libstagefright/rtsp/ARTPAssembler.cpp +++ b/media/libstagefright/rtsp/ARTPAssembler.cpp @@ -35,18 +35,6 @@ ARTPAssembler::ARTPAssembler() : mFirstFailureTimeUs(-1) { } -void ARTPAssembler::PropagateTimes( - const sp<ABuffer> &from, const sp<ABuffer> &to) { - uint32_t rtpTime; - CHECK(from->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); - - uint64_t ntpTime = 0; - CHECK(from->meta()->findInt64("ntp-time", (int64_t *)&ntpTime)); - - to->meta()->setInt32("rtp-time", rtpTime); - to->meta()->setInt64("ntp-time", ntpTime); -} - void ARTPAssembler::onPacketReceived(const sp<ARTPSource> &source) { AssemblyStatus status; for (;;) { @@ -75,4 +63,19 @@ void ARTPAssembler::onPacketReceived(const sp<ARTPSource> &source) { } } +// static +void ARTPAssembler::CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from) { + uint64_t ntpTime; + CHECK(from->meta()->findInt64("ntp-time", (int64_t *)&ntpTime)); + + uint32_t rtpTime; + CHECK(from->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); + + to->meta()->setInt64("ntp-time", ntpTime); + to->meta()->setInt32("rtp-time", rtpTime); + + // Copy the seq number. + to->setInt32Data(from->int32Data()); +} + } // namespace android diff --git a/media/libstagefright/rtsp/ARTPAssembler.h b/media/libstagefright/rtsp/ARTPAssembler.h index e598088..70ea186 100644 --- a/media/libstagefright/rtsp/ARTPAssembler.h +++ b/media/libstagefright/rtsp/ARTPAssembler.h @@ -40,12 +40,11 @@ struct ARTPAssembler : public RefBase { virtual void onByeReceived() = 0; protected: - static void PropagateTimes( - const sp<ABuffer> &from, const sp<ABuffer> &to); - virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source) = 0; virtual void packetLost() = 0; + static void CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from); + private: int64_t mFirstFailureTimeUs; diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp index d4eed7c..ce1ee0e 100644 --- a/media/libstagefright/rtsp/ARTPWriter.cpp +++ b/media/libstagefright/rtsp/ARTPWriter.cpp @@ -31,6 +31,7 @@ ARTPWriter::ARTPWriter(int fd) mReflector(new AHandlerReflector<ARTPWriter>(this)) { CHECK_GE(fd, 0); + mLooper->setName("rtp writer"); mLooper->registerHandler(mReflector); mLooper->start(); diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp index 9df17cb..a89946b 100644 --- a/media/libstagefright/rtsp/ARTSPController.cpp +++ b/media/libstagefright/rtsp/ARTSPController.cpp @@ -138,4 +138,9 @@ void ARTSPController::onMessageReceived(const sp<AMessage> &msg) { } } +int64_t ARTSPController::getNormalPlayTimeUs() { + CHECK(mHandler != NULL); + return mHandler->getNormalPlayTimeUs(); +} + } // namespace android diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h index 4c6f058..f20dd6f 100644 --- a/media/libstagefright/rtsp/MyHandler.h +++ b/media/libstagefright/rtsp/MyHandler.h @@ -23,6 +23,8 @@ #include "ARTSPConnection.h" #include "ASessionDescription.h" +#include <ctype.h> + #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooper.h> @@ -31,8 +33,44 @@ #define USE_TCP_INTERLEAVED 0 +// If no access units are received within 3 secs, assume that the rtp +// stream has ended and signal end of stream. +static int64_t kAccessUnitTimeoutUs = 3000000ll; + +// If no access units arrive for the first 10 secs after starting the +// stream, assume none ever will and signal EOS or switch transports. +static int64_t kStartupTimeoutUs = 10000000ll; + namespace android { +static bool GetAttribute(const char *s, const char *key, AString *value) { + value->clear(); + + size_t keyLen = strlen(key); + + for (;;) { + while (isspace(*s)) { + ++s; + } + + const char *colonPos = strchr(s, ';'); + + size_t len = + (colonPos == NULL) ? strlen(s) : colonPos - s; + + if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) { + value->setTo(&s[keyLen + 1], len - keyLen - 1); + return true; + } + + if (colonPos == NULL) { + return false; + } + + s = colonPos + 1; + } +} + struct MyHandler : public AHandler { MyHandler(const char *url, const sp<ALooper> &looper) : mLooper(looper), @@ -43,8 +81,10 @@ struct MyHandler : public AHandler { mSetupTracksSuccessful(false), mSeekPending(false), mFirstAccessUnit(true), - mFirstAccessUnitNTP(0) { - + mFirstAccessUnitNTP(0), + mNumAccessUnitsReceived(0), + mCheckPending(false) { + mNetLooper->setName("rtsp net"); mNetLooper->start(false /* runOnCallingThread */, false /* canCallJava */, PRIORITY_HIGHEST); @@ -76,6 +116,20 @@ struct MyHandler : public AHandler { msg->post(); } + int64_t getNormalPlayTimeUs() { + int64_t maxTimeUs = 0; + for (size_t i = 0; i < mTracks.size(); ++i) { + int64_t timeUs = mTracks.editItemAt(i).mPacketSource + ->getNormalPlayTimeUs(); + + if (i == 0 || timeUs > maxTimeUs) { + maxTimeUs = timeUs; + } + } + + return maxTimeUs; + } + virtual void onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case 'conn': @@ -269,12 +323,14 @@ struct MyHandler : public AHandler { CHECK_EQ(response->mStatusCode, 200u); + parsePlayResponse(response); + mDoneMsg->setInt32("result", OK); mDoneMsg->post(); mDoneMsg = NULL; sp<AMessage> timeout = new AMessage('tiou', id()); - timeout->post(10000000ll); + timeout->post(kStartupTimeoutUs); } else { sp<AMessage> reply = new AMessage('disc', id()); mConn->disconnect(reply); @@ -332,16 +388,38 @@ struct MyHandler : public AHandler { break; } + case 'chek': + { + if (mNumAccessUnitsReceived == 0) { + LOG(INFO) << "stream ended? aborting."; + (new AMessage('abor', id()))->post(); + break; + } + + mNumAccessUnitsReceived = 0; + msg->post(kAccessUnitTimeoutUs); + break; + } + case 'accu': { + ++mNumAccessUnitsReceived; + + if (!mCheckPending) { + mCheckPending = true; + sp<AMessage> check = new AMessage('chek', id()); + check->post(kAccessUnitTimeoutUs); + } + size_t trackIndex; CHECK(msg->findSize("track-index", &trackIndex)); + TrackInfo *track = &mTracks.editItemAt(trackIndex); + int32_t eos; if (msg->findInt32("eos", &eos)) { LOG(INFO) << "received BYE on track index " << trackIndex; #if 0 - TrackInfo *track = &mTracks.editItemAt(trackIndex); track->mPacketSource->signalEOS(ERROR_END_OF_STREAM); #endif return; @@ -352,10 +430,32 @@ struct MyHandler : public AHandler { sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get()); + uint32_t seqNum = (uint32_t)accessUnit->int32Data(); + + if (seqNum < track->mFirstSeqNumInSegment) { + LOG(INFO) << "dropping stale access-unit " + << "(" << seqNum << " < " + << track->mFirstSeqNumInSegment << ")"; + break; + } + uint64_t ntpTime; CHECK(accessUnit->meta()->findInt64( "ntp-time", (int64_t *)&ntpTime)); + uint32_t rtpTime; + CHECK(accessUnit->meta()->findInt32( + "rtp-time", (int32_t *)&rtpTime)); + + if (track->mNewSegment) { + track->mNewSegment = false; + + LOG(VERBOSE) << "first segment unit ntpTime=" + << StringPrintf("0x%016llx", ntpTime) + << " rtpTime=" << rtpTime + << " seq=" << seqNum; + } + if (mFirstAccessUnit) { mFirstAccessUnit = false; mFirstAccessUnitNTP = ntpTime; @@ -414,6 +514,11 @@ struct MyHandler : public AHandler { case 'see1': { + // Session is paused now. + for (size_t i = 0; i < mTracks.size(); ++i) { + mTracks.editItemAt(i).mPacketSource->flushQueue(); + } + int64_t timeUs; CHECK(msg->findInt64("time", &timeUs)); @@ -440,15 +545,13 @@ struct MyHandler : public AHandler { { CHECK(mSeekPending); - LOG(INFO) << "seek completed."; - mSeekPending = false; - int32_t result; CHECK(msg->findInt32("result", &result)); - if (result != OK) { - LOG(ERROR) << "seek FAILED"; - break; - } + + LOG(INFO) << "PLAY completed with result " + << result << " (" << strerror(-result) << ")"; + + CHECK_EQ(result, (status_t)OK); sp<RefBase> obj; CHECK(msg->findObject("response", &obj)); @@ -457,9 +560,10 @@ struct MyHandler : public AHandler { CHECK_EQ(response->mStatusCode, 200u); - for (size_t i = 0; i < mTracks.size(); ++i) { - mTracks.editItemAt(i).mPacketSource->flushQueue(); - } + parsePlayResponse(response); + + LOG(INFO) << "seek completed."; + mSeekPending = false; break; } @@ -480,9 +584,8 @@ struct MyHandler : public AHandler { { if (mFirstAccessUnit) { LOG(WARNING) << "Never received any data, disconnecting."; - + (new AMessage('abor', id()))->post(); } - (new AMessage('abor', id()))->post(); break; } @@ -492,6 +595,90 @@ struct MyHandler : public AHandler { } } + static void SplitString( + const AString &s, const char *separator, List<AString> *items) { + items->clear(); + size_t start = 0; + while (start < s.size()) { + ssize_t offset = s.find(separator, start); + + if (offset < 0) { + items->push_back(AString(s, start, s.size() - start)); + break; + } + + items->push_back(AString(s, start, offset - start)); + start = offset + strlen(separator); + } + } + + void parsePlayResponse(const sp<ARTSPResponse> &response) { + ssize_t i = response->mHeaders.indexOfKey("range"); + if (i < 0) { + // Server doesn't even tell use what range it is going to + // play, therefore we won't support seeking. + return; + } + + AString range = response->mHeaders.valueAt(i); + LOG(VERBOSE) << "Range: " << range; + + AString val; + CHECK(GetAttribute(range.c_str(), "npt", &val)); + float npt1, npt2; + + if (val == "now-") { + // This is a live stream and therefore not seekable. + return; + } else { + CHECK_EQ(sscanf(val.c_str(), "%f-%f", &npt1, &npt2), 2); + } + + i = response->mHeaders.indexOfKey("rtp-info"); + CHECK_GE(i, 0); + + AString rtpInfo = response->mHeaders.valueAt(i); + List<AString> streamInfos; + SplitString(rtpInfo, ",", &streamInfos); + + int n = 1; + for (List<AString>::iterator it = streamInfos.begin(); + it != streamInfos.end(); ++it) { + (*it).trim(); + LOG(VERBOSE) << "streamInfo[" << n << "] = " << *it; + + CHECK(GetAttribute((*it).c_str(), "url", &val)); + + size_t trackIndex = 0; + while (trackIndex < mTracks.size() + && !(val == mTracks.editItemAt(trackIndex).mURL)) { + ++trackIndex; + } + CHECK_LT(trackIndex, mTracks.size()); + + CHECK(GetAttribute((*it).c_str(), "seq", &val)); + + char *end; + unsigned long seq = strtoul(val.c_str(), &end, 10); + + TrackInfo *info = &mTracks.editItemAt(trackIndex); + info->mFirstSeqNumInSegment = seq; + info->mNewSegment = true; + + CHECK(GetAttribute((*it).c_str(), "rtptime", &val)); + + uint32_t rtpTime = strtoul(val.c_str(), &end, 10); + + LOG(VERBOSE) << "track #" << n + << ": rtpTime=" << rtpTime << " <=> npt=" << npt1; + + info->mPacketSource->setNormalPlayTimeMapping( + rtpTime, (int64_t)(npt1 * 1E6)); + + ++n; + } + } + sp<APacketSource> getPacketSource(size_t index) { CHECK_GE(index, 0u); CHECK_LT(index, mTracks.size()); @@ -516,11 +703,16 @@ private: bool mSeekPending; bool mFirstAccessUnit; uint64_t mFirstAccessUnitNTP; + int64_t mNumAccessUnitsReceived; + bool mCheckPending; struct TrackInfo { + AString mURL; int mRTPSocket; int mRTCPSocket; bool mUsingInterleavedTCP; + uint32_t mFirstSeqNumInSegment; + bool mNewSegment; sp<APacketSource> mPacketSource; }; @@ -550,8 +742,13 @@ private: mTracks.push(TrackInfo()); TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1); + info->mURL = trackURL; info->mPacketSource = source; info->mUsingInterleavedTCP = false; + info->mFirstSeqNumInSegment = 0; + info->mNewSegment = true; + + LOG(VERBOSE) << "track #" << mTracks.size() << " URL=" << trackURL; AString request = "SETUP "; request.append(trackURL); diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index b121158..1ffcd56 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -229,14 +229,6 @@ struct android_native_buffer_t; #define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */ #endif -#ifndef EGL_ANDROID_get_render_buffer -#define EGL_ANDROID_get_render_buffer 1 -#ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw); -#endif -typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface draw); -#endif - #ifndef EGL_ANDROID_swap_rectangle #define EGL_ANDROID_swap_rectangle 1 #ifdef EGL_EGLEXT_PROTOTYPES diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp index 9e25681..163b2db 100644 --- a/opengl/libagl/egl.cpp +++ b/opengl/libagl/egl.cpp @@ -158,7 +158,6 @@ struct egl_surface_t virtual EGLint getSwapBehavior() const; virtual EGLBoolean swapBuffers(); virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); - virtual EGLClientBuffer getRenderBuffer() const; protected: GGLSurface depth; }; @@ -202,9 +201,6 @@ EGLBoolean egl_surface_t::setSwapRectangle( { return EGL_FALSE; } -EGLClientBuffer egl_surface_t::getRenderBuffer() const { - return 0; -} // ---------------------------------------------------------------------------- @@ -230,7 +226,6 @@ struct egl_window_surface_v2_t : public egl_surface_t virtual EGLint getRefreshRate() const; virtual EGLint getSwapBehavior() const; virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h); - virtual EGLClientBuffer getRenderBuffer() const; private: status_t lock(android_native_buffer_t* buf, int usage, void** vaddr); @@ -626,11 +621,6 @@ EGLBoolean egl_window_surface_v2_t::setSwapRectangle( return EGL_TRUE; } -EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const -{ - return buffer; -} - EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl) { GGLSurface buffer; @@ -857,7 +847,6 @@ static char const * const gExtensionsString = // "KHR_image_pixmap " "EGL_ANDROID_image_native_buffer " "EGL_ANDROID_swap_rectangle " - "EGL_ANDROID_get_render_buffer " ; // ---------------------------------------------------------------------------- @@ -910,8 +899,6 @@ static const extention_map_t gExtentionMap[] = { (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, { "eglSetSwapRectangleANDROID", (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, - { "eglGetRenderBufferANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID }, }; /* @@ -2129,18 +2116,3 @@ EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, return EGL_TRUE; } - -EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw) -{ - if (egl_display_t::is_valid(dpy) == EGL_FALSE) - return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0); - - egl_surface_t* d = static_cast<egl_surface_t*>(draw); - if (!d->isValid()) - return setError(EGL_BAD_SURFACE, (EGLClientBuffer)0); - if (d->dpy != dpy) - return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0); - - // post the surface - return d->getRenderBuffer(); -} diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 94b60a1..5e61607 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -61,7 +61,6 @@ static char const * const gExtensionString = "EGL_KHR_image_pixmap " "EGL_ANDROID_image_native_buffer " "EGL_ANDROID_swap_rectangle " - "EGL_ANDROID_get_render_buffer " ; // ---------------------------------------------------------------------------- @@ -408,8 +407,6 @@ static const extention_map_t gExtentionMap[] = { (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, { "eglSetSwapRectangleANDROID", (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID }, - { "eglGetRenderBufferANDROID", - (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID }, }; extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS]; @@ -1810,19 +1807,3 @@ EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw, } return setError(EGL_BAD_DISPLAY, NULL); } - -EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw) -{ - SurfaceRef _s(draw); - if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0); - - if (!validate_display_surface(dpy, draw)) - return 0; - egl_display_t const * const dp = get_display(dpy); - egl_surface_t const * const s = get_surface(draw); - if (s->cnx->egl.eglGetRenderBufferANDROID) { - return s->cnx->egl.eglGetRenderBufferANDROID( - dp->disp[s->impl].dpy, s->surface); - } - return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0); -} diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index c6e0a24..f08bd3c 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -17,7 +17,9 @@ package com.android.defcontainer; import com.android.internal.app.IMediaContainerService; +import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; + import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; @@ -37,6 +39,7 @@ import android.os.StatFs; import android.app.IntentService; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Pair; import java.io.File; import java.io.FileInputStream; @@ -44,6 +47,11 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.LinkedList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; import android.os.FileUtils; import android.provider.Settings; @@ -59,6 +67,8 @@ public class DefaultContainerService extends IntentService { private static final String TAG = "DefContainer"; private static final boolean localLOGV = true; + private static final String LIB_DIR_NAME = "lib"; + private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() { /* * Creates a new container and copies resource there. @@ -194,18 +204,51 @@ public class DefaultContainerService extends IntentService { Log.w(TAG, "Make sure sdcard is mounted."); return null; } - // Create new container at newCachePath + + // The .apk file String codePath = packageURI.getPath(); File codeFile = new File(codePath); - String newCachePath = null; + + // Calculate size of container needed to hold base APK. + long sizeBytes = codeFile.length(); + + // Check all the native files that need to be copied and add that to the container size. + ZipFile zipFile; + List<Pair<ZipEntry, String>> nativeFiles; + try { + zipFile = new ZipFile(codeFile); + + nativeFiles = new LinkedList<Pair<ZipEntry, String>>(); + + NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles); + + final int N = nativeFiles.size(); + for (int i = 0; i < N; i++) { + final Pair<ZipEntry, String> entry = nativeFiles.get(i); + + /* + * Note that PackageHelper.createSdDir adds a 1MB padding on + * our claimed size, so we don't have to worry about block + * alignment here. + */ + sizeBytes += entry.first.getSize(); + } + } catch (ZipException e) { + Log.w(TAG, "Failed to extract data from package file", e); + return null; + } catch (IOException e) { + Log.w(TAG, "Failed to cache package shared libs", e); + return null; + } + // Create new container - if ((newCachePath = PackageHelper.createSdDir(codeFile, - newCid, key, Process.myUid())) == null) { + String newCachePath = null; + if ((newCachePath = PackageHelper.createSdDir(sizeBytes, newCid, key, Process.myUid())) == null) { Log.e(TAG, "Failed to create container " + newCid); return null; } - if (localLOGV) Log.i(TAG, "Created container for " + newCid - + " at path : " + newCachePath); + if (localLOGV) + Log.i(TAG, "Created container for " + newCid + " at path : " + newCachePath); File resFile = new File(newCachePath, resFileName); if (!FileUtils.copyFile(new File(codePath), resFile)) { Log.e(TAG, "Failed to copy " + codePath + " to " + resFile); @@ -213,6 +256,32 @@ public class DefaultContainerService extends IntentService { PackageHelper.destroySdDir(newCid); return null; } + + try { + File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME); + sharedLibraryDir.mkdir(); + + final int N = nativeFiles.size(); + for (int i = 0; i < N; i++) { + final Pair<ZipEntry, String> entry = nativeFiles.get(i); + + InputStream is = zipFile.getInputStream(entry.first); + try { + File destFile = new File(sharedLibraryDir, entry.second); + if (!FileUtils.copyToFile(is, destFile)) { + throw new IOException("Couldn't copy native binary " + + entry.first.getName() + " to " + entry.second); + } + } finally { + is.close(); + } + } + } catch (IOException e) { + Log.e(TAG, "Couldn't copy native file to container", e); + PackageHelper.destroySdDir(newCid); + return null; + } + if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); if (!PackageHelper.finalizeSdDir(newCid)) { Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath); diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png Binary files differdeleted file mode 100644 index bc127bd..0000000 --- a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png Binary files differdeleted file mode 100644 index 59af804..0000000 --- a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png Binary files differdeleted file mode 100644 index 258de13..0000000 --- a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png Binary files differdeleted file mode 100644 index 258de13..0000000 --- a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/alert_bar_background.xml b/packages/SystemUI/res/drawable/alert_bar_background.xml deleted file mode 100644 index 24b6aa3..0000000 --- a/packages/SystemUI/res/drawable/alert_bar_background.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" - android:drawable="@drawable/alert_bar_background_pressed" /> - <item - android:drawable="@drawable/alert_bar_background_normal" /> -</selector> - diff --git a/packages/SystemUI/res/layout/intruder_alert.xml b/packages/SystemUI/res/layout/intruder_alert.xml deleted file mode 100644 index ba4a774..0000000 --- a/packages/SystemUI/res/layout/intruder_alert.xml +++ /dev/null @@ -1,58 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* apps/common/assets/default/default/skins/StatusBar.xml -** -** Copyright 2006, 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. -*/ ---> - -<!-- android:background="@drawable/status_bar_closed_default_background" --> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_height="32dip" - android:layout_width="match_parent" - android:paddingLeft="8dip" - android:paddingRight="8dip" - > - - <LinearLayout - android:id="@+id/intruder_alert_content" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center" - android:animationCache="false" - android:orientation="horizontal" - android:background="@drawable/alert_bar_background" - android:clickable="true" - android:focusable="true" - android:descendantFocusability="afterDescendants" - > - - <ImageView - android:id="@+id/alertIcon" - android:layout_width="25dip" - android:layout_height="25dip" - android:layout_marginLeft="6dip" - android:layout_marginRight="8dip" - /> - <TextView - android:id="@+id/alertText" - android:textAppearance="@style/TextAppearance.StatusBar.IntruderAlert" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:singleLine="true" - /> - </LinearLayout> -</FrameLayout> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java index a47415e..8f2da7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java @@ -91,11 +91,6 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks private static final int MSG_ANIMATE = 1000; private static final int MSG_ANIMATE_REVEAL = 1001; - private static final int MSG_SHOW_INTRUDER = 1002; - private static final int MSG_HIDE_INTRUDER = 1003; - - // will likely move to a resource or other tunable param at some point - private static final int INTRUDER_ALERT_DECAY_MS = 10000; StatusBarPolicy mIconPolicy; @@ -247,9 +242,6 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks // we're never destroyed } - // for immersive activities - private View mIntruderAlertView; - /** * Nobody binds to us. */ @@ -270,10 +262,6 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks R.layout.status_bar_expanded, null); expanded.mService = this; - mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null); - mIntruderAlertView.setVisibility(View.GONE); - mIntruderAlertView.setClickable(true); - StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null); sb.mService = this; @@ -354,23 +342,6 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks // TODO lp.windowAnimations = R.style.Animation_StatusBar; WindowManagerImpl.getDefault().addView(view, lp); - - lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - PixelFormat.TRANSLUCENT); - lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; - lp.y += height * 1.5; // FIXME - lp.setTitle("IntruderAlert"); - lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert; - - WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp); } public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { @@ -395,55 +366,23 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks } public void addNotification(IBinder key, StatusBarNotification notification) { - StatusBarIconView iconView = addNotificationViews(key, notification); - if (iconView == null) return; - - boolean immersive = false; - try { - immersive = ActivityManagerNative.getDefault().isTopActivityImmersive(); - Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive")); - } catch (RemoteException ex) { - } - if (immersive) { - if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) { - Slog.d(TAG, "Presenting high-priority notification in immersive activity"); - // @@@ special new transient ticker mode - // 1. Populate mIntruderAlertView - - ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon); - TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText); - alertIcon.setImageDrawable(StatusBarIconView.getIcon( - alertIcon.getContext(), - iconView.getStatusBarIcon())); - alertText.setText(notification.notification.tickerText); - - View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content); - button.setOnClickListener( - new Launcher(notification.notification.contentIntent, - notification.pkg, notification.tag, notification.id)); - - // 2. Animate mIntruderAlertView in - mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER); - - // 3. Set alarm to age the notification off (TODO) - mHandler.removeMessages(MSG_HIDE_INTRUDER); - mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS); - } - } else if (notification.notification.fullScreenIntent != null) { - // not immersive & a full-screen alert should be shown - Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;" - + " sending fullScreenIntent"); + boolean shouldTick = true; + if (notification.notification.fullScreenIntent != null) { + shouldTick = false; + Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); try { notification.notification.fullScreenIntent.send(); } catch (PendingIntent.CanceledException e) { } - } else { - // usual case: status bar visible & not immersive + } + + StatusBarIconView iconView = addNotificationViews(key, notification); + if (iconView == null) return; - // show the ticker + if (shouldTick) { tick(notification); } - + // Recalculate the position of the sliding windows and the titles. setAreThereNotifications(); updateExpandedViewPos(EXPANDED_LEAVE_ALONE); @@ -721,12 +660,6 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks case MSG_ANIMATE_REVEAL: doRevealAnimation(); break; - case MSG_SHOW_INTRUDER: - setIntruderAlertVisibility(true); - break; - case MSG_HIDE_INTRUDER: - setIntruderAlertVisibility(false); - break; } } } @@ -1109,9 +1042,6 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks // close the shade if it was open animateCollapse(); - - // If this click was on the intruder alert, hide that instead - mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER); } } @@ -1548,10 +1478,6 @@ public class StatusBarService extends Service implements CommandQueue.Callbacks } }; - private void setIntruderAlertVisibility(boolean vis) { - mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE); - } - /** * Reload some of our resources when the configuration changes. * diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 3bcf427..a38970f 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -858,18 +858,22 @@ public class LocationManagerService extends ILocationManager.Stub implements Run } private void updateProvidersLocked() { + boolean changesMade = false; for (int i = mProviders.size() - 1; i >= 0; i--) { LocationProviderInterface p = mProviders.get(i); boolean isEnabled = p.isEnabled(); String name = p.getName(); boolean shouldBeEnabled = isAllowedBySettingsLocked(name); - if (isEnabled && !shouldBeEnabled) { updateProviderListenersLocked(name, false); + changesMade = true; } else if (!isEnabled && shouldBeEnabled) { updateProviderListenersLocked(name, true); + changesMade = true; } - + } + if (changesMade) { + mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)); } } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 0ff33d1..a2d3298 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -18,6 +18,7 @@ package com.android.server; import com.android.internal.app.IMediaContainerService; import com.android.internal.app.ResolverActivity; +import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; @@ -112,6 +113,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -188,6 +190,8 @@ class PackageManagerService extends IPackageManager.Stub { "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); + private static final String LIB_DIR_NAME = "lib"; + static final String mTempContainerPrefix = "smdl2tmp"; final HandlerThread mHandlerThread = new HandlerThread("PackageManager", @@ -678,13 +682,6 @@ class PackageManagerService extends IPackageManager.Stub { return false; } - static boolean isFwdLocked(int flags) { - if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) { - return true; - } - return false; - } - public static final IPackageManager main(Context context, boolean factoryTest) { PackageManagerService m = new PackageManagerService(context, factoryTest); ServiceManager.addService("package", m); @@ -1497,6 +1494,7 @@ class PackageManagerService extends IPackageManager.Stub { ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString; ps.pkg.applicationInfo.sourceDir = ps.codePathString; ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg).getPath(); + ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; ps.pkg.mSetEnabled = ps.enabled; } return generatePackageInfo(ps.pkg, flags); @@ -2376,8 +2374,7 @@ class PackageManagerService extends IPackageManager.Stub { PackageParser.Package p = i.next(); if (p.applicationInfo != null && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 - && (!mSafeMode || (p.applicationInfo.flags - &ApplicationInfo.FLAG_SYSTEM) != 0)) { + && (!mSafeMode || isSystemApp(p))) { finalList.add(PackageParser.generateApplicationInfo(p, flags)); } } @@ -2621,9 +2618,9 @@ class PackageManagerService extends IPackageManager.Stub { + "reverting from " + ps.codePathString + ": new version " + pkg.mVersionCode + " better than installed " + ps.versionCode); - InstallArgs args = new FileInstallArgs(ps.codePathString, ps.resourcePathString); + InstallArgs args = new FileInstallArgs(ps.codePathString, + ps.resourcePathString, ps.nativeLibraryPathString); args.cleanUpResourcesLI(); - removeNativeBinariesLI(pkg); mSettings.enableSystemPackageLP(ps.name); } } @@ -2663,8 +2660,8 @@ class PackageManagerService extends IPackageManager.Stub { return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE); } - private static void setApplicationInfoPaths(PackageParser.Package pkg, - String destCodePath, String destResPath) { + private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath, + String destResPath) { pkg.mPath = pkg.mScanPath = destCodePath; pkg.applicationInfo.sourceDir = destCodePath; pkg.applicationInfo.publicSourceDir = destResPath; @@ -3146,10 +3143,10 @@ class PackageManagerService extends IPackageManager.Stub { if (dataPath.exists()) { mOutPermissions[1] = 0; FileUtils.getPermissions(dataPath.getPath(), mOutPermissions); - if (mOutPermissions[1] == pkg.applicationInfo.uid - || !Process.supportsProcesses()) { - pkg.applicationInfo.dataDir = dataPath.getPath(); - } else { + + // If we have mismatched owners for the data path, we have a + // problem (unless we're running in the simulator.) + if (mOutPermissions[1] != pkg.applicationInfo.uid && Process.supportsProcesses()) { boolean recovered = false; if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { // If this is a system app, we can at least delete its @@ -3186,6 +3183,7 @@ class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.dataDir = "/mismatched_uid/settings_" + pkg.applicationInfo.uid + "/fs_" + mOutPermissions[1]; + pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir; String msg = "Package " + pkg.packageName + " has mismatched uid: " + mOutPermissions[1] + " on disk, " @@ -3229,32 +3227,38 @@ class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.dataDir = null; } } - + + /* + * Set the data dir to the default "/data/data/<package name>/lib" + * if we got here without anyone telling us different (e.g., apps + * stored on SD card have their native libraries stored in the ASEC + * container with the APK). + */ + if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) { + pkg.applicationInfo.nativeLibraryDir = new File(dataPath, LIB_DIR_NAME).getPath(); + } + pkgSetting.uidError = uidError; } - // Perform shared library installation and dex validation and - // optimization, if this is not a system app. + // If we're running in the simulator, we don't need to unpack anything. if (mInstaller != null) { String path = scanFile.getPath(); - if (scanFileNewer) { - // Note: We don't want to unpack the native binaries for - // system applications, unless they have been updated - // (the binaries are already under /system/lib). - // - // In other words, we're going to unpack the binaries - // only for non-system apps and system app upgrades. - // - int flags = pkg.applicationInfo.flags; - if ((flags & ApplicationInfo.FLAG_SYSTEM) == 0 || - (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { - Log.i(TAG, path + " changed; unpacking"); - int err = cachePackageSharedLibsLI(pkg, scanFile); - if (err != PackageManager.INSTALL_SUCCEEDED) { - mLastScanError = err; - return null; - } - } + /* Note: We don't want to unpack the native binaries for + * system applications, unless they have been updated + * (the binaries are already under /system/lib). + * Also, don't unpack libs for apps on the external card + * since they should have their libraries in the ASEC + * container already. + * + * In other words, we're going to unpack the binaries + * only for non-system apps and system app upgrades. + */ + if ((!isSystemApp(pkg) || isUpdatedSystemApp(pkg)) && !isExternal(pkg)) { + Log.i(TAG, path + " changed; unpacking"); + File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir); + sharedLibraryDir.mkdir(); + NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir); } pkg.mScanPath = path; @@ -3517,6 +3521,7 @@ class PackageManagerService extends IPackageManager.Stub { a.info.sourceDir = pkg.applicationInfo.sourceDir; a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir; a.info.dataDir = pkg.applicationInfo.dataDir; + a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; mInstrumentation.put(a.getComponentName(), a); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { @@ -3557,266 +3562,30 @@ class PackageManagerService extends IPackageManager.Stub { } } - // The following constants are returned by cachePackageSharedLibsForAbiLI - // to indicate if native shared libraries were found in the package. - // Values are: - // PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed - // PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package - // PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found - // in package (and not installed) - // - private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0; - private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1; - private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2; - // Return the path of the directory that will contain the native binaries // of a given installed package. This is relative to the data path. // - private static File getNativeBinaryDirForPackage(PackageParser.Package pkg) { - return new File(pkg.applicationInfo.dataDir + "/lib"); - } - - // Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk - // and automatically copy them to /data/data/<appname>/lib if present. - // - // NOTE: this method may throw an IOException if the library cannot - // be copied to its final destination, e.g. if there isn't enough - // room left on the data partition, or a ZipException if the package - // file is malformed. - // - private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg, - File scanFile, String cpuAbi) throws IOException, ZipException { - File sharedLibraryDir = getNativeBinaryDirForPackage(pkg); - final String apkLib = "lib/"; - final int apkLibLen = apkLib.length(); - final int cpuAbiLen = cpuAbi.length(); - final String libPrefix = "lib"; - final int libPrefixLen = libPrefix.length(); - final String libSuffix = ".so"; - final int libSuffixLen = libSuffix.length(); - boolean hasNativeLibraries = false; - boolean installedNativeLibraries = false; - - // the minimum length of a valid native shared library of the form - // lib/<something>/lib<name>.so. - final int minEntryLen = apkLibLen + 2 + libPrefixLen + 1 + libSuffixLen; - - ZipFile zipFile = new ZipFile(scanFile); - Enumeration<ZipEntry> entries = - (Enumeration<ZipEntry>) zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - // skip directories - if (entry.isDirectory()) { - continue; - } - String entryName = entry.getName(); - - // check that the entry looks like lib/<something>/lib<name>.so - // here, but don't check the ABI just yet. - // - // - must be sufficiently long - // - must end with libSuffix, i.e. ".so" - // - must start with apkLib, i.e. "lib/" - if (entryName.length() < minEntryLen || - !entryName.endsWith(libSuffix) || - !entryName.startsWith(apkLib) ) { - continue; - } - - // file name must start with libPrefix, i.e. "lib" - int lastSlash = entryName.lastIndexOf('/'); - - if (lastSlash < 0 || - !entryName.regionMatches(lastSlash+1, libPrefix, 0, libPrefixLen) ) { - continue; - } - - hasNativeLibraries = true; - - // check the cpuAbi now, between lib/ and /lib<name>.so - // - if (lastSlash != apkLibLen + cpuAbiLen || - !entryName.regionMatches(apkLibLen, cpuAbi, 0, cpuAbiLen) ) - continue; - - // extract the library file name, ensure it doesn't contain - // weird characters. we're guaranteed here that it doesn't contain - // a directory separator though. - String libFileName = entryName.substring(lastSlash+1); - if (!FileUtils.isFilenameSafe(new File(libFileName))) { - continue; - } - - installedNativeLibraries = true; - - // Always extract the shared library - String sharedLibraryFilePath = sharedLibraryDir.getPath() + - File.separator + libFileName; - File sharedLibraryFile = new File(sharedLibraryFilePath); - - if (Config.LOGD) { - Log.d(TAG, "Caching shared lib " + entry.getName()); - } - if (mInstaller == null) { - sharedLibraryDir.mkdir(); - } - cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir, - sharedLibraryFile); - } - if (!hasNativeLibraries) - return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; - - if (!installedNativeLibraries) - return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH; - - return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; - } - - // Find the gdbserver executable program in a package at - // lib/<cpuAbi>/gdbserver and copy it to /data/data/<name>/lib/gdbserver - // - // Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success, - // or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise. - // - private int cachePackageGdbServerLI(PackageParser.Package pkg, - File scanFile, String cpuAbi) throws IOException, ZipException { - File installGdbServerDir = getNativeBinaryDirForPackage(pkg); - final String GDBSERVER = "gdbserver"; - final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER; - - ZipFile zipFile = new ZipFile(scanFile); - Enumeration<ZipEntry> entries = - (Enumeration<ZipEntry>) zipFile.entries(); - - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - // skip directories - if (entry.isDirectory()) { - continue; - } - String entryName = entry.getName(); - - if (!entryName.equals(apkGdbServerPath)) { - continue; - } - - String installGdbServerPath = installGdbServerDir.getPath() + - "/" + GDBSERVER; - File installGdbServerFile = new File(installGdbServerPath); - - if (Config.LOGD) { - Log.d(TAG, "Caching gdbserver " + entry.getName()); - } - if (mInstaller == null) { - installGdbServerDir.mkdir(); - } - cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir, - installGdbServerFile); - - return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES; - } - return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES; - } - - // extract shared libraries stored in the APK as lib/<cpuAbi>/lib<name>.so - // and copy them to /data/data/<appname>/lib. - // - // This function will first try the main CPU ABI defined by Build.CPU_ABI - // (which corresponds to ro.product.cpu.abi), and also try an alternate - // one if ro.product.cpu.abi2 is defined. - // - private int cachePackageSharedLibsLI(PackageParser.Package pkg, File scanFile) { - // Remove all native binaries from a directory. This is used when upgrading - // a package: in case the new .apk doesn't contain a native binary that was - // in the old one (and thus installed), we need to remove it from - // /data/data/<appname>/lib - // - // The simplest way to do that is to remove all files in this directory, - // since it is owned by "system", applications are not supposed to write - // anything there. - removeNativeBinariesLI(pkg); - - String cpuAbi = Build.CPU_ABI; - try { - int result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi); - - // some architectures are capable of supporting several CPU ABIs - // for example, 'armeabi-v7a' also supports 'armeabi' native code - // this is indicated by the definition of the ro.product.cpu.abi2 - // system property. - // - // only scan the package twice in case of ABI mismatch - if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { - final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null); - if (cpuAbi2 != null) { - result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi2); - } - - if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) { - Slog.w(TAG,"Native ABI mismatch from package file"); - return PackageManager.INSTALL_FAILED_INVALID_APK; - } - - if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { - cpuAbi = cpuAbi2; - } - } - - // for debuggable packages, also extract gdbserver from lib/<abi> - // into /data/data/<appname>/lib too. - if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES && - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) { - int result2 = cachePackageGdbServerLI(pkg, scanFile, cpuAbi); - if (result2 == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_NATIVE_DEBUGGABLE; - } - } - } catch (ZipException e) { - Slog.w(TAG, "Failed to extract data from package file", e); - return PackageManager.INSTALL_FAILED_INVALID_APK; - } catch (IOException e) { - Slog.w(TAG, "Failed to cache package shared libs", e); - return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + private File getNativeBinaryDirForPackage(PackageParser.Package pkg) { + final String nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; + if (nativeLibraryDir != null) { + return new File(nativeLibraryDir); + } else { + // Fall back for old packages + return new File(pkg.applicationInfo.dataDir, LIB_DIR_NAME); } - return PackageManager.INSTALL_SUCCEEDED; } - private void cacheNativeBinaryLI(PackageParser.Package pkg, - ZipFile zipFile, ZipEntry entry, - File binaryDir, - File binaryFile) throws IOException { - InputStream inputStream = zipFile.getInputStream(entry); - try { - File tempFile = File.createTempFile("tmp", "tmp", binaryDir); - String tempFilePath = tempFile.getPath(); - // XXX package manager can't change owner, so the executable files for - // now need to be left as world readable and owned by the system. - if (! FileUtils.copyToFile(inputStream, tempFile) || - ! tempFile.setLastModified(entry.getTime()) || - FileUtils.setPermissions(tempFilePath, - FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP - |FileUtils.S_IXUSR|FileUtils.S_IXGRP|FileUtils.S_IXOTH - |FileUtils.S_IROTH, -1, -1) != 0 || - ! tempFile.renameTo(binaryFile)) { - // Failed to properly write file. - tempFile.delete(); - throw new IOException("Couldn't create cached binary " - + binaryFile + " in " + binaryDir); - } - } finally { - inputStream.close(); - } + // Convenience call for removeNativeBinariesLI(File) + private void removeNativeBinariesLI(PackageParser.Package pkg) { + File nativeLibraryDir = getNativeBinaryDirForPackage(pkg); + removeNativeBinariesLI(nativeLibraryDir); } // Remove the native binaries of a given package. This simply // gets rid of the files in the 'lib' sub-directory. - private void removeNativeBinariesLI(PackageParser.Package pkg) { - File binaryDir = getNativeBinaryDirForPackage(pkg); - + public void removeNativeBinariesLI(File binaryDir) { if (DEBUG_NATIVE) { - Slog.w(TAG,"Deleting native binaries from: " + binaryDir.getPath()); + Slog.w(TAG, "Deleting native binaries from: " + binaryDir.getPath()); } // Just remove any file in the directory. Since the directory @@ -3824,15 +3593,14 @@ class PackageManagerService extends IPackageManager.Stub { // to have written anything there. // if (binaryDir.exists()) { - File[] binaries = binaryDir.listFiles(); + File[] binaries = binaryDir.listFiles(); if (binaries != null) { - for (int nn=0; nn < binaries.length; nn++) { + for (int nn = 0; nn < binaries.length; nn++) { if (DEBUG_NATIVE) { - Slog.d(TAG," Deleting " + binaries[nn].getName()); + Slog.d(TAG, " Deleting " + binaries[nn].getName()); } if (!binaries[nn].delete()) { - Slog.w(TAG,"Could not delete native binary: " + - binaries[nn].getPath()); + Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath()); } } } @@ -4144,11 +3912,10 @@ class PackageManagerService extends IPackageManager.Stub { || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH); if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + if (isSystemApp(pkg)) { // For updated system applications, the signatureOrSystem permission // is granted only if it had been defined by the original application. - if ((pkg.applicationInfo.flags - & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) { + if (isUpdatedSystemApp(pkg)) { PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName); if(sysPs.grantedPermissions.contains(perm)) { allowed = true; @@ -4936,7 +4703,7 @@ class PackageManagerService extends IPackageManager.Stub { // App explictly prefers external. Let policy decide } else { // Prefer previous location - if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { + if (isExternal(pkg)) { return PackageHelper.RECOMMEND_INSTALL_EXTERNAL; } return PackageHelper.RECOMMEND_INSTALL_INTERNAL; @@ -5048,16 +4815,16 @@ class PackageManagerService extends IPackageManager.Stub { final InstallArgs srcArgs; final InstallArgs targetArgs; int mRet; - MoveParams(InstallArgs srcArgs, - IPackageMoveObserver observer, - int flags, String packageName) { + + MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags, + String packageName, String dataDir) { this.srcArgs = srcArgs; this.observer = observer; this.flags = flags; this.packageName = packageName; if (srcArgs != null) { Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath())); - targetArgs = createInstallArgs(packageUri, flags, packageName); + targetArgs = createInstallArgs(packageUri, flags, packageName, dataDir); } else { targetArgs = null; } @@ -5113,21 +4880,22 @@ class PackageManagerService extends IPackageManager.Stub { } } - private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) { + private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath, + String nativeLibraryPath) { if (installOnSd(flags)) { - return new SdInstallArgs(fullCodePath, fullResourcePath); + return new SdInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath); } else { - return new FileInstallArgs(fullCodePath, fullResourcePath); + return new FileInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath); } } - private InstallArgs createInstallArgs(Uri packageURI, int flags, - String pkgName) { + // Used by package mover + private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName, String dataDir) { if (installOnSd(flags)) { String cid = getNextCodePath(null, pkgName, "/" + SdInstallArgs.RES_FILE_NAME); return new SdInstallArgs(packageURI, cid); } else { - return new FileInstallArgs(packageURI, pkgName); + return new FileInstallArgs(packageURI, pkgName, dataDir); } } @@ -5154,6 +4922,7 @@ class PackageManagerService extends IPackageManager.Stub { abstract int doPostInstall(int status); abstract String getCodePath(); abstract String getResourcePath(); + abstract String getNativeLibraryPath(); // Need installer lock especially for dex file removal. abstract void cleanUpResourcesLI(); abstract boolean doPostDeleteLI(boolean delete); @@ -5164,6 +4933,7 @@ class PackageManagerService extends IPackageManager.Stub { File installDir; String codeFileName; String resourceFileName; + String libraryPath; boolean created = false; FileInstallArgs(InstallParams params) { @@ -5171,21 +4941,22 @@ class PackageManagerService extends IPackageManager.Stub { params.flags, params.installerPackageName); } - FileInstallArgs(String fullCodePath, String fullResourcePath) { + FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { super(null, null, 0, null); File codeFile = new File(fullCodePath); installDir = codeFile.getParentFile(); codeFileName = fullCodePath; resourceFileName = fullResourcePath; + libraryPath = nativeLibraryPath; } - FileInstallArgs(Uri packageURI, String pkgName) { + FileInstallArgs(Uri packageURI, String pkgName, String dataDir) { super(packageURI, null, 0, null); - boolean fwdLocked = isFwdLocked(flags); - installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir; + installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; String apkName = getNextCodePath(null, pkgName, ".apk"); codeFileName = new File(installDir, apkName + ".apk").getPath(); resourceFileName = getResourcePathFromCodePath(); + libraryPath = new File(dataDir, LIB_DIR_NAME).getPath(); } boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException { @@ -5197,8 +4968,7 @@ class PackageManagerService extends IPackageManager.Stub { } void createCopyFile() { - boolean fwdLocked = isFwdLocked(flags); - installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir; + installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir; codeFileName = createTempPackageFile(installDir).getPath(); resourceFileName = getResourcePathFromCodePath(); created = true; @@ -5226,8 +4996,7 @@ class PackageManagerService extends IPackageManager.Stub { } ParcelFileDescriptor out = null; try { - out = ParcelFileDescriptor.open(codeFile, - ParcelFileDescriptor.MODE_READ_WRITE); + out = ParcelFileDescriptor.open(codeFile, ParcelFileDescriptor.MODE_READ_WRITE); } catch (FileNotFoundException e) { Slog.e(TAG, "Failed to create file descritpor for : " + codeFileName); return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; @@ -5241,6 +5010,11 @@ class PackageManagerService extends IPackageManager.Stub { } finally { try { if (out != null) out.close(); } catch (IOException e) {} } + + if (!temp) { + NativeLibraryHelper.copyNativeBinariesLI(codeFile, new File(libraryPath)); + } + return ret; } @@ -5296,6 +5070,11 @@ class PackageManagerService extends IPackageManager.Stub { } } + @Override + String getNativeLibraryPath() { + return libraryPath; + } + private boolean cleanUp() { boolean ret = true; String sourceDir = getCodePath(); @@ -5332,11 +5111,14 @@ class PackageManagerService extends IPackageManager.Stub { // we don't consider this to be a failure of the core package deletion } } + if (libraryPath != null) { + removeNativeBinariesLI(new File(libraryPath)); + } } private boolean setPermissions() { // TODO Do this in a more elegant way later on. for now just a hack - if (!isFwdLocked(flags)) { + if (!isFwdLocked()) { final int filePermissions = FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP |FileUtils.S_IROTH; @@ -5354,35 +5136,42 @@ class PackageManagerService extends IPackageManager.Stub { } boolean doPostDeleteLI(boolean delete) { + // XXX err, shouldn't we respect the delete flag? cleanUpResourcesLI(); return true; } + + private boolean isFwdLocked() { + return (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0; + } } class SdInstallArgs extends InstallArgs { - String cid; - String cachePath; static final String RES_FILE_NAME = "pkg.apk"; + String cid; + String packagePath; + String libraryPath; + SdInstallArgs(InstallParams params) { super(params.packageURI, params.observer, params.flags, params.installerPackageName); } - SdInstallArgs(String fullCodePath, String fullResourcePath) { + SdInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) { super(null, null, PackageManager.INSTALL_EXTERNAL, null); // Extract cid from fullCodePath int eidx = fullCodePath.lastIndexOf("/"); String subStr1 = fullCodePath.substring(0, eidx); int sidx = subStr1.lastIndexOf("/"); cid = subStr1.substring(sidx+1, eidx); - cachePath = subStr1; + setCachePath(subStr1); } SdInstallArgs(String cid) { super(null, null, PackageManager.INSTALL_EXTERNAL, null); this.cid = cid; - cachePath = PackageHelper.getSdDir(cid); + setCachePath(PackageHelper.getSdDir(cid)); } SdInstallArgs(Uri packageURI, String cid) { @@ -5402,21 +5191,30 @@ class PackageManagerService extends IPackageManager.Stub { if (temp) { createCopyFile(); } - cachePath = imcs.copyResourceToContainer( + String newCachePath = imcs.copyResourceToContainer( packageURI, cid, getEncryptKey(), RES_FILE_NAME); - return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR : - PackageManager.INSTALL_SUCCEEDED; + if (newCachePath != null) { + setCachePath(newCachePath); + return PackageManager.INSTALL_SUCCEEDED; + } else { + return PackageManager.INSTALL_FAILED_CONTAINER_ERROR; + } } @Override String getCodePath() { - return cachePath + "/" + RES_FILE_NAME; + return packagePath; } @Override String getResourcePath() { - return cachePath + "/" + RES_FILE_NAME; + return packagePath; + } + + @Override + String getNativeLibraryPath() { + return libraryPath; } int doPreInstall(int status) { @@ -5426,8 +5224,11 @@ class PackageManagerService extends IPackageManager.Stub { } else { boolean mounted = PackageHelper.isContainerMounted(cid); if (!mounted) { - cachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), Process.SYSTEM_UID); - if (cachePath == null) { + String newCachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), + Process.SYSTEM_UID); + if (newCachePath != null) { + setCachePath(newCachePath); + } else { return PackageManager.INSTALL_FAILED_CONTAINER_ERROR; } } @@ -5473,13 +5274,19 @@ class PackageManagerService extends IPackageManager.Stub { return false; } Log.i(TAG, "Succesfully renamed " + cid + - " at path: " + cachePath + " to " + newCacheId + + " to " + newCacheId + " at new path: " + newCachePath); cid = newCacheId; - cachePath = newCachePath; + setCachePath(newCachePath); return true; } + private void setCachePath(String newCachePath) { + File cachePath = new File(newCachePath); + libraryPath = new File(cachePath, LIB_DIR_NAME).getPath(); + packagePath = new File(cachePath, RES_FILE_NAME).getPath(); + } + int doPostInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); @@ -5695,7 +5502,7 @@ class PackageManagerService extends IPackageManager.Stub { return; } } - boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); + boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res); } else { @@ -5855,7 +5662,7 @@ class PackageManagerService extends IPackageManager.Stub { !ps.codePathString.equals(oldPkgSetting.codePathString)) { int installFlags = 0; res.removedInfo.args = createInstallArgs(0, oldPkgSetting.codePathString, - oldPkgSetting.resourcePathString); + oldPkgSetting.resourcePathString, oldPkgSetting.nativeLibraryPathString); } } } @@ -6006,6 +5813,7 @@ class PackageManagerService extends IPackageManager.Stub { } // Set application objects path explicitly after the rename setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); + pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath(); if (replace) { replacePackageLI(pkg, parseFlags, scanMode, installerPackageName, res); @@ -6020,8 +5828,7 @@ class PackageManagerService extends IPackageManager.Stub { int retCode = 0; // TODO Gross hack but fix later. Ideally move this to be a post installation // check after alloting uid. - if ((newPackage.applicationInfo.flags - & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) { + if (isForwardLocked(newPackage)) { File destResourceFile = new File(newPackage.applicationInfo.publicSourceDir); try { extractPublicFiles(newPackage, destResourceFile); @@ -6056,12 +5863,20 @@ class PackageManagerService extends IPackageManager.Stub { return PackageManager.INSTALL_SUCCEEDED; } - private boolean isForwardLocked(PackageParser.Package pkg) { - return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0); + private static boolean isForwardLocked(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0; + } + + private static boolean isExternal(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; + } + + private static boolean isSystemApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } - private boolean isExternal(PackageParser.Package pkg) { - return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0); + private static boolean isUpdatedSystemApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } private void extractPublicFiles(PackageParser.Package newPackage, @@ -6291,7 +6106,7 @@ class PackageManagerService extends IPackageManager.Stub { // we don't consider this to be a failure of the core package deletion } } else { - //for emulator + // for simulator PackageParser.Package pkg = mPackages.get(packageName); File dataDir = new File(pkg.applicationInfo.dataDir); dataDir.delete(); @@ -6374,7 +6189,7 @@ class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { // Reinstate the old system package mSettings.enableSystemPackageLP(p.packageName); - // Remove any native libraries. + // Remove any native libraries. XXX needed? removeNativeBinariesLI(p); } // Install the system package @@ -6410,12 +6225,10 @@ class PackageManagerService extends IPackageManager.Stub { // Delete application code and resources if (deleteCodeAndResources) { // TODO can pick up from PackageSettings as well - int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE)!=0) ? - PackageManager.INSTALL_EXTERNAL : 0; - installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ? - PackageManager.INSTALL_FORWARD_LOCK : 0; - outInfo.args = createInstallArgs(installFlags, - applicationInfo.sourceDir, applicationInfo.publicSourceDir); + int installFlags = isExternal(p) ? PackageManager.INSTALL_EXTERNAL : 0; + installFlags |= isForwardLocked(p) ? PackageManager.INSTALL_FORWARD_LOCK : 0; + outInfo.args = createInstallArgs(installFlags, applicationInfo.sourceDir, + applicationInfo.publicSourceDir, applicationInfo.nativeLibraryDir); } return true; } @@ -6460,7 +6273,7 @@ class PackageManagerService extends IPackageManager.Stub { return false; } boolean ret = false; - if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (isSystemApp(p)) { Log.i(TAG, "Removing system package:"+p.packageName); // When an updated system application is deleted we delete the existing resources as well and // fall back to existing code in system partition @@ -7160,10 +6973,14 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" pkg="); pw.println(ps.pkg); pw.print(" codePath="); pw.println(ps.codePathString); pw.print(" resourcePath="); pw.println(ps.resourcePathString); + pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); pw.print(" obbPath="); pw.println(ps.obbPathString); if (ps.pkg != null) { pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion); + if (ps.pkg.mOperationPending) { + pw.println(" mOperationPending=true"); + } pw.print(" supportsScreens=["); boolean first = true; if ((ps.pkg.applicationInfo.flags & @@ -7211,9 +7028,6 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); pw.print(" installStatus="); pw.print(ps.installStatus); pw.print(" enabled="); pw.println(ps.enabled); - if (ps.pkg.mOperationPending) { - pw.println(" mOperationPending=true"); - } if (ps.disabledComponents.size() > 0) { pw.println(" disabledComponents:"); for (String s : ps.disabledComponents) { @@ -7730,6 +7544,7 @@ class PackageManagerService extends IPackageManager.Stub { String codePathString; File resourcePath; String resourcePathString; + String nativeLibraryPathString; String obbPathString; private long timeStamp; private String timeStampString = "0"; @@ -7769,7 +7584,7 @@ class PackageManagerService extends IPackageManager.Stub { this.resourcePathString = resourcePath.toString(); this.versionCode = pVersionCode; } - + public void setInstallerPackageName(String packageName) { installerPackageName = packageName; } @@ -8282,8 +8097,8 @@ class PackageManagerService extends IPackageManager.Stub { private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) { p.pkg = pkg; pkg.mSetEnabled = p.enabled; - String codePath = pkg.applicationInfo.sourceDir; - String resourcePath = pkg.applicationInfo.publicSourceDir; + final String codePath = pkg.applicationInfo.sourceDir; + final String resourcePath = pkg.applicationInfo.publicSourceDir; // Update code path if needed if (!codePath.equalsIgnoreCase(p.codePathString)) { Slog.w(TAG, "Code path for pkg : " + p.pkg.packageName + @@ -8298,6 +8113,12 @@ class PackageManagerService extends IPackageManager.Stub { p.resourcePath = new File(resourcePath); p.resourcePathString = resourcePath; } + // Update the native library path if needed + final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir; + if (nativeLibraryPath != null + && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) { + p.nativeLibraryPathString = nativeLibraryPath; + } // Update version code if needed if (pkg.mVersionCode != p.versionCode) { p.versionCode = pkg.mVersionCode; @@ -8595,7 +8416,7 @@ class PackageManagerService extends IPackageManager.Stub { StringBuilder sb = new StringBuilder(); for (PackageSetting pkg : mPackages.values()) { ApplicationInfo ai = pkg.pkg.applicationInfo; - String dataPath = ai.dataDir; + String dataPath = ai.dataDir; boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; // Avoid any application that has a space in its path @@ -8668,6 +8489,9 @@ class PackageManagerService extends IPackageManager.Stub { if (!pkg.resourcePathString.equals(pkg.codePathString)) { serializer.attribute(null, "resourcePath", pkg.resourcePathString); } + if (pkg.nativeLibraryPathString != null) { + serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); + } if (pkg.sharedUser == null) { serializer.attribute(null, "userId", Integer.toString(pkg.userId)); @@ -8707,6 +8531,9 @@ class PackageManagerService extends IPackageManager.Stub { if (!pkg.resourcePathString.equals(pkg.codePathString)) { serializer.attribute(null, "resourcePath", pkg.resourcePathString); } + if (pkg.nativeLibraryPathString != null) { + serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); + } serializer.attribute(null, "flags", Integer.toString(pkg.pkgFlags)); serializer.attribute(null, "ts", pkg.getTimeStampStr()); @@ -9111,6 +8938,7 @@ class PackageManagerService extends IPackageManager.Stub { String sharedIdStr = null; String codePathStr = null; String resourcePathStr = null; + String nativeLibraryPathStr = null; String obbPathStr = null; String systemStr = null; String installerPackageName = null; @@ -9129,6 +8957,7 @@ class PackageManagerService extends IPackageManager.Stub { sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); codePathStr = parser.getAttributeValue(null, "codePath"); resourcePathStr = parser.getAttributeValue(null, "resourcePath"); + nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath"); obbPathStr = parser.getAttributeValue(null, "obbPath"); version = parser.getAttributeValue(null, "version"); if (version != null) { @@ -9227,6 +9056,7 @@ class PackageManagerService extends IPackageManager.Stub { if (packageSetting != null) { packageSetting.uidError = "true".equals(uidError); packageSetting.installerPackageName = installerPackageName; + packageSetting.nativeLibraryPathString = nativeLibraryPathStr; packageSetting.obbPathString = obbPathStr; final String enabledStr = parser.getAttributeValue(null, "enabled"); if (enabledStr != null) { @@ -9893,12 +9723,10 @@ class PackageManagerService extends IPackageManager.Stub { returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; } else { // Disable moving fwd locked apps and system packages - if (pkg.applicationInfo != null && - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + if (pkg.applicationInfo != null && isSystemApp(pkg)) { Slog.w(TAG, "Cannot move system application"); returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; - } else if (pkg.applicationInfo != null && - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) { + } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) { Slog.w(TAG, "Cannot move forward locked app."); returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED; } else if (pkg.mOperationPending) { @@ -9913,8 +9741,8 @@ class PackageManagerService extends IPackageManager.Stub { } else { newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL; - currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ? - PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL; + currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL + : PackageManager.INSTALL_INTERNAL; if (newFlags == currFlags) { Slog.w(TAG, "No move required. Trying to move to same location"); returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION; @@ -9926,13 +9754,13 @@ class PackageManagerService extends IPackageManager.Stub { } } if (returnCode != PackageManager.MOVE_SUCCEEDED) { - processPendingMove(new MoveParams(null, observer, 0, packageName), returnCode); + processPendingMove(new MoveParams(null, observer, 0, packageName, null), returnCode); } else { Message msg = mHandler.obtainMessage(INIT_COPY); InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir, - pkg.applicationInfo.publicSourceDir); - MoveParams mp = new MoveParams(srcArgs, observer, newFlags, - packageName); + pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir); + MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName, + pkg.applicationInfo.dataDir); msg.obj = mp; mHandler.sendMessage(msg); } @@ -9950,7 +9778,7 @@ class PackageManagerService extends IPackageManager.Stub { ArrayList<String> pkgList = null; synchronized (mPackages) { PackageParser.Package pkg = mPackages.get(mp.packageName); - if (pkg == null ) { + if (pkg == null) { Slog.w(TAG, " Package " + mp.packageName + " doesn't exist. Aborting move"); returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST; @@ -9983,9 +9811,10 @@ class PackageManagerService extends IPackageManager.Stub { " Aborting move and returning error"); returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR; } else { - String oldCodePath = pkg.mPath; - String newCodePath = mp.targetArgs.getCodePath(); - String newResPath = mp.targetArgs.getResourcePath(); + final String oldCodePath = pkg.mPath; + final String newCodePath = mp.targetArgs.getCodePath(); + final String newResPath = mp.targetArgs.getResourcePath(); + final String newNativePath = mp.targetArgs.getNativeLibraryPath(); pkg.mPath = newCodePath; // Move dex files around if (moveDexFilesLI(pkg) @@ -9998,6 +9827,7 @@ class PackageManagerService extends IPackageManager.Stub { pkg.mScanPath = newCodePath; pkg.applicationInfo.sourceDir = newCodePath; pkg.applicationInfo.publicSourceDir = newResPath; + pkg.applicationInfo.nativeLibraryDir = newNativePath; PackageSetting ps = (PackageSetting) pkg.mExtras; ps.codePath = new File(pkg.applicationInfo.sourceDir); ps.codePathString = ps.codePath.getPath(); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d535343..5d5e862 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -5687,35 +5687,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - public void setImmersive(IBinder token, boolean immersive) { - synchronized(this) { - int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1; - if (index < 0) { - throw new IllegalArgumentException(); - } - ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); - r.immersive = immersive; - } - } - - public boolean isImmersive(IBinder token) { - synchronized (this) { - int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1; - if (index < 0) { - throw new IllegalArgumentException(); - } - ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index); - return r.immersive; - } - } - - public boolean isTopActivityImmersive() { - synchronized (this) { - ActivityRecord r = mMainStack.topRunningActivityLocked(null); - return (r != null) ? r.immersive : false; - } - } - public final void enterSafeMode() { synchronized(this) { // It only makes sense to do this before the system is ready diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 62be918..1687db1 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -103,7 +103,6 @@ class ActivityRecord extends IApplicationToken.Stub { boolean idle; // has the activity gone idle? boolean hasBeenLaunched;// has this activity ever been launched? boolean frozenBeforeDestroy;// has been frozen but not yet destroyed. - boolean immersive; // immersive mode (don't interrupt if possible) String stringName; // for caching of toString(). @@ -160,7 +159,6 @@ class ActivityRecord extends IApplicationToken.Stub { pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); pw.print(" inHistory="); pw.print(inHistory); pw.print(" persistent="); pw.print(persistent); - pw.print(" immersive="); pw.print(immersive); pw.print(" launchMode="); pw.println(launchMode); pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen); pw.print(" visible="); pw.print(visible); @@ -287,8 +285,6 @@ class ActivityRecord extends IApplicationToken.Stub { } else { isHomeActivity = false; } - - immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0; } else { realActivity = null; taskAffinity = null; @@ -300,7 +296,6 @@ class ActivityRecord extends IApplicationToken.Stub { packageName = null; fullscreen = true; isHomeActivity = false; - immersive = false; } } diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java index b665d2f..1078701 100644 --- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java @@ -76,17 +76,7 @@ public class StatusBarTest extends TestActivity win.setAttributes(winParams); } }, - new Test("Immersive: Enter") { - public void run() { - setImmersive(true); - } - }, - new Test("Immersive: Exit") { - public void run() { - setImmersive(false); - } - }, - new Test("Priority notification") { + new Test("fullScreenIntent") { public void run() { Notification not = new Notification(StatusBarTest.this, R.drawable.stat_sys_phone, @@ -96,9 +86,8 @@ public class StatusBarTest extends TestActivity "(888) 555-5038", null ); - not.flags |= Notification.FLAG_HIGH_PRIORITY; Intent fullScreenIntent = new Intent(StatusBarTest.this, TestAlertActivity.class); - int id = (int)System.currentTimeMillis(); // XXX HAX + int id = (int)System.currentTimeMillis(); fullScreenIntent.putExtra("id", id); not.fullScreenIntent = PendingIntent.getActivity( StatusBarTest.this, |