diff options
Diffstat (limited to 'core')
51 files changed, 1766 insertions, 748 deletions
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index 1cd7aa7..1d9e0f1 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -1483,7 +1483,13 @@ public class AccountManagerService } private static String getDatabaseName() { - return DATABASE_NAME; + if(Environment.isEncryptedFilesystemEnabled()) { + // Hard-coded path in case of encrypted file system + return Environment.getSystemSecureDirectory().getPath() + File.separator + DATABASE_NAME; + } else { + // Regular path in case of non-encrypted file system + return DATABASE_NAME; + } } private class DatabaseHelper extends SQLiteOpenHelper { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index f471f57..11b7b02 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2173,6 +2173,39 @@ class ContextImpl extends Context { throws NameNotFoundException { return getApplicationIcon(getApplicationInfo(packageName, 0)); } + + @Override + public Drawable getActivityLogo(ComponentName activityName) + throws NameNotFoundException { + return getActivityInfo(activityName, 0).loadLogo(this); + } + + @Override + public Drawable getActivityLogo(Intent intent) + throws NameNotFoundException { + if (intent.getComponent() != null) { + return getActivityLogo(intent.getComponent()); + } + + ResolveInfo info = resolveActivity( + intent, PackageManager.MATCH_DEFAULT_ONLY); + if (info != null) { + return info.activityInfo.loadLogo(this); + } + + throw new NameNotFoundException(intent.toUri(0)); + } + + @Override + public Drawable getApplicationLogo(ApplicationInfo info) { + return info.loadLogo(this); + } + + @Override + public Drawable getApplicationLogo(String packageName) + throws NameNotFoundException { + return getApplicationLogo(getApplicationInfo(packageName, 0)); + } @Override public Resources getResourcesForActivity( ComponentName activityName) throws NameNotFoundException { diff --git a/core/java/android/app/NativeActivity.java b/core/java/android/app/NativeActivity.java new file mode 100644 index 0000000..fd20b71 --- /dev/null +++ b/core/java/android/app/NativeActivity.java @@ -0,0 +1,141 @@ +package android.app; + +import dalvik.system.PathClassLoader; + +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.view.SurfaceHolder; + +import java.io.File; + +/** + * Convenience for implementing an activity that will be implemented + * purely in native code. That is, a game (or game-like thing). + */ +public class NativeActivity extends Activity implements SurfaceHolder.Callback { + public static final String META_DATA_LIB_NAME = "android.app.lib_name"; + + private int mNativeHandle; + + private native int loadNativeCode(String path); + private native void unloadNativeCode(int handle); + + private native void onStartNative(int handle); + private native void onResumeNative(int handle); + private native void onSaveInstanceStateNative(int handle); + private native void onPauseNative(int handle); + private native void onStopNative(int handle); + private native void onLowMemoryNative(int handle); + private native void onWindowFocusChangedNative(int handle, boolean focused); + private native void onSurfaceCreatedNative(int handle, SurfaceHolder holder); + private native void onSurfaceChangedNative(int handle, SurfaceHolder holder, + int format, int width, int height); + private native void onSurfaceDestroyedNative(int handle, SurfaceHolder holder); + + @Override + protected void onCreate(Bundle savedInstanceState) { + String libname = "main"; + ActivityInfo ai; + + getWindow().takeSurface(this); + + try { + ai = getPackageManager().getActivityInfo( + getIntent().getComponent(), PackageManager.GET_META_DATA); + if (ai.metaData != null) { + String ln = ai.metaData.getString(META_DATA_LIB_NAME); + if (ln != null) libname = ln; + } + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException("Error getting activity info", e); + } + + String path = null; + + if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) == 0) { + // If the application does not have (Java) code, then no ClassLoader + // has been set up for it. We will need to do our own search for + // the native code. + path = ai.applicationInfo.dataDir + "/lib/" + System.mapLibraryName(libname); + if (!(new File(path)).exists()) { + path = null; + } + } + + if (path == null) { + path = ((PathClassLoader)getClassLoader()).findLibrary(libname); + } + + if (path == null) { + throw new IllegalArgumentException("Unable to find native library: " + libname); + } + + mNativeHandle = loadNativeCode(path); + if (mNativeHandle == 0) { + throw new IllegalArgumentException("Unable to load native library: " + path); + } + super.onCreate(savedInstanceState); + } + + @Override + protected void onDestroy() { + unloadNativeCode(mNativeHandle); + super.onDestroy(); + } + + @Override + protected void onPause() { + super.onPause(); + onPauseNative(mNativeHandle); + } + + @Override + protected void onResume() { + super.onResume(); + onResumeNative(mNativeHandle); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + onSaveInstanceStateNative(mNativeHandle); + } + + @Override + protected void onStart() { + super.onStart(); + onStartNative(mNativeHandle); + } + + @Override + protected void onStop() { + super.onStop(); + onStopNative(mNativeHandle); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + onLowMemoryNative(mNativeHandle); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + onWindowFocusChangedNative(mNativeHandle, hasFocus); + } + + public void surfaceCreated(SurfaceHolder holder) { + onSurfaceCreatedNative(mNativeHandle, holder); + } + + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + onSurfaceChangedNative(mNativeHandle, holder, format, width, height); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + onSurfaceDestroyedNative(mNativeHandle, holder); + } +} diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 98a4993..6413cec 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -317,7 +317,9 @@ public class SyncStorageEngine extends Handler { if (sSyncStorageEngine != null) { return; } - File dataDir = Environment.getDataDirectory(); + // This call will return the correct directory whether Encrypted File Systems is + // enabled or not. + File dataDir = Environment.getSecureDataDirectory(); sSyncStorageEngine = new SyncStorageEngine(context, dataDir); } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 1577f9e..7047113 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -174,7 +174,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * Value for {@link #flags}: true when the application's window can be * increased in size for larger screens. Corresponds to * {@link android.R.styleable#AndroidManifestSupportsScreens_largeScreens - * android:smallScreens}. + * android:largeScreens}. */ public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<11; @@ -252,6 +252,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_RESTORE_ANY_VERSION = 1<<17; /** + * Value for {@link #flags}: Set to true if the application has been + * installed using the forward lock option. + * * Value for {@link #flags}: Set to true if the application is * currently installed on external/removable/unprotected storage. Such * applications may not be available if their storage is not currently @@ -262,12 +265,30 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_EXTERNAL_STORAGE = 1<<18; /** + * Value for {@link #flags}: true when the application's window can be + * increased in size for extra large screens. Corresponds to + * {@link android.R.styleable#AndroidManifestSupportsScreens_xlargeScreens + * android:xlargeScreens}. + */ + public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19; + + /** + * Value for {@link #flags}: this is true if the application has set + * its android:neverEncrypt to true, false otherwise. It is used to specify + * that this package specifically "opts-out" of a secured file system solution, + * and will always store its data in-the-clear. + * + * {@hide} + */ + public static final int FLAG_NEVER_ENCRYPT = 1<<30; + + /** * Value for {@link #flags}: Set to true if the application has been * installed using the forward lock option. * * {@hide} */ - public static final int FLAG_FORWARD_LOCK = 1<<20; + public static final int FLAG_FORWARD_LOCK = 1<<29; /** * Value for {@link #flags}: Set to true if the application is @@ -275,7 +296,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * * {@hide} */ - public static final int FLAG_NATIVE_DEBUGGABLE = 1<<21; + public static final int FLAG_NATIVE_DEBUGGABLE = 1<<28; /** * Flags associated with the application. Any combination of @@ -285,7 +306,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP}, * {@link #FLAG_TEST_ONLY}, {@link #FLAG_SUPPORTS_SMALL_SCREENS}, * {@link #FLAG_SUPPORTS_NORMAL_SCREENS}, - * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_RESIZEABLE_FOR_SCREENS}, + * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS}, + * {@link #FLAG_RESIZEABLE_FOR_SCREENS}, * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE} */ public int flags = 0; @@ -517,7 +539,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public void disableCompatibilityMode() { flags |= (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS | FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS | - FLAG_SUPPORTS_SCREEN_DENSITIES); + FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS); } /** diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java index cafe372..f16c4ef 100644 --- a/core/java/android/content/pm/ComponentInfo.java +++ b/core/java/android/content/pm/ComponentInfo.java @@ -157,6 +157,14 @@ public class ComponentInfo extends PackageItemInfo { /** * @hide */ + @Override + protected Drawable loadDefaultLogo(PackageManager pm) { + return applicationInfo.loadLogo(pm); + } + + /** + * @hide + */ @Override protected ApplicationInfo getApplicationInfo() { return applicationInfo; } diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java index 14c0680..d73aaf6 100644 --- a/core/java/android/content/pm/PackageItemInfo.java +++ b/core/java/android/content/pm/PackageItemInfo.java @@ -67,6 +67,14 @@ public class PackageItemInfo { public int icon; /** + * A drawable resource identifier (in the package's resources) of this + * component's logo. Logos may be larger/wider than icons and are + * displayed by certain UI elements in place of a name or name/icon + * combination. From the "logo" attribute or, if not set, 0. + */ + public int logo; + + /** * Additional meta-data associated with this component. This field * will only be filled in if you set the * {@link PackageManager#GET_META_DATA} flag when requesting the info. @@ -84,6 +92,7 @@ public class PackageItemInfo { nonLocalizedLabel = orig.nonLocalizedLabel; if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim(); icon = orig.icon; + logo = orig.logo; metaData = orig.metaData; } @@ -152,6 +161,42 @@ public class PackageItemInfo { } /** + * Retrieve the current graphical logo associated with this item. This + * will call back on the given PackageManager to load the logo from + * the application. + * + * @param pm A PackageManager from which the logo can be loaded; usually + * the PackageManager from which you originally retrieved this item. + * + * @return Returns a Drawable containing the item's logo. If the item + * does not have a logo, this method will return null. + */ + public Drawable loadLogo(PackageManager pm) { + if (logo != 0) { + Drawable d = pm.getDrawable(packageName, logo, getApplicationInfo()); + if (d != null) { + return d; + } + } + return loadDefaultLogo(pm); + } + + /** + * Retrieve the default graphical logo associated with this item. + * + * @param pm A PackageManager from which the logo can be loaded; usually + * the PackageManager from which you originally retrieved this item. + * + * @return Returns a Drawable containing the item's default logo + * or null if no default logo is available. + * + * @hide + */ + protected Drawable loadDefaultLogo(PackageManager pm) { + return null; + } + + /** * Load an XML resource attached to the meta-data of this item. This will * retrieved the name meta-data entry, and if defined call back on the * given PackageManager to load its XML file from the application. @@ -196,6 +241,7 @@ public class PackageItemInfo { dest.writeInt(labelRes); TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags); dest.writeInt(icon); + dest.writeInt(logo); dest.writeBundle(metaData); } @@ -206,6 +252,7 @@ public class PackageItemInfo { nonLocalizedLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); icon = source.readInt(); + logo = source.readInt(); metaData = source.readBundle(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 68b44e7..196f508 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1597,6 +1597,79 @@ public abstract class PackageManager { throws NameNotFoundException; /** + * Retrieve the logo associated with an activity. Given the full name of + * an activity, retrieves the information about it and calls + * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo. + * If the activity can not be found, NameNotFoundException is thrown. + * + * @param activityName Name of the activity whose logo is to be retrieved. + * + * @return Returns the image of the logo or null if the activity has no + * logo specified. + * + * @throws NameNotFoundException Thrown if the resources for the given + * activity could not be loaded. + * + * @see #getActivityLogo(Intent) + */ + public abstract Drawable getActivityLogo(ComponentName activityName) + throws NameNotFoundException; + + /** + * Retrieve the logo associated with an Intent. If intent.getClassName() is + * set, this simply returns the result of + * getActivityLogo(intent.getClassName()). Otherwise it resolves the intent's + * component and returns the logo associated with the resolved component. + * If intent.getClassName() can not be found or the Intent can not be resolved + * to a component, NameNotFoundException is thrown. + * + * @param intent The intent for which you would like to retrieve a logo. + * + * @return Returns the image of the logo, or null if the activity has no + * logo specified. + * + * @throws NameNotFoundException Thrown if the resources for application + * matching the given intent could not be loaded. + * + * @see #getActivityLogo(ComponentName) + */ + public abstract Drawable getActivityLogo(Intent intent) + throws NameNotFoundException; + + /** + * Retrieve the logo associated with an application. If it has not specified + * a logo, this method returns null. + * + * @param info Information about application being queried. + * + * @return Returns the image of the logo, or null if no logo is specified + * by the application. + * + * @see #getApplicationLogo(String) + */ + public abstract Drawable getApplicationLogo(ApplicationInfo info); + + /** + * Retrieve the logo associated with an application. Given the name of the + * application's package, retrieves the information about it and calls + * getApplicationLogo() to return its logo. If the application can not be + * found, NameNotFoundException is thrown. + * + * @param packageName Name of the package whose application logo is to be + * retrieved. + * + * @return Returns the image of the logo, or null if no application logo + * has been specified. + * + * @throws NameNotFoundException Thrown if the resources for the given + * application could not be loaded. + * + * @see #getApplicationLogo(ApplicationInfo) + */ + public abstract Drawable getApplicationLogo(String packageName) + throws NameNotFoundException; + + /** * Retrieve text from a package. This is a low-level API used by * the various package manager info structures (such as * {@link ComponentInfo} to implement retrieval of their associated diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 2a20a2d..4ddc124 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -105,17 +105,19 @@ public class PackageParser { final int nameRes; final int labelRes; final int iconRes; + final int logoRes; String tag; TypedArray sa; ParsePackageItemArgs(Package _owner, String[] _outError, - int _nameRes, int _labelRes, int _iconRes) { + int _nameRes, int _labelRes, int _iconRes, int _logoRes) { owner = _owner; outError = _outError; nameRes = _nameRes; labelRes = _labelRes; iconRes = _iconRes; + logoRes = _logoRes; } } @@ -127,10 +129,10 @@ public class PackageParser { int flags; ParseComponentArgs(Package _owner, String[] _outError, - int _nameRes, int _labelRes, int _iconRes, + int _nameRes, int _labelRes, int _iconRes, int _logoRes, String[] _sepProcesses, int _processRes, int _descriptionRes, int _enabledRes) { - super(_owner, _outError, _nameRes, _labelRes, _iconRes); + super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes); sepProcesses = _sepProcesses; processRes = _processRes; descriptionRes = _descriptionRes; @@ -789,6 +791,7 @@ public class PackageParser { int supportsSmallScreens = 1; int supportsNormalScreens = 1; int supportsLargeScreens = 1; + int supportsXLargeScreens = 1; int resizeable = 1; int anyDensity = 1; @@ -996,9 +999,12 @@ public class PackageParser { supportsLargeScreens = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, supportsLargeScreens); + supportsXLargeScreens = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_xlargeScreens, + supportsXLargeScreens); resizeable = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, - supportsLargeScreens); + resizeable); anyDensity = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, anyDensity); @@ -1132,6 +1138,11 @@ public class PackageParser { >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; } + if (supportsXLargeScreens < 0 || (supportsXLargeScreens > 0 + && pkg.applicationInfo.targetSdkVersion + >= android.os.Build.VERSION_CODES.GINGERBREAD)) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS; + } if (resizeable < 0 || (resizeable > 0 && pkg.applicationInfo.targetSdkVersion >= android.os.Build.VERSION_CODES.DONUT)) { @@ -1241,7 +1252,8 @@ public class PackageParser { "<permission-group>", sa, com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, - com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon)) { + com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, + com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1276,7 +1288,8 @@ public class PackageParser { "<permission>", sa, com.android.internal.R.styleable.AndroidManifestPermission_name, com.android.internal.R.styleable.AndroidManifestPermission_label, - com.android.internal.R.styleable.AndroidManifestPermission_icon)) { + com.android.internal.R.styleable.AndroidManifestPermission_icon, + com.android.internal.R.styleable.AndroidManifestPermission_logo)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1329,7 +1342,8 @@ public class PackageParser { "<permission-tree>", sa, com.android.internal.R.styleable.AndroidManifestPermissionTree_name, com.android.internal.R.styleable.AndroidManifestPermissionTree_label, - com.android.internal.R.styleable.AndroidManifestPermissionTree_icon)) { + com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, + com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1373,7 +1387,8 @@ public class PackageParser { mParseInstrumentationArgs = new ParsePackageItemArgs(owner, outError, com.android.internal.R.styleable.AndroidManifestInstrumentation_name, com.android.internal.R.styleable.AndroidManifestInstrumentation_label, - com.android.internal.R.styleable.AndroidManifestInstrumentation_icon); + com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, + com.android.internal.R.styleable.AndroidManifestInstrumentation_logo); mParseInstrumentationArgs.tag = "<instrumentation>"; } @@ -1485,6 +1500,8 @@ public class PackageParser { ai.icon = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); + ai.logo = sa.getResourceId( + com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); ai.theme = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); ai.descriptionRes = sa.getResourceId( @@ -1542,6 +1559,12 @@ public class PackageParser { ai.flags |= ApplicationInfo.FLAG_TEST_ONLY; } + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_neverEncrypt, + false)) { + ai.flags |= ApplicationInfo.FLAG_NEVER_ENCRYPT; + } + String str; str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); @@ -1705,7 +1728,7 @@ public class PackageParser { private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, String[] outError, String tag, TypedArray sa, - int nameRes, int labelRes, int iconRes) { + int nameRes, int labelRes, int iconRes, int logoRes) { String name = sa.getNonConfigurationString(nameRes, 0); if (name == null) { outError[0] = tag + " does not specify android:name"; @@ -1723,6 +1746,11 @@ public class PackageParser { outInfo.icon = iconVal; outInfo.nonLocalizedLabel = null; } + + int logoVal = sa.getResourceId(logoRes, 0); + if (logoVal != 0) { + outInfo.logo = logoVal; + } TypedValue v = sa.peekValue(labelRes); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { @@ -1745,6 +1773,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivity_name, com.android.internal.R.styleable.AndroidManifestActivity_label, com.android.internal.R.styleable.AndroidManifestActivity_icon, + com.android.internal.R.styleable.AndroidManifestActivity_logo, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestActivity_process, com.android.internal.R.styleable.AndroidManifestActivity_description, @@ -1947,6 +1976,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivityAlias_name, com.android.internal.R.styleable.AndroidManifestActivityAlias_label, com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, + com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, mSeparateProcesses, 0, com.android.internal.R.styleable.AndroidManifestActivityAlias_description, @@ -1980,6 +2010,7 @@ public class PackageParser { info.configChanges = target.info.configChanges; info.flags = target.info.flags; info.icon = target.info.icon; + info.logo = target.info.logo; info.labelRes = target.info.labelRes; info.nonLocalizedLabel = target.info.nonLocalizedLabel; info.launchMode = target.info.launchMode; @@ -2074,6 +2105,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestProvider_name, com.android.internal.R.styleable.AndroidManifestProvider_label, com.android.internal.R.styleable.AndroidManifestProvider_icon, + com.android.internal.R.styleable.AndroidManifestProvider_logo, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestProvider_process, com.android.internal.R.styleable.AndroidManifestProvider_description, @@ -2337,6 +2369,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestService_name, com.android.internal.R.styleable.AndroidManifestService_label, com.android.internal.R.styleable.AndroidManifestService_icon, + com.android.internal.R.styleable.AndroidManifestService_logo, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestService_process, com.android.internal.R.styleable.AndroidManifestService_description, @@ -2540,6 +2573,9 @@ public class PackageParser { outInfo.icon = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0); + + outInfo.logo = sa.getResourceId( + com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); sa.recycle(); @@ -2801,6 +2837,11 @@ public class PackageParser { outInfo.icon = iconVal; outInfo.nonLocalizedLabel = null; } + + int logoVal = args.sa.getResourceId(args.logoRes, 0); + if (logoVal != 0) { + outInfo.logo = logoVal; + } TypedValue v = args.sa.peekValue(args.labelRes); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { @@ -3135,6 +3176,7 @@ public class PackageParser { public int labelRes; public CharSequence nonLocalizedLabel; public int icon; + public int logo; } public final static class ActivityIntentInfo extends IntentInfo { diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 11c67cc..d0ba590 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -99,7 +99,22 @@ public class CompatibilityInfo { */ private static final int CONFIGURED_LARGE_SCREENS = 16; - private static final int SCALING_EXPANDABLE_MASK = SCALING_REQUIRED | EXPANDABLE | LARGE_SCREENS; + /** + * A flag mask to indicates that the application supports xlarge screens. + * The flag is set to true if + * 1) Application declares it supports xlarge screens in manifest file using <supports-screens> or + * 2) The screen size is not xlarge + * {@see compatibilityFlag} + */ + private static final int XLARGE_SCREENS = 32; + + /** + * A flag mask to tell if the application supports xlarge screens. This differs + * from XLARGE_SCREENS in that the application that does not support xlarge + * screens will be marked as supporting them if the current screen is not + * xlarge. + */ + private static final int CONFIGURED_XLARGE_SCREENS = 64; /** * The effective screen density we have selected for this application. @@ -127,6 +142,9 @@ public class CompatibilityInfo { if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { mCompatibilityFlags |= LARGE_SCREENS | CONFIGURED_LARGE_SCREENS; } + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS) != 0) { + mCompatibilityFlags |= XLARGE_SCREENS | CONFIGURED_XLARGE_SCREENS; + } if ((appInfo.flags & ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS) != 0) { mCompatibilityFlags |= EXPANDABLE | CONFIGURED_EXPANDABLE; } @@ -157,6 +175,7 @@ public class CompatibilityInfo { this(ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS, EXPANDABLE | CONFIGURED_EXPANDABLE, DisplayMetrics.DENSITY_DEVICE, @@ -196,6 +215,17 @@ public class CompatibilityInfo { } /** + * Sets large screen bit in the compatibility flag. + */ + public void setXLargeScreens(boolean expandable) { + if (expandable) { + mCompatibilityFlags |= CompatibilityInfo.XLARGE_SCREENS; + } else { + mCompatibilityFlags &= ~CompatibilityInfo.XLARGE_SCREENS; + } + } + + /** * @return true if the application is configured to be expandable. */ public boolean isConfiguredExpandable() { @@ -210,6 +240,13 @@ public class CompatibilityInfo { } /** + * @return true if the application is configured to be expandable. + */ + public boolean isConfiguredXLargeScreens() { + return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_XLARGE_SCREENS) != 0; + } + + /** * @return true if the scaling is required */ public boolean isScalingRequired() { diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 1a0c867..02956ba 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -62,6 +62,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static final int SCREENLAYOUT_SIZE_SMALL = 0x01; public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02; public static final int SCREENLAYOUT_SIZE_LARGE = 0x03; + public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04; public static final int SCREENLAYOUT_LONG_MASK = 0x30; public static final int SCREENLAYOUT_LONG_UNDEFINED = 0x00; @@ -82,7 +83,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration * <p>The {@link #SCREENLAYOUT_SIZE_MASK} bits define the overall size * of the screen. They may be one of * {@link #SCREENLAYOUT_SIZE_SMALL}, {@link #SCREENLAYOUT_SIZE_NORMAL}, - * or {@link #SCREENLAYOUT_SIZE_LARGE}. + * {@link #SCREENLAYOUT_SIZE_LARGE}, or {@link #SCREENLAYOUT_SIZE_XLARGE}. * * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen * is wider/taller than normal. They may be one of diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 8687a89..46c6cb8 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -84,13 +84,29 @@ public class Camera { private boolean mWithBuffer; /** + * Returns the number of Cameras available. + * @hide + */ + public native static int getNumberOfCameras(); + + /** * Returns a new Camera object. + * If {@link #getNumberOfCameras()} returns N, the valid is is 0 to N-1. + * The id 0 is the default camera. + * @hide + */ + public static Camera open(int cameraId) { + return new Camera(cameraId); + } + + /** + * Returns a new Camera object. This returns the default camera. */ public static Camera open() { - return new Camera(); + return new Camera(0); } - Camera() { + Camera(int cameraId) { mShutterCallback = null; mRawImageCallback = null; mJpegCallback = null; @@ -107,14 +123,14 @@ public class Camera { mEventHandler = null; } - native_setup(new WeakReference<Camera>(this)); + native_setup(new WeakReference<Camera>(this), cameraId); } protected void finalize() { native_release(); } - private native final void native_setup(Object camera_this); + private native final void native_setup(Object camera_this, int cameraId); private native final void native_release(); @@ -746,6 +762,8 @@ public class Camera { private static final String KEY_ZOOM_RATIOS = "zoom-ratios"; private static final String KEY_ZOOM_SUPPORTED = "zoom-supported"; private static final String KEY_SMOOTH_ZOOM_SUPPORTED = "smooth-zoom-supported"; + private static final String KEY_FOCUS_DISTANCES = "focus-distances"; + // Parameter key suffix for supported values. private static final String SUPPORTED_VALUES_SUFFIX = "-values"; @@ -858,6 +876,36 @@ public class Camera { */ public static final String FOCUS_MODE_EDOF = "edof"; + // Indices for focus distance array. + /** + * The array index of near focus distance for use with + * {@link #getFocusDistances(float[])}. + */ + public static final int FOCUS_DISTANCE_NEAR_INDEX = 0; + + /** + * The array index of optimal focus distance for use with + * {@link #getFocusDistances(float[])}. + */ + public static final int FOCUS_DISTANCE_OPTIMAL_INDEX = 1; + + /** + * The array index of far focus distance for use with + * {@link #getFocusDistances(float[])}. + */ + public static final int FOCUS_DISTANCE_FAR_INDEX = 2; + + /** + * Continuous focus mode. The camera continuously tries to focus. This + * is ideal for shooting video or shooting photo of moving object. + * Continuous focus starts when {@link #autoFocus(AutoFocusCallback)} is + * called. Continuous focus stops when {@link #cancelAutoFocus()} is + * called. AutoFocusCallback will be only called once as soon as the + * picture is in focus. + */ + public static final String FOCUS_MODE_CONTINUOUS = "continuous"; + + // Formats for setPreviewFormat and setPictureFormat. private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp"; private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp"; @@ -1788,6 +1836,42 @@ public class Camera { return TRUE.equals(str); } + /** + * Gets the distances from the camera to where an object appears to be + * in focus. The object is sharpest at the optimal focus distance. The + * depth of field is the far focus distance minus near focus distance. + * + * Focus distances may change after calling {@link + * #autoFocus(AutoFocusCallback)}, {@link #cancelAutoFocus}, or {@link + * #startPreview()}. Applications can call {@link #getParameters()} + * and this method anytime to get the latest focus distances. If the + * focus mode is FOCUS_MODE_EDOF, the values may be all 0, which means + * focus distance is not applicable. If the focus mode is + * FOCUS_MODE_CONTINUOUS and autofocus has started, focus distances may + * change from time to time. + * + * Far focus distance > optimal focus distance > near focus distance. If + * the far focus distance is infinity, the value will be + * Float.POSITIVE_INFINITY. + * + * @param output focus distances in meters. output must be a float + * array with three elements. Near focus distance, optimal focus + * distance, and far focus distance will be filled in the array. + * @see #NEAR_FOCUS_DISTANCE_INDEX + * @see #OPTIMAL_FOCUS_DISTANCE_INDEX + * @see #FAR_FOCUS_DISTANCE_INDEX + */ + public void getFocusDistances(float[] output) { + if (output == null || output.length != 3) { + throw new IllegalArgumentException( + "output must be an float array with three elements."); + } + List<Float> distances = splitFloat(get(KEY_FOCUS_DISTANCES)); + output[0] = distances.get(0); + output[1] = distances.get(1); + output[2] = distances.get(2); + } + // Splits a comma delimited string to an ArrayList of String. // Return null if the passing string is null or the size is 0. private ArrayList<String> split(String str) { @@ -1817,6 +1901,21 @@ public class Camera { return substrings; } + // Splits a comma delimited string to an ArrayList of Float. + // Return null if the passing string is null or the size is 0. + private ArrayList<Float> splitFloat(String str) { + if (str == null) return null; + + StringTokenizer tokenizer = new StringTokenizer(str, ","); + ArrayList<Float> substrings = new ArrayList<Float>(); + while (tokenizer.hasMoreElements()) { + String token = tokenizer.nextToken(); + substrings.add(Float.parseFloat(token)); + } + if (substrings.size() == 0) return null; + return substrings; + } + // Returns the value of a float parameter. private float getFloat(String key, float defaultValue) { try { diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 3e9fd42..9d1a634 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -180,6 +180,10 @@ public class Build { public static final int ECLAIR_MR1 = 7; public static final int FROYO = 8; + + public static final int KRAKEN = CUR_DEVELOPMENT; + + public static final int GINGERBREAD = CUR_DEVELOPMENT; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 812391c..c7cbed6 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -28,6 +28,8 @@ public class Environment { private static final File ROOT_DIRECTORY = getDirectory("ANDROID_ROOT", "/system"); + private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled"; + private static IMountService mMntSvc = null; /** @@ -37,9 +39,55 @@ public class Environment { return ROOT_DIRECTORY; } + /** + * Gets the system directory available for secure storage. + * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system). + * Otherwise, it returns the unencrypted /data/system directory. + * @return File object representing the secure storage system directory. + * @hide + */ + public static File getSystemSecureDirectory() { + if (isEncryptedFilesystemEnabled()) { + return new File(SECURE_DATA_DIRECTORY, "system"); + } else { + return new File(DATA_DIRECTORY, "system"); + } + } + + /** + * Gets the data directory for secure storage. + * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure). + * Otherwise, it returns the unencrypted /data directory. + * @return File object representing the data directory for secure storage. + * @hide + */ + public static File getSecureDataDirectory() { + if (isEncryptedFilesystemEnabled()) { + return SECURE_DATA_DIRECTORY; + } else { + return DATA_DIRECTORY; + } + } + + /** + * Returns whether the Encrypted File System feature is enabled on the device or not. + * @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code> + * if disabled. + * @hide + */ + public static boolean isEncryptedFilesystemEnabled() { + return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false); + } + private static final File DATA_DIRECTORY = getDirectory("ANDROID_DATA", "/data"); + /** + * @hide + */ + private static final File SECURE_DATA_DIRECTORY + = getDirectory("ANDROID_SECURE_DATA", "/data/secure"); + private static final File EXTERNAL_STORAGE_DIRECTORY = getDirectory("EXTERNAL_STORAGE", "/sdcard"); diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index bc653d6..d394a46 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -36,8 +36,9 @@ public class MessageQueue { Message mMessages; private final ArrayList mIdleHandlers = new ArrayList(); private boolean mQuiting = false; + private int mObject = 0; // used by native code boolean mQuitAllowed = true; - + /** * Callback interface for discovering when a thread is going to block * waiting for more messages. @@ -85,16 +86,49 @@ public class MessageQueue { } } + // Add an input pipe to the set being selected over. If token is + // negative, remove 'handler's entry from the current set and forget + // about it. + void setInputToken(int token, int region, Handler handler) { + if (token >= 0) nativeRegisterInputStream(token, region, handler); + else nativeUnregisterInputStream(token); + } + MessageQueue() { + nativeInit(); } + private native void nativeInit(); + + /** + * @param token fd of the readable end of the input stream + * @param region fd of the ashmem region used for data transport alongside the 'token' fd + * @param handler Handler from which to make input messages based on data read from the fd + */ + private native void nativeRegisterInputStream(int token, int region, Handler handler); + private native void nativeUnregisterInputStream(int token); + private native void nativeSignal(); + + /** + * Wait until the designated time for new messages to arrive. + * + * @param when Timestamp in SystemClock.uptimeMillis() base of the next message in the queue. + * If 'when' is zero, the method will check for incoming messages without blocking. If + * 'when' is negative, the method will block forever waiting for the next message. + * @return + */ + private native int nativeWaitForNext(long when); final Message next() { boolean tryIdle = true; + // when we start out, we'll just touch the input pipes and then go from there + long timeToNextEventMillis = 0; while (true) { long now; Object[] idlers = null; - + + nativeWaitForNext(timeToNextEventMillis); + // Try to retrieve the next message, returning if found. synchronized (this) { now = SystemClock.uptimeMillis(); @@ -135,20 +169,17 @@ public class MessageQueue { synchronized (this) { // No messages, nobody to tell about it... time to wait! - try { - if (mMessages != null) { - if (mMessages.when-now > 0) { - Binder.flushPendingCommands(); - this.wait(mMessages.when-now); - } - } else { + if (mMessages != null) { + if (mMessages.when - now > 0) { Binder.flushPendingCommands(); - this.wait(); + timeToNextEventMillis = mMessages.when - now; } - } - catch (InterruptedException e) { + } else { + Binder.flushPendingCommands(); + timeToNextEventMillis = -1; } } + // loop to the while(true) and do the appropriate nativeWait(when) } } @@ -190,7 +221,6 @@ public class MessageQueue { if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; - this.notify(); } else { Message prev = null; while (p != null && p.when <= when) { @@ -199,8 +229,8 @@ public class MessageQueue { } msg.next = prev.next; prev.next = msg; - this.notify(); } + nativeSignal(); } return true; } @@ -321,7 +351,7 @@ public class MessageQueue { void poke() { synchronized (this) { - this.notify(); + nativeSignal(); } } } diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 0a3b2cf..d26f066 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -179,7 +179,7 @@ public class ParcelFileDescriptor implements Parcelable { /** * An InputStream you can create on a ParcelFileDescriptor, which will * take care of calling {@link ParcelFileDescriptor#close - * ParcelFileDescritor.close()} for you when the stream is closed. + * ParcelFileDescriptor.close()} for you when the stream is closed. */ public static class AutoCloseInputStream extends FileInputStream { private final ParcelFileDescriptor mFd; @@ -198,7 +198,7 @@ public class ParcelFileDescriptor implements Parcelable { /** * An OutputStream you can create on a ParcelFileDescriptor, which will * take care of calling {@link ParcelFileDescriptor#close - * ParcelFileDescritor.close()} for you when the stream is closed. + * ParcelFileDescriptor.close()} for you when the stream is closed. */ public static class AutoCloseOutputStream extends FileOutputStream { private final ParcelFileDescriptor mFd; diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index b6dc1b5..5fea6fe 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -348,6 +348,23 @@ public class RecoverySystem { } /** + * Reboot into the recovery system to wipe the /data partition and toggle + * Encrypted File Systems on/off. + * @param extras to add to the RECOVERY_COMPLETED intent after rebooting. + * @throws IOException if something goes wrong. + * + * @hide + */ + public static void rebootToggleEFS(Context context, boolean efsEnabled) + throws IOException { + if (efsEnabled) { + bootCommand(context, "--set_encrypted_filesystem=on"); + } else { + bootCommand(context, "--set_encrypted_filesystem=off"); + } + } + + /** * Reboot into the recovery system with the supplied argument. * @param arg to pass to the recovery utility. * @throws IOException if something goes wrong. diff --git a/core/java/android/pim/vcard/VCardBuilder.java b/core/java/android/pim/vcard/VCardBuilder.java index 0a6415d..1da6d7a 100644 --- a/core/java/android/pim/vcard/VCardBuilder.java +++ b/core/java/android/pim/vcard/VCardBuilder.java @@ -642,22 +642,18 @@ public class VCardBuilder { if (TextUtils.isEmpty(phoneNumber)) { continue; } - int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE); - if (type == Phone.TYPE_PAGER) { + + // PAGER number needs unformatted "phone number". + final int type = (typeAsObject != null ? typeAsObject : DEFAULT_PHONE_TYPE); + if (type == Phone.TYPE_PAGER || + VCardConfig.refrainPhoneNumberFormatting(mVCardType)) { phoneLineExists = true; if (!phoneSet.contains(phoneNumber)) { phoneSet.add(phoneNumber); appendTelLine(type, label, phoneNumber, isPrimary); } } else { - // The entry "may" have several phone numbers when the contact entry is - // corrupted because of its original source. - // - // e.g. I encountered the entry like the following. - // "111-222-3333 (Miami)\n444-555-6666 (Broward; 305-653-6796 (Miami); ..." - // This kind of entry is not able to be inserted via Android devices, but - // possible if the source of the data is already corrupted. - List<String> phoneNumberList = splitIfSeveralPhoneNumbersExist(phoneNumber); + final List<String> phoneNumberList = splitAndTrimPhoneNumbers(phoneNumber); if (phoneNumberList.isEmpty()) { continue; } @@ -670,7 +666,7 @@ public class VCardBuilder { phoneSet.add(actualPhoneNumber); appendTelLine(type, label, formattedPhoneNumber, isPrimary); } - } + } // for (String actualPhoneNumber : phoneNumberList) { } } } @@ -682,15 +678,38 @@ public class VCardBuilder { return this; } - private List<String> splitIfSeveralPhoneNumbersExist(final String phoneNumber) { - List<String> phoneList = new ArrayList<String>(); + /** + * <p> + * Splits a given string expressing phone numbers into several strings, and remove + * unnecessary characters inside them. The size of a returned list becomes 1 when + * no split is needed. + * </p> + * <p> + * The given number "may" have several phone numbers when the contact entry is corrupted + * because of its original source. + * e.g. "111-222-3333 (Miami)\n444-555-6666 (Broward; 305-653-6796 (Miami)" + * </p> + * <p> + * This kind of "phone numbers" will not be created with Android vCard implementation, + * but we may encounter them if the source of the input data has already corrupted + * implementation. + * </p> + * <p> + * To handle this case, this method first splits its input into multiple parts + * (e.g. "111-222-3333 (Miami)", "444-555-6666 (Broward", and 305653-6796 (Miami)") and + * removes unnecessary strings like "(Miami)". + * </p> + * <p> + * Do not call this method when trimming is inappropriate for its receivers. + * </p> + */ + private List<String> splitAndTrimPhoneNumbers(final String phoneNumber) { + final List<String> phoneList = new ArrayList<String>(); StringBuilder builder = new StringBuilder(); final int length = phoneNumber.length(); for (int i = 0; i < length; i++) { final char ch = phoneNumber.charAt(i); - // TODO: add a test case for string with '+', and care the other possible issues - // which may happen by ignoring non-digits other than '+'. if (Character.isDigit(ch) || ch == '+') { builder.append(ch); } else if ((ch == ';' || ch == '\n') && builder.length() > 0) { diff --git a/core/java/android/pim/vcard/VCardConfig.java b/core/java/android/pim/vcard/VCardConfig.java index 3409be6..8219840 100644 --- a/core/java/android/pim/vcard/VCardConfig.java +++ b/core/java/android/pim/vcard/VCardConfig.java @@ -15,6 +15,7 @@ */ package android.pim.vcard; +import android.telephony.PhoneNumberUtils; import android.util.Log; import java.util.HashMap; @@ -190,6 +191,30 @@ public class VCardConfig { */ public static final int FLAG_REFRAIN_IMAGE_EXPORT = 0x02000000; + /** + * <P> + * The flag indicating the vCard composer does touch nothing toward phone number Strings + * but leave it as is. + * </P> + * <P> + * The vCard specifications mention nothing toward phone numbers, while some devices + * do (wrongly, but with innevitable reasons). + * For example, there's a possibility Japanese mobile phones are expected to have + * just numbers, hypens, plus, etc. but not usual alphabets, while US mobile phones + * should get such characters. To make exported vCard simple for external parsers, + * we have used {@link PhoneNumberUtils#formatNumber(String)} during export, and + * removed unnecessary characters inside the number (e.g. "111-222-3333 (Miami)" + * becomes "111-222-3333"). + * Unfortunate side effect of that use was some control characters used in the other + * areas may be badly affected by the formatting. + * </P> + * <P> + * This flag disables that formatting, affecting both importer and exporter. + * If the user is aware of some side effects due to the implicit formatting, use this flag. + * </P> + */ + public static final int FLAG_REFRAIN_PHONE_NUMBER_FORMATTING = 0x02000000; + //// The followings are VCard types available from importer/exporter. //// /** @@ -431,6 +456,10 @@ public class VCardConfig { return sJapaneseMobileTypeSet.contains(vcardType); } + /* package */ static boolean refrainPhoneNumberFormatting(final int vcardType) { + return ((vcardType & FLAG_REFRAIN_PHONE_NUMBER_FORMATTING) != 0); + } + public static boolean needsToConvertPhoneticString(final int vcardType) { return ((vcardType & FLAG_CONVERT_PHONETIC_NAME_STRINGS) != 0); } @@ -445,4 +474,4 @@ public class VCardConfig { private VCardConfig() { } -}
\ No newline at end of file +} diff --git a/core/java/android/pim/vcard/VCardEntry.java b/core/java/android/pim/vcard/VCardEntry.java index 1327770..7c7e9b8 100644 --- a/core/java/android/pim/vcard/VCardEntry.java +++ b/core/java/android/pim/vcard/VCardEntry.java @@ -488,7 +488,7 @@ public class VCardEntry { final StringBuilder builder = new StringBuilder(); final String trimed = data.trim(); final String formattedNumber; - if (type == Phone.TYPE_PAGER) { + if (type == Phone.TYPE_PAGER || VCardConfig.refrainPhoneNumberFormatting(mVCardType)) { formattedNumber = trimed; } else { final int length = trimed.length(); @@ -500,8 +500,7 @@ public class VCardEntry { } // Use NANP in default when there's no information about locale. - final int formattingType = (VCardConfig.isJapaneseDevice(mVCardType) ? - PhoneNumberUtils.FORMAT_JAPAN : PhoneNumberUtils.FORMAT_NANP); + final int formattingType = VCardUtils.getPhoneNumberFormat(mVCardType); formattedNumber = PhoneNumberUtils.formatNumber(builder.toString(), formattingType); } PhoneData phoneData = new PhoneData(type, formattedNumber, label, isPrimary); diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index 893db2e..ac89934 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -554,6 +554,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { if (!result) { if (deviceObjectPath != null) { String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); + if (address == null) return; BluetoothDevice device = mAdapter.getRemoteDevice(address); int state = getSinkState(device); handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 3d1d7d6..2ade44e 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -522,20 +522,14 @@ public abstract class WallpaperService extends Service { } try { - SurfaceHolder.Callback callbacks[] = null; - synchronized (mSurfaceHolder.mCallbacks) { - final int N = mSurfaceHolder.mCallbacks.size(); - if (N > 0) { - callbacks = new SurfaceHolder.Callback[N]; - mSurfaceHolder.mCallbacks.toArray(callbacks); - } - } + mSurfaceHolder.ungetCallbacks(); if (surfaceCreating) { mIsCreating = true; if (DEBUG) Log.v(TAG, "onSurfaceCreated(" + mSurfaceHolder + "): " + this); onSurfaceCreated(mSurfaceHolder); + SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceCreated(mSurfaceHolder); @@ -557,6 +551,7 @@ public abstract class WallpaperService extends Service { + "): " + this); onSurfaceChanged(mSurfaceHolder, mFormat, mCurWidth, mCurHeight); + SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { c.surfaceChanged(mSurfaceHolder, mFormat, @@ -698,14 +693,12 @@ public abstract class WallpaperService extends Service { void reportSurfaceDestroyed() { if (mSurfaceCreated) { mSurfaceCreated = false; - SurfaceHolder.Callback callbacks[]; - synchronized (mSurfaceHolder.mCallbacks) { - callbacks = new SurfaceHolder.Callback[ - mSurfaceHolder.mCallbacks.size()]; - mSurfaceHolder.mCallbacks.toArray(callbacks); - } - for (SurfaceHolder.Callback c : callbacks) { - c.surfaceDestroyed(mSurfaceHolder); + mSurfaceHolder.ungetCallbacks(); + SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); + if (callbacks != null) { + for (SurfaceHolder.Callback c : callbacks) { + c.surfaceDestroyed(mSurfaceHolder); + } } if (DEBUG) Log.v(TAG, "onSurfaceDestroyed(" + mSurfaceHolder + "): " + this); diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 2628eb4..76d8106 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -135,6 +135,7 @@ public class DisplayMetrics { int screenLayout) { boolean expandable = compatibilityInfo.isConfiguredExpandable(); boolean largeScreens = compatibilityInfo.isConfiguredLargeScreens(); + boolean xlargeScreens = compatibilityInfo.isConfiguredXLargeScreens(); // Note: this assume that configuration is updated before calling // updateMetrics method. @@ -157,8 +158,18 @@ public class DisplayMetrics { compatibilityInfo.setLargeScreens(false); } } + if (!xlargeScreens) { + if ((screenLayout&Configuration.SCREENLAYOUT_SIZE_MASK) + != Configuration.SCREENLAYOUT_SIZE_XLARGE) { + xlargeScreens = true; + // the current screen size is not large. + compatibilityInfo.setXLargeScreens(true); + } else { + compatibilityInfo.setXLargeScreens(false); + } + } - if (!expandable || !largeScreens) { + if (!expandable || (!largeScreens && !xlargeScreens)) { // This is a larger screen device and the app is not // compatible with large screens, so diddle it. diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 83ef8ba..cd0ae3b 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -140,13 +140,13 @@ public class Surface implements Parcelable { public static final int FLAGS_ORIENTATION_ANIMATION_DISABLE = 0x000000001; @SuppressWarnings("unused") - private int mSurface; - @SuppressWarnings("unused") private int mSurfaceControl; @SuppressWarnings("unused") private int mSaveCount; @SuppressWarnings("unused") private Canvas mCanvas; + @SuppressWarnings("unused") + private int mNativeSurface; private String mName; // The display metrics used to provide the pseudo canvas size for applications @@ -422,13 +422,13 @@ public class Surface implements Parcelable { /* no user serviceable parts here ... */ @Override protected void finalize() throws Throwable { - if (mSurface != 0 || mSurfaceControl != 0) { + if (mNativeSurface != 0 || mSurfaceControl != 0) { if (DEBUG_RELEASE) { Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" - + mSurface + ", " + mSurfaceControl + ")", mCreationStack); + + mNativeSurface + ", " + mSurfaceControl + ")", mCreationStack); } else { Log.w(LOG_TAG, "Surface.finalize() has work. You should have called release() (" - + mSurface + ", " + mSurfaceControl + ")"); + + mNativeSurface + ", " + mSurfaceControl + ")"); } } release(); diff --git a/core/java/android/view/SurfaceHolder.java b/core/java/android/view/SurfaceHolder.java index 64a10d1..34e4638 100644 --- a/core/java/android/view/SurfaceHolder.java +++ b/core/java/android/view/SurfaceHolder.java @@ -182,7 +182,6 @@ public interface SurfaceHolder { /** * Enable or disable option to keep the screen turned on while this * surface is displayed. The default is false, allowing it to turn off. - * Enabling the option effectivelty. * This is safe to call from any thread. * * @param screenOn Supply to true to force the screen to stay on, false diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 03efea9..aa124e6 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -16,8 +16,10 @@ package android.view; +import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.IInputMethodCallback; import com.android.internal.view.IInputMethodSession; +import com.android.internal.view.RootViewSurfaceTaker; import android.graphics.Canvas; import android.graphics.PixelFormat; @@ -26,12 +28,12 @@ import android.graphics.Rect; import android.graphics.Region; import android.os.*; import android.os.Process; -import android.os.SystemProperties; import android.util.AndroidRuntimeException; import android.util.Config; import android.util.DisplayMetrics; import android.util.Log; import android.util.EventLog; +import android.util.Slog; import android.util.SparseArray; import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; @@ -50,6 +52,7 @@ import android.Manifest; import android.media.AudioManager; import java.lang.ref.WeakReference; +import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -76,6 +79,7 @@ public final class ViewRoot extends Handler implements ViewParent, /** @noinspection PointlessBooleanExpression*/ private static final boolean DEBUG_DRAW = false || LOCAL_LOGV; private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV; + private static final boolean DEBUG_INPUT = true || LOCAL_LOGV; private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV; private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV; private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV; @@ -133,6 +137,11 @@ public final class ViewRoot extends Handler implements ViewParent, int mViewVisibility; boolean mAppVisible = true; + SurfaceHolder.Callback mSurfaceHolderCallback; + BaseSurfaceHolder mSurfaceHolder; + boolean mIsCreating; + boolean mDrawingAllowed; + final Region mTransparentRegion; final Region mPreviousTransparentRegion; @@ -425,6 +434,9 @@ public final class ViewRoot extends Handler implements ViewParent, } } + // fd [0] is the receiver, [1] is the sender + private native int[] makeInputChannel(); + /** * We have one child */ @@ -435,6 +447,13 @@ public final class ViewRoot extends Handler implements ViewParent, mView = view; mWindowAttributes.copyFrom(attrs); attrs = mWindowAttributes; + if (view instanceof RootViewSurfaceTaker) { + mSurfaceHolderCallback = + ((RootViewSurfaceTaker)view).willYouTakeTheSurface(); + if (mSurfaceHolderCallback != null) { + mSurfaceHolder = new TakenSurfaceHolder(); + } + } Resources resources = mView.getContext().getResources(); CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo(); mTranslator = compatibilityInfo.getTranslator(); @@ -469,6 +488,14 @@ public final class ViewRoot extends Handler implements ViewParent, mAdded = true; int res; /* = WindowManagerImpl.ADD_OKAY; */ + // Set up the input event channel + if (false) { + int[] fds = makeInputChannel(); + if (DEBUG_INPUT) { + Log.v(TAG, "makeInputChannel() returned " + fds); + } + } + // Schedule the first layout -before- adding to the window // manager, to make sure we do the relayout before receiving // any other events from the system. @@ -682,6 +709,7 @@ public final class ViewRoot extends Handler implements ViewParent, boolean windowResizesToFitContent = false; boolean fullRedrawNeeded = mFullRedrawNeeded; boolean newSurface = false; + boolean surfaceChanged = false; WindowManager.LayoutParams lp = mWindowAttributes; int desiredWindowWidth; @@ -700,6 +728,7 @@ public final class ViewRoot extends Handler implements ViewParent, WindowManager.LayoutParams params = null; if (mWindowAttributesChanged) { mWindowAttributesChanged = false; + surfaceChanged = true; params = lp; } Rect frame = mWinFrame; @@ -886,11 +915,18 @@ public final class ViewRoot extends Handler implements ViewParent, } } + if (mSurfaceHolder != null) { + mSurfaceHolder.mSurfaceLock.lock(); + mDrawingAllowed = true; + lp.format = mSurfaceHolder.getRequestedFormat(); + lp.type = mSurfaceHolder.getRequestedType(); + } + boolean initialized = false; boolean contentInsetsChanged = false; boolean visibleInsetsChanged; + boolean hadSurface = mSurface.isValid(); try { - boolean hadSurface = mSurface.isValid(); int fl = 0; if (params != null) { fl = params.flags; @@ -965,6 +1001,7 @@ public final class ViewRoot extends Handler implements ViewParent, } } catch (RemoteException e) { } + if (DEBUG_ORIENTATION) Log.v( "ViewRoot", "Relayout returned: frame=" + frame + ", surface=" + mSurface); @@ -977,6 +1014,57 @@ public final class ViewRoot extends Handler implements ViewParent, mWidth = frame.width(); mHeight = frame.height(); + if (mSurfaceHolder != null) { + // The app owns the surface; tell it about what is going on. + if (mSurface.isValid()) { + // XXX .copyFrom() doesn't work! + //mSurfaceHolder.mSurface.copyFrom(mSurface); + mSurfaceHolder.mSurface = mSurface; + } + mSurfaceHolder.mSurfaceLock.unlock(); + if (mSurface.isValid()) { + if (!hadSurface) { + mSurfaceHolder.ungetCallbacks(); + + mIsCreating = true; + mSurfaceHolderCallback.surfaceCreated(mSurfaceHolder); + SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); + if (callbacks != null) { + for (SurfaceHolder.Callback c : callbacks) { + c.surfaceCreated(mSurfaceHolder); + } + } + surfaceChanged = true; + } + if (surfaceChanged) { + mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder, + lp.format, mWidth, mHeight); + SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); + if (callbacks != null) { + for (SurfaceHolder.Callback c : callbacks) { + c.surfaceChanged(mSurfaceHolder, lp.format, + mWidth, mHeight); + } + } + } + mIsCreating = false; + } else if (hadSurface) { + mSurfaceHolder.ungetCallbacks(); + SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); + mSurfaceHolderCallback.surfaceDestroyed(mSurfaceHolder); + if (callbacks != null) { + for (SurfaceHolder.Callback c : callbacks) { + c.surfaceDestroyed(mSurfaceHolder); + } + } + mSurfaceHolder.mSurfaceLock.lock(); + // Make surface invalid. + //mSurfaceHolder.mSurface.copyFrom(mSurface); + mSurfaceHolder.mSurface = new Surface(); + mSurfaceHolder.mSurfaceLock.unlock(); + } + } + if (initialized) { mGlCanvas.setViewport((int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f)); @@ -1268,6 +1356,12 @@ public final class ViewRoot extends Handler implements ViewParent, boolean scalingRequired = mAttachInfo.mScalingRequired; Rect dirty = mDirty; + if (mSurfaceHolder != null) { + // The app owns the surface, we won't draw. + dirty.setEmpty(); + return; + } + if (mUseGL) { if (!dirty.isEmpty()) { Canvas canvas = mGlCanvas; @@ -1332,103 +1426,105 @@ public final class ViewRoot extends Handler implements ViewParent, appScale + ", width=" + mWidth + ", height=" + mHeight); } - Canvas canvas; - try { - int left = dirty.left; - int top = dirty.top; - int right = dirty.right; - int bottom = dirty.bottom; - canvas = surface.lockCanvas(dirty); - - if (left != dirty.left || top != dirty.top || right != dirty.right || - bottom != dirty.bottom) { - mAttachInfo.mIgnoreDirtyState = true; - } - - // TODO: Do this in native - canvas.setDensity(mDensity); - } catch (Surface.OutOfResourcesException e) { - Log.e("ViewRoot", "OutOfResourcesException locking surface", e); - // TODO: we should ask the window manager to do something! - // for now we just do nothing - return; - } catch (IllegalArgumentException e) { - Log.e("ViewRoot", "IllegalArgumentException locking surface", e); - // TODO: we should ask the window manager to do something! - // for now we just do nothing - return; - } + if (!dirty.isEmpty() || mIsAnimating) { + Canvas canvas; + try { + int left = dirty.left; + int top = dirty.top; + int right = dirty.right; + int bottom = dirty.bottom; + canvas = surface.lockCanvas(dirty); + + if (left != dirty.left || top != dirty.top || right != dirty.right || + bottom != dirty.bottom) { + mAttachInfo.mIgnoreDirtyState = true; + } - try { - if (!dirty.isEmpty() || mIsAnimating) { - long startTime = 0L; + // TODO: Do this in native + canvas.setDensity(mDensity); + } catch (Surface.OutOfResourcesException e) { + Log.e("ViewRoot", "OutOfResourcesException locking surface", e); + // TODO: we should ask the window manager to do something! + // for now we just do nothing + return; + } catch (IllegalArgumentException e) { + Log.e("ViewRoot", "IllegalArgumentException locking surface", e); + // TODO: we should ask the window manager to do something! + // for now we just do nothing + return; + } - if (DEBUG_ORIENTATION || DEBUG_DRAW) { - Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w=" - + canvas.getWidth() + ", h=" + canvas.getHeight()); - //canvas.drawARGB(255, 255, 0, 0); - } + try { + if (!dirty.isEmpty() || mIsAnimating) { + long startTime = 0L; - if (Config.DEBUG && ViewDebug.profileDrawing) { - startTime = SystemClock.elapsedRealtime(); - } + if (DEBUG_ORIENTATION || DEBUG_DRAW) { + Log.v("ViewRoot", "Surface " + surface + " drawing to bitmap w=" + + canvas.getWidth() + ", h=" + canvas.getHeight()); + //canvas.drawARGB(255, 255, 0, 0); + } - // If this bitmap's format includes an alpha channel, we - // need to clear it before drawing so that the child will - // properly re-composite its drawing on a transparent - // background. This automatically respects the clip/dirty region - // or - // If we are applying an offset, we need to clear the area - // where the offset doesn't appear to avoid having garbage - // left in the blank areas. - if (!canvas.isOpaque() || yoff != 0) { - canvas.drawColor(0, PorterDuff.Mode.CLEAR); - } + if (Config.DEBUG && ViewDebug.profileDrawing) { + startTime = SystemClock.elapsedRealtime(); + } - dirty.setEmpty(); - mIsAnimating = false; - mAttachInfo.mDrawingTime = SystemClock.uptimeMillis(); - mView.mPrivateFlags |= View.DRAWN; + // If this bitmap's format includes an alpha channel, we + // need to clear it before drawing so that the child will + // properly re-composite its drawing on a transparent + // background. This automatically respects the clip/dirty region + // or + // If we are applying an offset, we need to clear the area + // where the offset doesn't appear to avoid having garbage + // left in the blank areas. + if (!canvas.isOpaque() || yoff != 0) { + canvas.drawColor(0, PorterDuff.Mode.CLEAR); + } - if (DEBUG_DRAW) { - Context cxt = mView.getContext(); - Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + - ", metrics=" + cxt.getResources().getDisplayMetrics() + - ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); - } - int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); - try { - canvas.translate(0, -yoff); - if (mTranslator != null) { - mTranslator.translateCanvas(canvas); + dirty.setEmpty(); + mIsAnimating = false; + mAttachInfo.mDrawingTime = SystemClock.uptimeMillis(); + mView.mPrivateFlags |= View.DRAWN; + + if (DEBUG_DRAW) { + Context cxt = mView.getContext(); + Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + + ", metrics=" + cxt.getResources().getDisplayMetrics() + + ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); + } + int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + try { + canvas.translate(0, -yoff); + if (mTranslator != null) { + mTranslator.translateCanvas(canvas); + } + canvas.setScreenDensity(scalingRequired + ? DisplayMetrics.DENSITY_DEVICE : 0); + mView.draw(canvas); + } finally { + mAttachInfo.mIgnoreDirtyState = false; + canvas.restoreToCount(saveCount); } - canvas.setScreenDensity(scalingRequired - ? DisplayMetrics.DENSITY_DEVICE : 0); - mView.draw(canvas); - } finally { - mAttachInfo.mIgnoreDirtyState = false; - canvas.restoreToCount(saveCount); - } - if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) { - mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING); - } + if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) { + mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING); + } - if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) { - int now = (int)SystemClock.elapsedRealtime(); - if (sDrawTime != 0) { - nativeShowFPS(canvas, now - sDrawTime); + if (SHOW_FPS || Config.DEBUG && ViewDebug.showFps) { + int now = (int)SystemClock.elapsedRealtime(); + if (sDrawTime != 0) { + nativeShowFPS(canvas, now - sDrawTime); + } + sDrawTime = now; } - sDrawTime = now; - } - if (Config.DEBUG && ViewDebug.profileDrawing) { - EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime); + if (Config.DEBUG && ViewDebug.profileDrawing) { + EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime); + } } - } - } finally { - surface.unlockCanvasAndPost(canvas); + } finally { + surface.unlockCanvasAndPost(canvas); + } } if (LOCAL_LOGV) { @@ -2813,6 +2909,46 @@ public final class ViewRoot extends Handler implements ViewParent, return scrollToRectOrFocus(rectangle, immediate); } + class TakenSurfaceHolder extends BaseSurfaceHolder { + @Override + public boolean onAllowLockCanvas() { + return mDrawingAllowed; + } + + @Override + public void onRelayoutContainer() { + // Not currently interesting -- from changing between fixed and layout size. + } + + public void setFormat(int format) { + ((RootViewSurfaceTaker)mView).setSurfaceFormat(format); + } + + public void setType(int type) { + ((RootViewSurfaceTaker)mView).setSurfaceType(type); + } + + @Override + public void onUpdateSurface() { + // We take care of format and type changes on our own. + throw new IllegalStateException("Shouldn't be here"); + } + + public boolean isCreating() { + return mIsCreating; + } + + @Override + public void setFixedSize(int width, int height) { + throw new UnsupportedOperationException( + "Currently only support sizing from layout"); + } + + public void setKeepScreenOn(boolean screenOn) { + ((RootViewSurfaceTaker)mView).setSurfaceKeepScreenOn(screenOn); + } + } + static class InputMethodCallback extends IInputMethodCallback.Stub { private WeakReference<ViewRoot> mViewRoot; diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 7dd5085..234deba 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -473,6 +473,14 @@ public abstract class Window { } /** + * Take ownership of this window's surface. The window's view hierarchy + * will no longer draw into the surface, though it will otherwise continue + * to operate (such as for receiving input events). The given SurfaceHolder + * callback will be used to tell you about state changes to the surface. + */ + public abstract void takeSurface(SurfaceHolder.Callback callback); + + /** * Return whether this window is being displayed with a floating style * (based on the {@link android.R.attr#windowIsFloating} attribute in * the style/theme). diff --git a/core/java/com/android/internal/view/BaseSurfaceHolder.java b/core/java/com/android/internal/view/BaseSurfaceHolder.java index e0d3a5f..3a04993 100644 --- a/core/java/com/android/internal/view/BaseSurfaceHolder.java +++ b/core/java/com/android/internal/view/BaseSurfaceHolder.java @@ -33,9 +33,11 @@ public abstract class BaseSurfaceHolder implements SurfaceHolder { public final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<SurfaceHolder.Callback>(); - + SurfaceHolder.Callback[] mGottenCallbacks; + boolean mHaveGottenCallbacks; + public final ReentrantLock mSurfaceLock = new ReentrantLock(); - public final Surface mSurface = new Surface(); + public Surface mSurface = new Surface(); int mRequestedWidth = -1; int mRequestedHeight = -1; @@ -83,6 +85,31 @@ public abstract class BaseSurfaceHolder implements SurfaceHolder { } } + public SurfaceHolder.Callback[] getCallbacks() { + if (mHaveGottenCallbacks) { + return mGottenCallbacks; + } + + synchronized (mCallbacks) { + final int N = mCallbacks.size(); + if (N > 0) { + if (mGottenCallbacks == null || mGottenCallbacks.length != N) { + mGottenCallbacks = new SurfaceHolder.Callback[N]; + } + mCallbacks.toArray(mGottenCallbacks); + } else { + mGottenCallbacks = null; + } + mHaveGottenCallbacks = true; + } + + return mGottenCallbacks; + } + + public void ungetCallbacks() { + mHaveGottenCallbacks = false; + } + public void setFixedSize(int width, int height) { if (mRequestedWidth != width || mRequestedHeight != height) { mRequestedWidth = width; diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java new file mode 100644 index 0000000..fcb1645 --- /dev/null +++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java @@ -0,0 +1,11 @@ +package com.android.internal.view; + +import android.view.SurfaceHolder; + +/** hahahah */ +public interface RootViewSurfaceTaker { + SurfaceHolder.Callback willYouTakeTheSurface(); + void setSurfaceType(int type); + void setSurfaceFormat(int format); + void setSurfaceKeepScreenOn(boolean keepOn); +} diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java index 23e2277..fa47ff6 100644 --- a/core/java/com/android/internal/widget/DigitalClock.java +++ b/core/java/com/android/internal/widget/DigitalClock.java @@ -30,7 +30,7 @@ import android.provider.Settings; import android.text.format.DateFormat; import android.util.AttributeSet; import android.view.View; -import android.widget.RelativeLayout; +import android.widget.LinearLayout; import android.widget.TextView; import java.text.DateFormatSymbols; @@ -39,7 +39,7 @@ import java.util.Calendar; /** * Displays the time */ -public class DigitalClock extends RelativeLayout { +public class DigitalClock extends LinearLayout { private final static String M12 = "h:mm"; private final static String M24 = "kk:mm"; diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a39d06b..dbad7e9 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -28,6 +28,7 @@ LOCAL_SRC_FILES:= \ Time.cpp \ com_google_android_gles_jni_EGLImpl.cpp \ com_google_android_gles_jni_GLImpl.cpp.arm \ + android_app_NativeActivity.cpp \ android_opengl_GLES10.cpp \ android_opengl_GLES10Ext.cpp \ android_opengl_GLES11.cpp \ @@ -50,6 +51,7 @@ LOCAL_SRC_FILES:= \ android_os_Debug.cpp \ android_os_FileUtils.cpp \ android_os_MemoryFile.cpp \ + android_os_MessageQueue.cpp \ android_os_ParcelFileDescriptor.cpp \ android_os_Power.cpp \ android_os_StatFs.cpp \ @@ -122,7 +124,6 @@ LOCAL_SRC_FILES:= \ android_server_BluetoothA2dpService.cpp \ android_message_digest_sha1.cpp \ android_ddm_DdmHandleNativeHeap.cpp \ - android_location_GpsLocationProvider.cpp \ com_android_internal_os_ZygoteInit.cpp \ com_android_internal_graphics_NativeUtils.cpp \ android_backup_BackupDataInput.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 9fbf171..76df9db 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -128,6 +128,7 @@ extern int register_android_nio_utils(JNIEnv* env); extern int register_android_pim_EventRecurrence(JNIEnv* env); extern int register_android_text_format_Time(JNIEnv* env); extern int register_android_os_Debug(JNIEnv* env); +extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_ParcelFileDescriptor(JNIEnv *env); extern int register_android_os_Power(JNIEnv *env); extern int register_android_os_StatFs(JNIEnv *env); @@ -155,11 +156,11 @@ extern int register_android_server_BluetoothEventLoop(JNIEnv *env); extern int register_android_server_BluetoothA2dpService(JNIEnv* env); extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv* env); -extern int register_android_location_GpsLocationProvider(JNIEnv* env); extern int register_android_backup_BackupDataInput(JNIEnv *env); extern int register_android_backup_BackupDataOutput(JNIEnv *env); extern int register_android_backup_FileBackupHelperBase(JNIEnv *env); extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env); +extern int register_android_app_NativeActivity(JNIEnv *env); static AndroidRuntime* gCurRuntime = NULL; @@ -1249,6 +1250,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_Debug), REG_JNI(register_android_os_FileObserver), REG_JNI(register_android_os_FileUtils), + REG_JNI(register_android_os_MessageQueue), REG_JNI(register_android_os_ParcelFileDescriptor), REG_JNI(register_android_os_Power), REG_JNI(register_android_os_StatFs), @@ -1278,11 +1280,12 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_server_BluetoothA2dpService), REG_JNI(register_android_message_digest_sha1), REG_JNI(register_android_ddm_DdmHandleNativeHeap), - REG_JNI(register_android_location_GpsLocationProvider), REG_JNI(register_android_backup_BackupDataInput), REG_JNI(register_android_backup_BackupDataOutput), REG_JNI(register_android_backup_FileBackupHelperBase), REG_JNI(register_android_backup_BackupHelperDispatcher), + + REG_JNI(register_android_app_NativeActivity), }; /* diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp new file mode 100644 index 0000000..f2ab134 --- /dev/null +++ b/core/jni/android_app_NativeActivity.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2010 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. + */ + +#define LOG_TAG "NativeActivity" +#include <utils/Log.h> + +#include "JNIHelp.h" +#include <android_runtime/AndroidRuntime.h> +#include <android/native_activity.h> + +#include <dlfcn.h> + +namespace android +{ + +struct NativeCode { + NativeCode(void* _dlhandle, android_activity_create_t* _createFunc) { + memset(&activity, sizeof(activity), 0); + memset(&callbacks, sizeof(callbacks), 0); + dlhandle = _dlhandle; + createActivityFunc = _createFunc; + surface = NULL; + } + + ~NativeCode() { + if (callbacks.onDestroy != NULL) { + callbacks.onDestroy(&activity); + } + if (dlhandle != NULL) { + dlclose(dlhandle); + } + } + + void setSurface(jobject _surface) { + if (surface != NULL) { + activity.env->DeleteGlobalRef(surface); + } + if (_surface != NULL) { + surface = activity.env->NewGlobalRef(_surface); + } else { + surface = NULL; + } + } + + android_activity_t activity; + android_activity_callbacks_t callbacks; + + void* dlhandle; + android_activity_create_t* createActivityFunc; + + jobject surface; +}; + +static jint +loadNativeCode_native(JNIEnv* env, jobject clazz, jstring path) +{ + const char* pathStr = env->GetStringUTFChars(path, NULL); + NativeCode* code = NULL; + + void* handle = dlopen(pathStr, RTLD_LAZY); + + env->ReleaseStringUTFChars(path, pathStr); + + if (handle != NULL) { + code = new NativeCode(handle, (android_activity_create_t*) + dlsym(handle, "android_onCreateActivity")); + if (code->createActivityFunc == NULL) { + LOGW("android_onCreateActivity not found"); + delete code; + return 0; + } + code->activity.callbacks = &code->callbacks; + code->activity.env = env; + code->activity.clazz = clazz; + code->createActivityFunc(&code->activity, NULL, 0); + } + + return (jint)code; +} + +static void +unloadNativeCode_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + delete code; + } +} + +static void +onStart_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onStart != NULL) { + code->callbacks.onStart(&code->activity); + } + } +} + +static void +onResume_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onResume != NULL) { + code->callbacks.onResume(&code->activity); + } + } +} + +static void +onSaveInstanceState_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onSaveInstanceState != NULL) { + size_t len = 0; + code->callbacks.onSaveInstanceState(&code->activity, &len); + } + } +} + +static void +onPause_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onPause != NULL) { + code->callbacks.onPause(&code->activity); + } + } +} + +static void +onStop_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onStop != NULL) { + code->callbacks.onStop(&code->activity); + } + } +} + +static void +onLowMemory_native(JNIEnv* env, jobject clazz, jint handle) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onLowMemory != NULL) { + code->callbacks.onLowMemory(&code->activity); + } + } +} + +static void +onWindowFocusChanged_native(JNIEnv* env, jobject clazz, jint handle, jboolean focused) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->callbacks.onWindowFocusChanged != NULL) { + code->callbacks.onWindowFocusChanged(&code->activity, focused ? 1 : 0); + } + } +} + +static void +onSurfaceCreated_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + code->setSurface(surface); + if (code->callbacks.onSurfaceCreated != NULL) { + code->callbacks.onSurfaceCreated(&code->activity, + (android_surface_t*)code->surface); + } + } +} + +static void +onSurfaceChanged_native(JNIEnv* env, jobject clazz, jint handle, jobject surface, + jint format, jint width, jint height) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->surface != NULL && code->callbacks.onSurfaceChanged != NULL) { + code->callbacks.onSurfaceChanged(&code->activity, + (android_surface_t*)code->surface, format, width, height); + } + } +} + +static void +onSurfaceDestroyed_native(JNIEnv* env, jobject clazz, jint handle, jobject surface) +{ + if (handle != 0) { + NativeCode* code = (NativeCode*)handle; + if (code->surface != NULL && code->callbacks.onSurfaceDestroyed != NULL) { + code->callbacks.onSurfaceDestroyed(&code->activity, + (android_surface_t*)code->surface); + } + code->setSurface(NULL); + } +} + +static const JNINativeMethod g_methods[] = { + { "loadNativeCode", "(Ljava/lang/String;)I", (void*)loadNativeCode_native }, + { "unloadNativeCode", "(I)V", (void*)unloadNativeCode_native }, + { "onStartNative", "(I)V", (void*)onStart_native }, + { "onResumeNative", "(I)V", (void*)onResume_native }, + { "onSaveInstanceStateNative", "(I)V", (void*)onSaveInstanceState_native }, + { "onPauseNative", "(I)V", (void*)onPause_native }, + { "onStopNative", "(I)V", (void*)onStop_native }, + { "onLowMemoryNative", "(I)V", (void*)onLowMemory_native }, + { "onWindowFocusChangedNative", "(IZ)V", (void*)onWindowFocusChanged_native }, + { "onSurfaceCreatedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceCreated_native }, + { "onSurfaceChangedNative", "(ILandroid/view/SurfaceHolder;III)V", (void*)onSurfaceChanged_native }, + { "onSurfaceDestroyedNative", "(ILandroid/view/SurfaceHolder;)V", (void*)onSurfaceDestroyed_native }, +}; + +static const char* const kNativeActivityPathName = "android/app/NativeActivity"; + +int register_android_app_NativeActivity(JNIEnv* env) +{ + //LOGD("register_android_app_NativeActivity"); + + jclass clazz; + + clazz = env->FindClass(kNativeActivityPathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.NativeActivity"); + + return AndroidRuntime::registerNativeMethods( + env, kNativeActivityPathName, + g_methods, NELEM(g_methods)); +} + +} diff --git a/core/jni/android_bluetooth_HeadsetBase.cpp b/core/jni/android_bluetooth_HeadsetBase.cpp index b0b0cb8..5593a26 100644 --- a/core/jni/android_bluetooth_HeadsetBase.cpp +++ b/core/jni/android_bluetooth_HeadsetBase.cpp @@ -169,7 +169,7 @@ again: // never receive non-ASCII UTF-8). // This was added because of the BMW 2005 E46 which sends binary junk. if (is_ascii(buf)) { - LOG(LOG_INFO, "Bluetooth AT recv", buf); + LOG(LOG_INFO, "Bluetooth AT recv", "%s", buf); } else { LOGW("Ignoring invalid AT command: %s", buf); buf[0] = NULL; @@ -494,7 +494,7 @@ static void pretty_log_urc(const char *urc) { } } } - LOG(LOG_INFO, "Bluetooth AT sent", buf); + LOG(LOG_INFO, "Bluetooth AT sent", "%s", buf); free(buf); } diff --git a/core/jni/android_bluetooth_common.cpp b/core/jni/android_bluetooth_common.cpp index 343fa53..9a8f1b8 100644 --- a/core/jni/android_bluetooth_common.cpp +++ b/core/jni/android_bluetooth_common.cpp @@ -65,6 +65,7 @@ static Properties adapter_properties[] = { {"PairableTimeout", DBUS_TYPE_UINT32}, {"Discovering", DBUS_TYPE_BOOLEAN}, {"Devices", DBUS_TYPE_ARRAY}, + {"UUIDs", DBUS_TYPE_ARRAY}, }; typedef union { diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index b85466b..c363156 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -288,10 +288,16 @@ void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) } } +static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz) +{ + return Camera::getNumberOfCameras(); +} + // connect to camera service -static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) +static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, + jobject weak_this, jint cameraId) { - sp<Camera> camera = Camera::connect(); + sp<Camera> camera = Camera::connect(cameraId); if (camera == NULL) { jniThrowException(env, "java/lang/RuntimeException", @@ -566,8 +572,11 @@ static void android_hardware_Camera_setDisplayOrientation(JNIEnv *env, jobject t //------------------------------------------------- static JNINativeMethod camMethods[] = { + { "getNumberOfCameras", + "()I", + (void *)android_hardware_Camera_getNumberOfCameras }, { "native_setup", - "(Ljava/lang/Object;)V", + "(Ljava/lang/Object;I)V", (void*)android_hardware_Camera_native_setup }, { "native_release", "()V", @@ -659,7 +668,7 @@ int register_android_hardware_Camera(JNIEnv *env) { field fields_to_find[] = { { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, - { "android/view/Surface", "mSurface", "I", &fields.surface } + { "android/view/Surface", ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface } }; if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp deleted file mode 100755 index f60fe6d..0000000 --- a/core/jni/android_location_GpsLocationProvider.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/* - * 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. - */ - -#define LOG_TAG "GpsLocationProvider" - -//#define LOG_NDDEBUG 0 - -#include "JNIHelp.h" -#include "jni.h" -#include "hardware_legacy/gps.h" -#include "hardware_legacy/gps_ni.h" -#include "utils/Log.h" -#include "utils/misc.h" - -#include <string.h> -#include <pthread.h> - -static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER; -static jmethodID method_reportLocation; -static jmethodID method_reportStatus; -static jmethodID method_reportSvStatus; -static jmethodID method_reportAGpsStatus; -static jmethodID method_reportNmea; -static jmethodID method_xtraDownloadRequest; -static jmethodID method_reportNiNotification; - -static const GpsInterface* sGpsInterface = NULL; -static const GpsXtraInterface* sGpsXtraInterface = NULL; -static const AGpsInterface* sAGpsInterface = NULL; -static const GpsPrivacyInterface* sGpsPrivacyInterface = NULL; -static const GpsNiInterface* sGpsNiInterface = NULL; -static const GpsDebugInterface* sGpsDebugInterface = NULL; - -// data written to by GPS callbacks -static GpsLocation sGpsLocation; -static GpsStatus sGpsStatus; -static GpsSvStatus sGpsSvStatus; -static AGpsStatus sAGpsStatus; -static GpsNiNotification sGpsNiNotification; - -// buffer for NMEA data -#define NMEA_SENTENCE_LENGTH 100 -#define NMEA_SENTENCE_COUNT 40 -struct NmeaSentence { - GpsUtcTime timestamp; - char nmea[NMEA_SENTENCE_LENGTH]; -}; -static NmeaSentence sNmeaBuffer[NMEA_SENTENCE_COUNT]; -static int mNmeaSentenceCount = 0; - -// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event -// and android_location_GpsLocationProvider_read_status -static GpsLocation sGpsLocationCopy; -static GpsStatus sGpsStatusCopy; -static GpsSvStatus sGpsSvStatusCopy; -static AGpsStatus sAGpsStatusCopy; -static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_COUNT]; -static GpsNiNotification sGpsNiNotificationCopy; - -enum CallbackType { - kLocation = 1, - kStatus = 2, - kSvStatus = 4, - kAGpsStatus = 8, - kXtraDownloadRequest = 16, - kDisableRequest = 32, - kNmeaAvailable = 64, - kNiNotification = 128, -}; -static int sPendingCallbacks; - -namespace android { - -static void location_callback(GpsLocation* location) -{ - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kLocation; - memcpy(&sGpsLocation, location, sizeof(sGpsLocation)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void status_callback(GpsStatus* status) -{ - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kStatus; - memcpy(&sGpsStatus, status, sizeof(sGpsStatus)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void sv_status_callback(GpsSvStatus* sv_status) -{ - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kSvStatus; - memcpy(&sGpsSvStatus, sv_status, sizeof(GpsSvStatus)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length) -{ - pthread_mutex_lock(&sEventMutex); - - if (length >= NMEA_SENTENCE_LENGTH) { - LOGE("NMEA data too long in nmea_callback (length = %d)\n", length); - length = NMEA_SENTENCE_LENGTH - 1; - } - if (mNmeaSentenceCount >= NMEA_SENTENCE_COUNT) { - LOGE("NMEA data overflowed buffer\n"); - pthread_mutex_unlock(&sEventMutex); - return; - } - - sPendingCallbacks |= kNmeaAvailable; - sNmeaBuffer[mNmeaSentenceCount].timestamp = timestamp; - memcpy(sNmeaBuffer[mNmeaSentenceCount].nmea, nmea, length); - sNmeaBuffer[mNmeaSentenceCount].nmea[length] = 0; - mNmeaSentenceCount++; - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void agps_status_callback(AGpsStatus* agps_status) -{ - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kAGpsStatus; - memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -GpsCallbacks sGpsCallbacks = { - location_callback, - status_callback, - sv_status_callback, - nmea_callback -}; - -static void -download_request_callback() -{ - pthread_mutex_lock(&sEventMutex); - sPendingCallbacks |= kXtraDownloadRequest; - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void -gps_ni_notify_callback(GpsNiNotification *notification) -{ - LOGD("gps_ni_notify_callback: notif=%d", notification->notification_id); - - pthread_mutex_lock(&sEventMutex); - - sPendingCallbacks |= kNiNotification; - memcpy(&sGpsNiNotification, notification, sizeof(GpsNiNotification)); - - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -GpsXtraCallbacks sGpsXtraCallbacks = { - download_request_callback, -}; - -AGpsCallbacks sAGpsCallbacks = { - agps_status_callback, -}; - -GpsNiCallbacks sGpsNiCallbacks = { - gps_ni_notify_callback, -}; - -static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { - method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); - method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); - method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); - method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V"); - method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V"); - method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); - method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V"); -} - -static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) { - if (!sGpsInterface) - sGpsInterface = gps_get_interface(); - return (sGpsInterface != NULL); -} - -static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) -{ - if (!sGpsInterface) - sGpsInterface = gps_get_interface(); - if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) - return false; - - if (!sAGpsInterface) - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - if (sAGpsInterface) - sAGpsInterface->init(&sAGpsCallbacks); - - if (!sGpsNiInterface) - sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE); - if (sGpsNiInterface) - sGpsNiInterface->init(&sGpsNiCallbacks); - - // Clear privacy lock while enabled - if (!sGpsPrivacyInterface) - sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE); - if (sGpsPrivacyInterface) - sGpsPrivacyInterface->set_privacy_lock(0); - - if (!sGpsDebugInterface) - sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE); - - return true; -} - -static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj) -{ - // Enable privacy lock while disabled - if (!sGpsPrivacyInterface) - sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE); - if (sGpsPrivacyInterface) - sGpsPrivacyInterface->set_privacy_lock(1); - - pthread_mutex_lock(&sEventMutex); - sPendingCallbacks |= kDisableRequest; - pthread_cond_signal(&sEventCond); - pthread_mutex_unlock(&sEventMutex); -} - -static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) -{ - sGpsInterface->cleanup(); -} - -static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode, - jboolean singleFix, jint fixFrequency) -{ - int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency)); - if (result) { - return false; - } - - return (sGpsInterface->start() == 0); -} - -static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj) -{ - return (sGpsInterface->stop() == 0); -} - -static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) -{ - sGpsInterface->delete_aiding_data(flags); -} - -static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj) -{ - pthread_mutex_lock(&sEventMutex); - while (sPendingCallbacks == 0) { - pthread_cond_wait(&sEventCond, &sEventMutex); - } - - // copy and clear the callback flags - int pendingCallbacks = sPendingCallbacks; - sPendingCallbacks = 0; - int nmeaSentenceCount = mNmeaSentenceCount; - mNmeaSentenceCount = 0; - - // copy everything and unlock the mutex before calling into Java code to avoid the possibility - // of timeouts in the GPS engine. - if (pendingCallbacks & kLocation) - memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy)); - if (pendingCallbacks & kStatus) - memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy)); - if (pendingCallbacks & kSvStatus) - memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy)); - if (pendingCallbacks & kAGpsStatus) - memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy)); - if (pendingCallbacks & kNmeaAvailable) - memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0])); - if (pendingCallbacks & kNiNotification) - memcpy(&sGpsNiNotificationCopy, &sGpsNiNotification, sizeof(sGpsNiNotificationCopy)); - pthread_mutex_unlock(&sEventMutex); - - if (pendingCallbacks & kLocation) { - env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags, - (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude, - (jdouble)sGpsLocationCopy.altitude, - (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing, - (jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp); - } - if (pendingCallbacks & kStatus) { - env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status); - } - if (pendingCallbacks & kSvStatus) { - env->CallVoidMethod(obj, method_reportSvStatus); - } - if (pendingCallbacks & kAGpsStatus) { - env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status); - } - if (pendingCallbacks & kNmeaAvailable) { - for (int i = 0; i < nmeaSentenceCount; i++) { - env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp); - } - } - if (pendingCallbacks & kXtraDownloadRequest) { - env->CallVoidMethod(obj, method_xtraDownloadRequest); - } - if (pendingCallbacks & kDisableRequest) { - // don't need to do anything - we are just poking so wait_for_event will return. - } - if (pendingCallbacks & kNiNotification) { - LOGD("android_location_GpsLocationProvider_wait_for_event: sent notification callback."); - jstring reqId = env->NewStringUTF(sGpsNiNotificationCopy.requestor_id); - jstring text = env->NewStringUTF(sGpsNiNotificationCopy.text); - jstring extras = env->NewStringUTF(sGpsNiNotificationCopy.extras); - env->CallVoidMethod(obj, method_reportNiNotification, - sGpsNiNotificationCopy.notification_id, - sGpsNiNotificationCopy.ni_type, - sGpsNiNotificationCopy.notify_flags, - sGpsNiNotificationCopy.timeout, - sGpsNiNotificationCopy.default_response, - reqId, - text, - sGpsNiNotificationCopy.requestor_id_encoding, - sGpsNiNotificationCopy.text_encoding, - extras - ); - } -} - -static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj, - jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray, - jintArray maskArray) -{ - // this should only be called from within a call to reportStatus, so we don't need to lock here - - jint* prns = env->GetIntArrayElements(prnArray, 0); - jfloat* snrs = env->GetFloatArrayElements(snrArray, 0); - jfloat* elev = env->GetFloatArrayElements(elevArray, 0); - jfloat* azim = env->GetFloatArrayElements(azumArray, 0); - jint* mask = env->GetIntArrayElements(maskArray, 0); - - int num_svs = sGpsSvStatusCopy.num_svs; - for (int i = 0; i < num_svs; i++) { - prns[i] = sGpsSvStatusCopy.sv_list[i].prn; - snrs[i] = sGpsSvStatusCopy.sv_list[i].snr; - elev[i] = sGpsSvStatusCopy.sv_list[i].elevation; - azim[i] = sGpsSvStatusCopy.sv_list[i].azimuth; - } - mask[0] = sGpsSvStatusCopy.ephemeris_mask; - mask[1] = sGpsSvStatusCopy.almanac_mask; - mask[2] = sGpsSvStatusCopy.used_in_fix_mask; - - env->ReleaseIntArrayElements(prnArray, prns, 0); - env->ReleaseFloatArrayElements(snrArray, snrs, 0); - env->ReleaseFloatArrayElements(elevArray, elev, 0); - env->ReleaseFloatArrayElements(azumArray, azim, 0); - env->ReleaseIntArrayElements(maskArray, mask, 0); - return num_svs; -} - -static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jint index, jbyteArray nmeaArray, jint buffer_size) -{ - // this should only be called from within a call to reportNmea, so we don't need to lock here - - jbyte* nmea = env->GetByteArrayElements(nmeaArray, 0); - - int length = strlen(sNmeaBufferCopy[index].nmea); - if (length > buffer_size) - length = buffer_size; - memcpy(nmea, sNmeaBufferCopy[index].nmea, length); - - env->ReleaseByteArrayElements(nmeaArray, nmea, 0); - return length; -} - -static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time, - jlong timeReference, jint uncertainty) -{ - sGpsInterface->inject_time(time, timeReference, uncertainty); -} - -static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj, - jdouble latitude, jdouble longitude, jfloat accuracy) -{ - sGpsInterface->inject_location(latitude, longitude, accuracy); -} - -static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj) -{ - if (!sGpsXtraInterface) { - sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE); - if (sGpsXtraInterface) { - int result = sGpsXtraInterface->init(&sGpsXtraCallbacks); - if (result) { - sGpsXtraInterface = NULL; - } - } - } - - return (sGpsXtraInterface != NULL); -} - -static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj, - jbyteArray data, jint length) -{ - jbyte* bytes = env->GetByteArrayElements(data, 0); - sGpsXtraInterface->inject_xtra_data((char *)bytes, length); - env->ReleaseByteArrayElements(data, bytes, 0); -} - -static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - if (apn == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return; - } - const char *apnStr = env->GetStringUTFChars(apn, NULL); - sAGpsInterface->data_conn_open(apnStr); - env->ReleaseStringUTFChars(apn, apnStr); - } -} - -static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - sAGpsInterface->data_conn_closed(); - } -} - -static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - sAGpsInterface->data_conn_failed(); - } -} - -static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, - jint type, jstring hostname, jint port) -{ - if (!sAGpsInterface) { - sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); - } - if (sAGpsInterface) { - const char *c_hostname = env->GetStringUTFChars(hostname, NULL); - sAGpsInterface->set_server(type, c_hostname, port); - env->ReleaseStringUTFChars(hostname, c_hostname); - } -} - -static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj, - jint notifId, jint response) -{ - if (!sGpsNiInterface) - sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE); - if (sGpsNiInterface) - sGpsNiInterface->respond(notifId, response); -} - -static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj) -{ - jstring result = NULL; - if (sGpsDebugInterface) { - const size_t maxLength = 2047; - char buffer[maxLength+1]; - size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength); - if (length > maxLength) length = maxLength; - buffer[length] = 0; - result = env->NewStringUTF(buffer); - } - return result; -} - -static JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, - {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, - {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}, - {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable}, - {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup}, - {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start}, - {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop}, - {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data}, - {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event}, - {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status}, - {"native_read_nmea", "(I[BI)I", (void*)android_location_GpsLocationProvider_read_nmea}, - {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time}, - {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location}, - {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, - {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, - {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, - {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed}, - {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed}, - {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server}, - {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response}, - {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state}, -}; - -int register_android_location_GpsLocationProvider(JNIEnv* env) -{ - return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods)); -} - -} /* namespace android */ diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp new file mode 100644 index 0000000..8984057 --- /dev/null +++ b/core/jni/android_os_MessageQueue.cpp @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2010 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. + */ + +#define LOG_TAG "MQNative" + +#include "JNIHelp.h" + +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <fcntl.h> + +#include <android_runtime/AndroidRuntime.h> +#include <utils/SystemClock.h> +#include <utils/Vector.h> +#include <utils/Log.h> + +using namespace android; + +// ---------------------------------------------------------------------------- + +static struct { + jclass mClass; + + jfieldID mObject; // native object attached to the DVM MessageQueue +} gMessageQueueOffsets; + +static struct { + jclass mClass; + jmethodID mConstructor; +} gKeyEventOffsets; + +// TODO: also MotionEvent offsets etc. a la gKeyEventOffsets + +static struct { + jclass mClass; + jmethodID mObtain; // obtain(Handler h, int what, Object obj) +} gMessageOffsets; + +// ---------------------------------------------------------------------------- + +static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) +{ + if (jniThrowException(env, exc, msg) != 0) + assert(false); +} + +// ---------------------------------------------------------------------------- + +class MessageQueueNative { +public: + MessageQueueNative(int readSocket, int writeSocket); + ~MessageQueueNative(); + + // select on all FDs until the designated time; forever if wakeupTime is < 0 + int waitForSignal(jobject mqueue, jlong wakeupTime); + + // signal the queue-ready pipe + void signalQueuePipe(); + + // Specify a new input pipe, passing in responsibility for the socket fd and + // ashmem region + int registerInputPipe(JNIEnv* env, int socketFd, int memRegionFd, jobject handler); + + // Forget about this input pipe, closing the socket and ashmem region as well + int unregisterInputPipe(JNIEnv* env, int socketFd); + + size_t numRegisteredPipes() const { return mInputPipes.size(); } + +private: + struct InputPipe { + int fd; + int region; + jobject handler; + + InputPipe() {} + InputPipe(int _fd, int _r, jobject _h) : fd(_fd), region(_r), handler(_h) {} + }; + + // consume an event from a socket, put it on the DVM MessageQueue indicated, + // and notify the other end of the pipe that we've consumed it. + void queueEventFromPipe(const InputPipe& pipe, jobject mqueue); + + int mQueueReadFd, mQueueWriteFd; + Vector<InputPipe> mInputPipes; +}; + +MessageQueueNative::MessageQueueNative(int readSocket, int writeSocket) + : mQueueReadFd(readSocket), mQueueWriteFd(writeSocket) { +} + +MessageQueueNative::~MessageQueueNative() { +} + +int MessageQueueNative::waitForSignal(jobject mqueue, jlong timeoutMillis) { + struct timeval tv, *timeout; + fd_set fdset; + + if (timeoutMillis < 0) { + timeout = NULL; + } else { + if (timeoutMillis == 0) { + tv.tv_sec = 0; + tv.tv_usec = 0; + } else { + tv.tv_sec = (timeoutMillis / 1000); + tv.tv_usec = (timeoutMillis - (1000 * tv.tv_sec)) * 1000; + } + timeout = &tv; + } + + // always rebuild the fd set from scratch + FD_ZERO(&fdset); + + // the queue signalling pipe + FD_SET(mQueueReadFd, &fdset); + int maxFd = mQueueReadFd; + + // and the input sockets themselves + for (size_t i = 0; i < mInputPipes.size(); i++) { + FD_SET(mInputPipes[i].fd, &fdset); + if (maxFd < mInputPipes[i].fd) { + maxFd = mInputPipes[i].fd; + } + } + + // now wait + int res = select(maxFd + 1, &fdset, NULL, NULL, timeout); + + // Error? Just return it and bail + if (res < 0) return res; + + // What happened -- timeout or actual data arrived? + if (res == 0) { + // select() returned zero, which means we timed out, which means that it's time + // to deliver the head element that was already on the queue. Just fall through + // without doing anything else. + } else { + // Data (or a queue signal) arrived! + // + // If it's data, pull the data off the pipe, build a new Message with it, put it on + // the DVM-side MessageQueue (pointed to by the 'mqueue' parameter), then proceed + // into the queue-signal case. + // + // If a queue signal arrived, just consume any data pending in that pipe and + // fall out. + bool queue_signalled = (FD_ISSET(mQueueReadFd, &fdset) != 0); + + for (size_t i = 0; i < mInputPipes.size(); i++) { + if (FD_ISSET(mInputPipes[i].fd, &fdset)) { + queueEventFromPipe(mInputPipes[i], mqueue); + queue_signalled = true; // we know a priori that queueing the event does this + } + } + + // Okay, stuff went on the queue. Consume the contents of the signal pipe + // now that we're awake and about to start dispatching messages again. + if (queue_signalled) { + uint8_t buf[16]; + ssize_t nRead; + do { + nRead = read(mQueueReadFd, buf, sizeof(buf)); + } while (nRead > 0); // in nonblocking mode we'll get -1 when it's drained + } + } + + return 0; +} + +// signals to the queue pipe are one undefined byte. it's just a "data has arrived" token +// and the pipe is drained on receipt of at least one signal +void MessageQueueNative::signalQueuePipe() { + int dummy[1]; + write(mQueueWriteFd, dummy, 1); +} + +void MessageQueueNative::queueEventFromPipe(const InputPipe& inPipe, jobject mqueue) { + // !!! TODO: read the event data from the InputPipe's ashmem region, convert it to a DVM + // event object of the proper type [MotionEvent or KeyEvent], create a Message holding + // it as appropriate, point the Message to the Handler associated with this InputPipe, + // and call up to the DVM MessageQueue implementation to enqueue it for delivery. +} + +// the number of registered pipes on success; < 0 on error +int MessageQueueNative::registerInputPipe(JNIEnv* env, + int socketFd, int memRegionFd, jobject handler) { + // make sure this fd is not already known to us + for (size_t i = 0; i < mInputPipes.size(); i++) { + if (mInputPipes[i].fd == socketFd) { + LOGE("Attempt to re-register input fd %d", socketFd); + return -1; + } + } + + mInputPipes.push( InputPipe(socketFd, memRegionFd, env->NewGlobalRef(handler)) ); + return mInputPipes.size(); +} + +// Remove an input pipe from our bookkeeping. Also closes the socket and ashmem +// region file descriptor! +// +// returns the number of remaining input pipes on success; < 0 on error +int MessageQueueNative::unregisterInputPipe(JNIEnv* env, int socketFd) { + for (size_t i = 0; i < mInputPipes.size(); i++) { + if (mInputPipes[i].fd == socketFd) { + close(mInputPipes[i].fd); + close(mInputPipes[i].region); + env->DeleteGlobalRef(mInputPipes[i].handler); + mInputPipes.removeAt(i); + return mInputPipes.size(); + } + } + LOGW("Tried to unregister input pipe %d but not found!", socketFd); + return -1; +} + +// ---------------------------------------------------------------------------- + +namespace android { + +static void android_os_MessageQueue_init(JNIEnv* env, jobject obj) { + // Create the pipe + int fds[2]; + int err = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); + if (err != 0) { + doThrow(env, "java/lang/RuntimeException", "Unable to create socket pair"); + } + + MessageQueueNative *mqn = new MessageQueueNative(fds[0], fds[1]); + if (mqn == NULL) { + close(fds[0]); + close(fds[1]); + doThrow(env, "java/lang/RuntimeException", "Unable to allocate native queue"); + } + + int flags = fcntl(fds[0], F_GETFL); + fcntl(fds[0], F_SETFL, flags | O_NONBLOCK); + flags = fcntl(fds[1], F_GETFL); + fcntl(fds[1], F_SETFL, flags | O_NONBLOCK); + + env->SetIntField(obj, gMessageQueueOffsets.mObject, (jint)mqn); +} + +static void android_os_MessageQueue_signal(JNIEnv* env, jobject obj) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + mqn->signalQueuePipe(); + } else { + doThrow(env, "java/lang/IllegalStateException", "Queue not initialized"); + } +} + +static int android_os_MessageQueue_waitForNext(JNIEnv* env, jobject obj, jlong when) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + int res = mqn->waitForSignal(obj, when); + return res; // the DVM event, if any, has been constructed and queued now + } + + return -1; +} + +static void android_os_MessageQueue_registerInputStream(JNIEnv* env, jobject obj, + jint socketFd, jint regionFd, jobject handler) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + mqn->registerInputPipe(env, socketFd, regionFd, handler); + } else { + doThrow(env, "java/lang/IllegalStateException", "Queue not initialized"); + } +} + +static void android_os_MessageQueue_unregisterInputStream(JNIEnv* env, jobject obj, + jint socketFd) { + MessageQueueNative *mqn = (MessageQueueNative*) env->GetIntField(obj, gMessageQueueOffsets.mObject); + if (mqn != NULL) { + mqn->unregisterInputPipe(env, socketFd); + } else { + doThrow(env, "java/lang/IllegalStateException", "Queue not initialized"); + } +} + +// ---------------------------------------------------------------------------- + +const char* const kKeyEventPathName = "android/view/KeyEvent"; +const char* const kMessagePathName = "android/os/Message"; +const char* const kMessageQueuePathName = "android/os/MessageQueue"; + +static JNINativeMethod gMessageQueueMethods[] = { + /* name, signature, funcPtr */ + { "nativeInit", "()V", (void*)android_os_MessageQueue_init }, + { "nativeSignal", "()V", (void*)android_os_MessageQueue_signal }, + { "nativeWaitForNext", "(J)I", (void*)android_os_MessageQueue_waitForNext }, + { "nativeRegisterInputStream", "(IILandroid/os/Handler;)V", (void*)android_os_MessageQueue_registerInputStream }, + { "nativeUnregisterInputStream", "(I)V", (void*)android_os_MessageQueue_unregisterInputStream }, +}; + +int register_android_os_MessageQueue(JNIEnv* env) { + jclass clazz; + + clazz = env->FindClass(kMessageQueuePathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.MessageQueue"); + gMessageQueueOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gMessageQueueOffsets.mObject = env->GetFieldID(clazz, "mObject", "I"); + assert(gMessageQueueOffsets.mObject); + + clazz = env->FindClass(kMessagePathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Message"); + gMessageOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gMessageOffsets.mObtain = env->GetStaticMethodID(clazz, "obtain", + "(Landroid/os/Handler;ILjava/lang/Object;)Landroid/os/Message;"); + assert(gMessageOffsets.mObtain); + + clazz = env->FindClass(kKeyEventPathName); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.view.KeyEvent"); + gKeyEventOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gKeyEventOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(JJIIIIIII)V"); + assert(gKeyEventOffsets.mConstructor); + + return AndroidRuntime::registerNativeMethods(env, kMessageQueuePathName, + gMessageQueueMethods, NELEM(gMessageQueueMethods)); +} + + +}; // end of namespace android diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index a2b7cc4..b7d0c67 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -1504,8 +1504,7 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* } jobjectArray array = env->NewObjectArray(N, cls, NULL); - if (array == NULL) { - doThrow(env, "java/lang/OutOfMemoryError"); + if (env->ExceptionCheck()) { res.unlockBag(startOfBag); return NULL; } @@ -1533,15 +1532,23 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* } else { const char16_t* str16 = pool->stringAt(value.data, &strLen); str = env->NewString(str16, strLen); - if (str == NULL) { - doThrow(env, "java/lang/OutOfMemoryError"); - res.unlockBag(startOfBag); - return NULL; - } + } + + // If one of our NewString{UTF} calls failed due to memory, an + // exception will be pending. + if (env->ExceptionCheck()) { + res.unlockBag(startOfBag); + return NULL; } } env->SetObjectArrayElement(array, i, str); + + // If we have a large amount of strings in our array, we might + // overflow the local reference table of the VM. + if (str != NULL) { + env->DeleteLocalRef(str); + } } res.unlockBag(startOfBag); return array; diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 788374b..838ef22 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -19,6 +19,7 @@ #include "android_util_Binder.h" #include <surfaceflinger/SurfaceComposerClient.h> +#include <surfaceflinger/Surface.h> #include <ui/Region.h> #include <ui/Rect.h> @@ -332,7 +333,7 @@ static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect) SkRegion clipReg; if (dirtyRegion.isRect()) { // very common case - const Rect& b(dirtyRegion.getBounds()); + const Rect b(dirtyRegion.getBounds()); clipReg.setRect(b.left, b.top, b.right, b.bottom); } else { size_t count; @@ -680,7 +681,7 @@ static JNINativeMethod gSurfaceMethods[] = { void nativeClassInit(JNIEnv* env, jclass clazz) { - so.surface = env->GetFieldID(clazz, "mSurface", "I"); + so.surface = env->GetFieldID(clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I"); so.surfaceControl = env->GetFieldID(clazz, "mSurfaceControl", "I"); so.saveCount = env->GetFieldID(clazz, "mSaveCount", "I"); so.canvas = env->GetFieldID(clazz, "mCanvas", "Landroid/graphics/Canvas;"); diff --git a/core/jni/android_view_ViewRoot.cpp b/core/jni/android_view_ViewRoot.cpp index 9d62d89..70ad8c5 100644 --- a/core/jni/android_view_ViewRoot.cpp +++ b/core/jni/android_view_ViewRoot.cpp @@ -16,6 +16,7 @@ #include <stdio.h> #include <assert.h> +#include <sys/socket.h> #include <core/SkCanvas.h> #include <core/SkDevice.h> @@ -24,6 +25,7 @@ #include "GraphicsJNI.h" #include "jni.h" +#include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> #include <utils/misc.h> @@ -78,6 +80,39 @@ static void android_view_ViewRoot_abandonGlCaches(JNIEnv* env, jobject) { SkGLCanvas::AbandonAllTextures(); } +static jintArray android_view_ViewRoot_makeInputChannel(JNIEnv* env, jobject) { + int fd[2]; + jint* arrayData = NULL; + + // Create the pipe + int err = socketpair(AF_LOCAL, SOCK_STREAM, 0, fd); + if (err != 0) { + fprintf(stderr, "socketpair() failed: %d\n", errno); + doThrow(env, "java/lang/RuntimeException", "Unable to create pipe"); + return NULL; + } + + // Set up the return array + jintArray array = env->NewIntArray(2); + if (env->ExceptionCheck()) { + fprintf(stderr, "Exception allocating fd array"); + goto bail; + } + + arrayData = env->GetIntArrayElements(array, 0); + arrayData[0] = fd[0]; + arrayData[1] = fd[1]; + env->ReleaseIntArrayElements(array, arrayData, 0); + + return array; + +bail: + env->DeleteLocalRef(array); + close(fd[0]); + close(fd[1]); + return NULL; +} + // ---------------------------------------------------------------------------- const char* const kClassPathName = "android/view/ViewRoot"; @@ -86,7 +121,9 @@ static JNINativeMethod gMethods[] = { { "nativeShowFPS", "(Landroid/graphics/Canvas;I)V", (void*)android_view_ViewRoot_showFPS }, { "nativeAbandonGlCaches", "()V", - (void*)android_view_ViewRoot_abandonGlCaches } + (void*)android_view_ViewRoot_abandonGlCaches }, + { "makeInputChannel", "()[I", + (void*)android_view_ViewRoot_makeInputChannel } }; int register_android_view_ViewRoot(JNIEnv* env) { diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp index 6a8c4b9..01a1504 100644 --- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp +++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp @@ -96,7 +96,7 @@ static void nativeClassInit(JNIEnv *_env, jclass eglImplClass) gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class, "mEGLConfig", "I"); jclass surface_class = _env->FindClass("android/view/Surface"); - gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, "mSurface", "I"); + gSurface_SurfaceFieldID = _env->GetFieldID(surface_class, ANDROID_VIEW_SURFACE_JNI_ID, "I"); jclass bitmap_class = _env->FindClass("android/graphics/Bitmap"); gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "I"); diff --git a/core/res/res/layout/keyguard_screen_tab_unlock.xml b/core/res/res/layout/keyguard_screen_tab_unlock.xml index 200a1b2..79ca617 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock.xml @@ -65,7 +65,7 @@ android:layout_below="@id/carrier" android:layout_marginTop="52dip" android:layout_marginLeft="20dip" - android:paddingBottom="8dip" + android:layout_marginBottom="8dip" > <TextView android:id="@+id/timeDisplay" diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml index 23505c2..8353887 100644 --- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml +++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml @@ -66,7 +66,7 @@ android:layout_height="wrap_content" android:layout_below="@id/carrier" android:layout_marginTop="56dip" - android:paddingBottom="8dip" + android:layout_marginBottom="8dip" > <TextView android:id="@+id/timeDisplay" diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml index b5cd442..c1b406f 100644 --- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml +++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml @@ -58,19 +58,18 @@ android:ellipsize="marquee" android:gravity="right|bottom" /> - <com.android.internal.widget.DigitalClock android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_marginTop="8dip" - android:paddingBottom="8dip" > <TextView android:id="@+id/timeDisplay" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:gravity="bottom" android:singleLine="true" android:ellipsize="none" android:textSize="72sp" @@ -85,9 +84,8 @@ <TextView android:id="@+id/am_pm" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toRightOf="@id/timeDisplay" - android:layout_alignBaseline="@id/timeDisplay" + android:layout_height="match_parent" + android:gravity="bottom" android:singleLine="true" android:ellipsize="none" android:textSize="22sp" diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml index 9ac0a47..74a0eee 100644 --- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml +++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml @@ -55,12 +55,12 @@ android:layout_alignParentTop="true" android:layout_marginTop="15dip" android:layout_marginLeft="20dip" - android:paddingBottom="8dip" > <TextView android:id="@+id/timeDisplay" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:gravity="bottom" android:singleLine="true" android:ellipsize="none" android:textSize="56sp" @@ -74,9 +74,8 @@ <TextView android:id="@+id/am_pm" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toRightOf="@id/timeDisplay" - android:layout_alignBaseline="@id/timeDisplay" + android:layout_height="match_parent" + android:gravity="bottom" android:singleLine="true" android:ellipsize="none" android:textSize="18sp" diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index ed7447c..b4c4811 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -62,6 +62,22 @@ a reference to a Drawable resource containing the image definition. --> <attr name="icon" format="reference" /> + <!-- A Drawable resource providing an extended graphical logo for its + associated item. Use with the application tag (to supply a default + logo for all application components), or with the activity, receiver, + service, or instrumentation tag (to supply a specific logo for that + component). It may also be used with the intent-filter tag to supply + a logo to show to the user when an activity is being selected based + on a particular Intent. + + <p>The given logo will be used to display to the user a graphical + representation of its associated component; for example as the + header in the Action Bar. The primary differences between an icon + and a logo are that logos are often wider and more detailed, and are + used without an accompanying text caption. This must be a reference + to a Drawable resource containing the image definition. --> + <attr name="logo" format="reference" /> + <!-- Name of the activity to be launched to manage application's space on device. The specified activity gets automatically launched when the application's space needs to be managed and is usually invoked @@ -79,6 +95,13 @@ by applications. --> <attr name="allowClearUserData" format="boolean" /> + <!-- Option to let applications specify that user data should + never be encrypted if an Encrypted File System solution + is enabled. Specifically, this is an "opt-out" feature, meaning + that, by default, user data will be encrypted if the EFS feature + is enabled. --> + <attr name="neverEncrypt" format="boolean" /> + <!-- Option to indicate this application is only for testing purposes. For example, it may expose functionality or data outside of itself that would cause a security hole, but is useful for testing. This @@ -688,6 +711,7 @@ <attr name="theme" /> <attr name="label" /> <attr name="icon" /> + <attr name="logo" /> <attr name="description" /> <attr name="permission" /> <attr name="process" /> @@ -715,6 +739,7 @@ <attr name="killAfterRestore" /> <attr name="restoreNeedsApplication" /> <attr name="restoreAnyVersion" /> + <attr name="neverEncrypt" /> </declare-styleable> <!-- The <code>permission</code> tag declares a security permission that can be @@ -734,6 +759,7 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> + <attr name="logo" /> <attr name="permissionGroup" /> <attr name="description" /> <attr name="protectionLevel" /> @@ -758,6 +784,7 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> + <attr name="logo" /> <attr name="description" /> </declare-styleable> @@ -787,6 +814,7 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> + <attr name="logo" /> </declare-styleable> <!-- The <code>uses-permission</code> tag requests a @@ -937,6 +965,8 @@ screen, so that it retains the dimensions it was originally designed for. --> <attr name="largeScreens" format="boolean" /> + <!-- Indicates whether the application supports extra large screen form-factors. --> + <attr name="xlargeScreens" format="boolean" /> <!-- Indicates whether the application can resize itself to newer screen sizes. This is mostly used to distinguish between old applications that may not be compatible with newly introduced @@ -989,6 +1019,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="logo" /> <attr name="process" /> <attr name="authorities" /> <attr name="syncable" /> @@ -1068,6 +1099,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="logo" /> <attr name="permission" /> <attr name="process" /> <!-- Specify whether the service is enabled or not (that is, can be instantiated by the system). @@ -1100,6 +1132,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="logo" /> <attr name="permission" /> <attr name="process" /> <!-- Specify whether the receiver is enabled or not (that is, can be instantiated by the system). @@ -1132,6 +1165,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="logo" /> <attr name="launchMode" /> <attr name="screenOrientation" /> <attr name="configChanges" /> @@ -1185,6 +1219,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="logo" /> <attr name="permission" /> <!-- Specify whether the activity-alias is enabled or not (that is, can be instantiated by the system). It can also be specified for an application as a whole, in which case a value of "false" @@ -1254,6 +1289,7 @@ parent="AndroidManifestActivity AndroidManifestReceiver AndroidManifestService"> <attr name="label" /> <attr name="icon" /> + <attr name="logo" /> <attr name="priority" /> </declare-styleable> @@ -1360,6 +1396,7 @@ <attr name="targetPackage" /> <attr name="label" /> <attr name="icon" /> + <attr name="logo" /> <attr name="handleProfiling" /> <attr name="functionalTest" /> </declare-styleable> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 98c3a0a..5d18e9e 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1239,4 +1239,23 @@ <public type="anim" name="cycle_interpolator" id="0x010a000c" /> +<!-- =============================================================== + Resources introduced in kraken. + =============================================================== --> + + <public type="attr" name="logo" id="0x010102be" /> + <public type="attr" name="xlargeScreens" id="0x010102bf" /> + + <public-padding type="attr" name="kraken_resource_pad" end="0x01010300" /> + <public-padding type="id" name="kraken_resource_pad" end="0x01020040" /> + <public-padding type="anim" name="kraken_resource_pad" end="0x010a0020" /> + <public-padding type="drawable" name="kraken_resource_pad" end="0x01080100" /> + <public-padding type="style" name="kraken_resource_pad" end="0x01030090" /> + <public-padding type="string" name="kraken_resource_pad" end="0x01040020" /> + <public-padding type="integer" name="kraken_resource_pad" end="0x010e0010" /> + <public-padding type="layout" name="kraken_resource_pad" end="0x01090020" /> + <public-padding type="dimen" name="kraken_resource_pad" end="0x01050010" /> + <public-padding type="color" name="kraken_resource_pad" end="0x01060020" /> + <public-padding type="array" name="kraken_resource_pad" end="0x01070010" /> + </resources> diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml index c318577..5480993 100644 --- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml +++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml @@ -24,17 +24,19 @@ <application> <uses-library android:name="android.test.runner" /> <activity android:name="ConnectivityManagerTestActivity" - android:label="CMTest"> + android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.TEST" /> + <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <!-- This declares that this app uses the instrumentation test runner targeting - the package of browserpowertest. To run the tests use the command: - "adb shell am instrument -w com.android.connectivitymanagertest/.ConnectivityManagerTestRunner" + the package of connectivitymanagertest. To run the tests use the command: + "adb shell am instrument -e ssid <SSID> -w + com.android.connectivitymanagertest/.ConnectivityManagerTestRunner", + the access point <SSID> should be an open AP. --> <instrumentation android:name=".ConnectivityManagerTestRunner" android:targetPackage="com.android.connectivitymanagertest" diff --git a/core/tests/ConnectivityManagerTest/res/values/strings.xml b/core/tests/ConnectivityManagerTest/res/values/strings.xml new file mode 100644 index 0000000..fb6e82f --- /dev/null +++ b/core/tests/ConnectivityManagerTest/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">ConnectivityManagerTest</string> +</resources> diff --git a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java b/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java index 004a197..2de0464 100644 --- a/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java +++ b/core/tests/coretests/src/android/pim/vcard/VCardExporterTests.java @@ -275,6 +275,16 @@ public class VCardExporterTests extends VCardTestsBase { testPhoneBasicCommon(V30); } + public void testPhoneRefrainFormatting() { + mVerifier.initForExportTest(V21 | VCardConfig.FLAG_REFRAIN_PHONE_NUMBER_FORMATTING); + mVerifier.addInputEntry().addContentValues(Phone.CONTENT_ITEM_TYPE) + .put(Phone.NUMBER, "1234567890(abcdefghijklmnopqrstuvwxyz)") + .put(Phone.TYPE, Phone.TYPE_HOME); + mVerifier.addPropertyNodesVerifierElemWithEmptyName() + .addExpectedNode("TEL", "1234567890(abcdefghijklmnopqrstuvwxyz)", + new TypeSet("HOME")); + } + /** * Tests that vCard composer emits corresponding type param which we expect. */ |