diff options
104 files changed, 3479 insertions, 948 deletions
diff --git a/api/current.xml b/api/current.xml index 6121c43..1713533 100644 --- a/api/current.xml +++ b/api/current.xml @@ -10659,6 +10659,17 @@ visibility="public" > </field> +<field name="screen_background_light_transparent" + type="int" + transient="false" + volatile="false" + value="17301674" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="spinner_background" type="int" transient="false" @@ -12714,6 +12725,17 @@ visibility="public" > </field> +<field name="Theme_Light_WallpaperSettings" + type="int" + transient="false" + volatile="false" + value="16973922" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Theme_NoDisplay" type="int" transient="false" @@ -12802,6 +12824,17 @@ visibility="public" > </field> +<field name="Theme_WallpaperSettings" + type="int" + transient="false" + volatile="false" + value="16973921" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Theme_Wallpaper_NoTitleBar" type="int" transient="false" @@ -35145,6 +35178,17 @@ visibility="public" > </field> +<field name="ACTION_DOCK_EVENT" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.action.DOCK_EVENT"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="ACTION_EDIT" type="java.lang.String" transient="false" @@ -35860,6 +35904,17 @@ visibility="public" > </field> +<field name="CATEGORY_CAR_DOCK" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.category.CAR_DOCK"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="CATEGORY_DEFAULT" type="java.lang.String" transient="false" @@ -35871,6 +35926,17 @@ visibility="public" > </field> +<field name="CATEGORY_DESK_DOCK" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.category.DESK_DOCK"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="CATEGORY_DEVELOPMENT_PREFERENCE" type="java.lang.String" transient="false" @@ -36090,6 +36156,50 @@ visibility="public" > </field> +<field name="EXTRA_DOCK_STATE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.intent.extra.DOCK_STATE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_DOCK_STATE_CAR" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_DOCK_STATE_DESK" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="EXTRA_DOCK_STATE_UNDOCKED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EXTRA_DONT_KILL_APP" type="java.lang.String" transient="false" @@ -43753,6 +43863,39 @@ visibility="public" > </field> +<field name="NAVIGATIONHIDDEN_NO" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NAVIGATIONHIDDEN_UNDEFINED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="NAVIGATIONHIDDEN_YES" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="NAVIGATION_DPAD" type="int" transient="false" @@ -44075,6 +44218,16 @@ visibility="public" > </field> +<field name="navigationHidden" + type="int" + transient="false" + volatile="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="orientation" type="int" transient="false" @@ -66923,6 +67076,17 @@ <parameter name="cb" type="android.hardware.Camera.AutoFocusCallback"> </parameter> </method> +<method name="cancelAutoFocus" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="true" + deprecated="not deprecated" + visibility="public" +> +</method> <method name="getParameters" return="android.hardware.Camera.Parameters" abstract="false" @@ -77281,6 +77445,387 @@ </parameter> </method> </interface> +<class name="ExifInterface" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="ExifInterface" + type="android.media.ExifInterface" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="filename" type="java.lang.String"> +</parameter> +<exception name="IOException" type="java.io.IOException"> +</exception> +</constructor> +<method name="getAttribute" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="tag" type="java.lang.String"> +</parameter> +</method> +<method name="getDateTime" + return="long" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getLatLong" + return="float[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getOrientationString" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getThumbnail" + return="byte[]" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="getWhiteBalanceString" + return="java.lang.String" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="hasThumbnail" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="saveAttributes" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<exception name="IOException" type="java.io.IOException"> +</exception> +</method> +<method name="setAttribute" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="tag" type="java.lang.String"> +</parameter> +<parameter name="value" type="java.lang.String"> +</parameter> +</method> +<field name="ORIENTATION_FLIP_HORIZONTAL" + type="int" + transient="false" + volatile="false" + value="2" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_FLIP_VERTICAL" + type="int" + transient="false" + volatile="false" + value="4" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_NORMAL" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_ROTATE_180" + type="int" + transient="false" + volatile="false" + value="3" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_ROTATE_270" + type="int" + transient="false" + volatile="false" + value="8" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_ROTATE_90" + type="int" + transient="false" + volatile="false" + value="6" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_TRANSPOSE" + type="int" + transient="false" + volatile="false" + value="5" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_TRANSVERSE" + type="int" + transient="false" + volatile="false" + value="7" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="ORIENTATION_UNDEFINED" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_DATETIME" + type="java.lang.String" + transient="false" + volatile="false" + value=""DateTime"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_FLASH" + type="java.lang.String" + transient="false" + volatile="false" + value=""Flash"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_GPS_LATITUDE" + type="java.lang.String" + transient="false" + volatile="false" + value=""GPSLatitude"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_GPS_LATITUDE_REF" + type="java.lang.String" + transient="false" + volatile="false" + value=""GPSLatitudeRef"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_GPS_LONGITUDE" + type="java.lang.String" + transient="false" + volatile="false" + value=""GPSLongitude"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_GPS_LONGITUDE_REF" + type="java.lang.String" + transient="false" + volatile="false" + value=""GPSLongitudeRef"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_IMAGE_LENGTH" + type="java.lang.String" + transient="false" + volatile="false" + value=""ImageLength"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_IMAGE_WIDTH" + type="java.lang.String" + transient="false" + volatile="false" + value=""ImageWidth"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_MAKE" + type="java.lang.String" + transient="false" + volatile="false" + value=""Make"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_MODEL" + type="java.lang.String" + transient="false" + volatile="false" + value=""Model"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_ORIENTATION" + type="java.lang.String" + transient="false" + volatile="false" + value=""Orientation"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="TAG_WHITE_BALANCE" + type="java.lang.String" + transient="false" + volatile="false" + value=""WhiteBalance"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="WHITEBALANCE_AUTO" + type="int" + transient="false" + volatile="false" + value="0" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="WHITEBALANCE_MANUAL" + type="int" + transient="false" + volatile="false" + value="1" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> <class name="FaceDetector" extends="java.lang.Object" abstract="false" @@ -117496,6 +118041,37 @@ </implements> </interface> </package> +<package name="android.service.wallpaper" +> +<class name="WallpaperSettingsActivity" + extends="android.preference.PreferenceActivity" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<constructor name="WallpaperSettingsActivity" + type="android.service.wallpaper.WallpaperSettingsActivity" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<field name="EXTRA_PREVIEW_MODE" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.service.wallpaper.PREVIEW_MODE"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> +</package> <package name="android.speech" > <class name="RecognizerIntent" @@ -159296,6 +159872,17 @@ visibility="public" > </field> +<field name="FLAG_TURN_SCREEN_ON" + type="int" + transient="false" + volatile="false" + value="2097152" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="FLAG_WATCH_OUTSIDE_TOUCH" type="int" transient="false" diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index c13893a..0bdcc1d 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -714,11 +714,14 @@ public class AccountManagerService extends IAccountManager.Stub { Notification n = new Notification(android.R.drawable.stat_sys_warning, null, 0 /* when */); - final CharSequence subtitleFormatString = - mContext.getText(R.string.permission_request_notification_subtitle); + final String titleAndSubtitle = + mContext.getString(R.string.permission_request_notification_with_subtitle, + account.name); + final int index = titleAndSubtitle.indexOf('\n'); + final String title = titleAndSubtitle.substring(0, index); + final String subtitle = titleAndSubtitle.substring(index + 1); n.setLatestEventInfo(mContext, - mContext.getText(R.string.permission_request_notification_title), - String.format(subtitleFormatString.toString(), account.name), + title, subtitle, PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)); ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE)) .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n); diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java index 8f7e8ca..4f9531e 100644 --- a/core/java/android/app/SuggestionsAdapter.java +++ b/core/java/android/app/SuggestionsAdapter.java @@ -20,14 +20,15 @@ import android.app.SearchManager.DialogCursorProtocol; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; +import android.content.ContentResolver.OpenResourceIdResult; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.database.Cursor; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.DrawableContainer; import android.graphics.drawable.StateListDrawable; import android.net.Uri; import android.os.Bundle; @@ -38,14 +39,15 @@ import android.util.Log; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; +import android.widget.Filter; import android.widget.ImageView; import android.widget.ResourceCursorAdapter; import android.widget.TextView; -import android.widget.Filter; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.List; import java.util.WeakHashMap; /** @@ -580,14 +582,26 @@ class SuggestionsAdapter extends ResourceCursorAdapter { // Not cached, try using it as a plain resource ID in the provider's context. int resourceId = Integer.parseInt(drawableId); drawable = mProviderContext.getResources().getDrawable(resourceId); - if (DBG) Log.d(LOG_TAG, "Found icon by resource ID: " + drawableId); } catch (NumberFormatException nfe) { - // The id was not an integer resource id. - // Let the ContentResolver handle content, android.resource and file URIs. + // The id was not an integer resource id, use it as a URI try { Uri uri = Uri.parse(drawableId); - InputStream stream = mProviderContext.getContentResolver().openInputStream(uri); - if (stream != null) { + String scheme = uri.getScheme(); + if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) { + // Load drawables through Resources, to get the source density information + OpenResourceIdResult r = + mProviderContext.getContentResolver().getResourceId(uri); + try { + drawable = r.r.getDrawable(r.id); + } catch (Resources.NotFoundException ex) { + throw new FileNotFoundException("Resource does not exist: " + uri); + } + } else { + // Let the ContentResolver handle content and file URIs. + InputStream stream = mProviderContext.getContentResolver().openInputStream(uri); + if (stream == null) { + throw new FileNotFoundException("Failed to open " + uri); + } try { drawable = Drawable.createFromStream(stream, null); } finally { @@ -598,22 +612,25 @@ class SuggestionsAdapter extends ResourceCursorAdapter { } } } - if (DBG) Log.d(LOG_TAG, "Opened icon input stream: " + drawableId); } catch (FileNotFoundException fnfe) { - if (DBG) Log.d(LOG_TAG, "Icon stream not found: " + drawableId); + Log.w(LOG_TAG, "Icon not found: " + drawableId + ", " + fnfe.getMessage()); // drawable = null; } - - // If we got a drawable for this resource id, then stick it in the - // map so we don't do this lookup again. - if (drawable != null) { - mOutsideDrawablesCache.put(drawableId, drawable.getConstantState()); - } } catch (Resources.NotFoundException nfe) { - if (DBG) Log.d(LOG_TAG, "Icon resource not found: " + drawableId); + Log.w(LOG_TAG, "Icon resource not found: " + drawableId); // drawable = null; } + if (drawable == null) { + if (DBG) Log.d(LOG_TAG, "Didn't find icon: " + drawableId); + } else { + if (DBG) { + Log.d(LOG_TAG, "Found icon: " + drawableId); + } + // Cache it so we don't do this lookup again + mOutsideDrawablesCache.put(drawableId, drawable.getConstantState()); + } + return drawable; } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 88a4d02..307899a 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -527,12 +527,22 @@ public abstract class ContentResolver { } } - class OpenResourceIdResult { - Resources r; - int id; + /** + * A resource identified by the {@link Resources} that contains it, and a resource id. + * + * @hide + */ + public class OpenResourceIdResult { + public Resources r; + public int id; } - - OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { + + /** + * Resolves an android.resource URI to a {@link Resources} and a resource id. + * + * @hide + */ + public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { String authority = uri.getAuthority(); Resources r; if (TextUtils.isEmpty(authority)) { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c053ace..fc977c8 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -529,6 +529,8 @@ import java.util.Set; * <li> {@link #CATEGORY_HOME} * <li> {@link #CATEGORY_PREFERENCE} * <li> {@link #CATEGORY_TEST} + * <li> {@link #CATEGORY_CAR_DOCK} + * <li> {@link #CATEGORY_DESK_DOCK} * </ul> * * <h3>Standard Extra Data</h3> @@ -1861,12 +1863,29 @@ public class Intent implements Parcelable { */ public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST = "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST"; + /** + * An activity to run when device is inserted into a car dock. + * Used with {@link #ACTION_MAIN} to launch an activity. + * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead. + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK"; + /** + * An activity to run when device is inserted into a car dock. + * Used with {@link #ACTION_MAIN} to launch an activity. + * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead. + */ + @SdkConstant(SdkConstantType.INTENT_CATEGORY) + public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK"; /** * Broadcast Action: The phone was docked or undocked. Includes the extra * field {@link #EXTRA_DOCK_STATE}, containing the current dock state. - * @hide + * This is intended for monitoring the current dock state. + * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK} + * or {@link #CATEGORY_DESK_DOCK} instead. */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT"; // --------------------------------------------------------------------- @@ -2005,28 +2024,24 @@ public class Intent implements Parcelable { * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED}, * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}. - * @hide */ public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE"; /** * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE} * to represent that the phone is not in any dock. - * @hide */ public static final int EXTRA_DOCK_STATE_UNDOCKED = 0; /** * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE} * to represent that the phone is in a desk dock. - * @hide */ public static final int EXTRA_DOCK_STATE_DESK = 1; /** * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE} * to represent that the phone is in a car dock. - * @hide */ public static final int EXTRA_DOCK_STATE_CAR = 2; diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 27783ef..1ad13c5 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -217,7 +217,9 @@ public class ActivityInfo extends ComponentInfo public static final int CONFIG_KEYBOARD = 0x0010; /** * Bit in {@link #configChanges} that indicates that the activity - * can itself handle changes to the keyboard being hidden/exposed. + * can itself handle changes to the keyboard or navigation being hidden/exposed. + * Note that inspite of the name, this applies to the changes to any + * hidden states: keyboard or navigation. * Set from the {@link android.R.attr#configChanges} attribute. */ public static final int CONFIG_KEYBOARD_HIDDEN = 0x0020; diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index cbf8410..1fe34b5 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -138,6 +138,18 @@ public final class Configuration implements Parcelable, Comparable<Configuration */ public int navigation; + public static final int NAVIGATIONHIDDEN_UNDEFINED = 0; + public static final int NAVIGATIONHIDDEN_NO = 1; + public static final int NAVIGATIONHIDDEN_YES = 2; + + /** + * A flag indicating whether any 5-way or DPAD navigation available. + * This will be set on a device with a mechanism to hide the navigation + * controls from the user, when that mechanism is closed. One of: + * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}. + */ + public int navigationHidden; + public static final int ORIENTATION_UNDEFINED = 0; public static final int ORIENTATION_PORTRAIT = 1; public static final int ORIENTATION_LANDSCAPE = 2; @@ -174,6 +186,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration keyboardHidden = o.keyboardHidden; hardKeyboardHidden = o.hardKeyboardHidden; navigation = o.navigation; + navigationHidden = o.navigationHidden; orientation = o.orientation; screenLayout = o.screenLayout; } @@ -198,6 +211,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration sb.append(hardKeyboardHidden); sb.append(" nav="); sb.append(navigation); + sb.append("/"); + sb.append(navigationHidden); sb.append(" orien="); sb.append(orientation); sb.append(" layout="); @@ -219,6 +234,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration keyboardHidden = KEYBOARDHIDDEN_UNDEFINED; hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED; navigation = NAVIGATION_UNDEFINED; + navigationHidden = NAVIGATIONHIDDEN_UNDEFINED; orientation = ORIENTATION_UNDEFINED; screenLayout = SCREENLAYOUT_SIZE_UNDEFINED; } @@ -286,6 +302,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration changed |= ActivityInfo.CONFIG_NAVIGATION; navigation = delta.navigation; } + if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED + && navigationHidden != delta.navigationHidden) { + changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; + navigationHidden = delta.navigationHidden; + } if (delta.orientation != ORIENTATION_UNDEFINED && orientation != delta.orientation) { changed |= ActivityInfo.CONFIG_ORIENTATION; @@ -360,6 +381,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration && navigation != delta.navigation) { changed |= ActivityInfo.CONFIG_NAVIGATION; } + if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED + && navigationHidden != delta.navigationHidden) { + changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN; + } if (delta.orientation != ORIENTATION_UNDEFINED && orientation != delta.orientation) { changed |= ActivityInfo.CONFIG_ORIENTATION; @@ -416,6 +441,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration dest.writeInt(keyboardHidden); dest.writeInt(hardKeyboardHidden); dest.writeInt(navigation); + dest.writeInt(navigationHidden); dest.writeInt(orientation); dest.writeInt(screenLayout); } @@ -448,6 +474,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration keyboardHidden = source.readInt(); hardKeyboardHidden = source.readInt(); navigation = source.readInt(); + navigationHidden = source.readInt(); orientation = source.readInt(); screenLayout = source.readInt(); } @@ -478,6 +505,8 @@ public final class Configuration implements Parcelable, Comparable<Configuration if (n != 0) return n; n = this.navigation - that.navigation; if (n != 0) return n; + n = this.navigationHidden - that.navigationHidden; + if (n != 0) return n; n = this.orientation - that.orientation; if (n != 0) return n; n = this.screenLayout - that.screenLayout; @@ -503,6 +532,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration return ((int)this.fontScale) + this.mcc + this.mnc + this.locale.hashCode() + this.touchscreen + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden - + this.navigation + this.orientation + this.screenLayout; + + this.navigation + this.navigationHidden + + this.orientation + this.screenLayout; } } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 9991600..13effe0 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -38,12 +38,12 @@ import android.os.Message; * <p>There is no default constructor for this class. Use {@link #open()} to * get a Camera object.</p> * - * <p>In order to use the device camera, you must declare the - * {@link android.Manifest.permission#CAMERA} permission in your Android + * <p>In order to use the device camera, you must declare the + * {@link android.Manifest.permission#CAMERA} permission in your Android * Manifest. Also be sure to include the * <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a> - * manifest element in order to declare camera features used by your application. - * For example, if you use the camera and auto-focus feature, your Manifest + * manifest element in order to declare camera features used by your application. + * For example, if you use the camera and auto-focus feature, your Manifest * should include the following:</p> * <pre> <uses-permission android:name="android.permission.CAMERA" /> * <uses-feature android:name="android.hardware.camera" /> @@ -52,7 +52,7 @@ import android.os.Message; * <p class="caution"><strong>Caution:</strong> Different Android-powered devices * may have different hardware specifications, such as megapixel ratings and * auto-focus capabilities. In order for your application to be compatible with - * more devices, you should not make assumptions about the device camera + * more devices, you should not make assumptions about the device camera * specifications.</p> */ public class Camera { @@ -197,7 +197,7 @@ public class Camera { * The callback that delivers the preview frames. * * @param data The contents of the preview frame in the format defined - * by {@link android.graphics.PixelFormat}, which can be queried + * by {@link android.graphics.PixelFormat}, which can be queried * with {@link android.hardware.Camera.Parameters#getPreviewFormat()}. * If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)} * is never called, the default will be the YCbCr_420_SP @@ -340,11 +340,11 @@ public class Camera { /** * Handles the callback for the camera auto focus. - * <p>Devices that do not support auto-focus will receive a "fake" - * callback to this interface. If your application needs auto-focus and + * <p>Devices that do not support auto-focus will receive a "fake" + * callback to this interface. If your application needs auto-focus and * should not be installed on devices <em>without</em> auto-focus, you must * declare that your app uses the - * {@code android.hardware.camera.autofocus} feature, in the + * {@code android.hardware.camera.autofocus} feature, in the * <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a> * manifest element.</p> */ @@ -368,11 +368,11 @@ public class Camera { * AutoFocusCallback#onAutoFocus(boolean, Camera)} callback will be called * immediately. * <p>If your application should not be installed - * on devices without auto-focus, you must declare that your application - * uses auto-focus with the + * on devices without auto-focus, you must declare that your application + * uses auto-focus with the * <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><uses-feature></a> * manifest element.</p> - * + * * @param cb the callback to run */ public final void autoFocus(AutoFocusCallback cb) @@ -387,7 +387,6 @@ public class Camera { * this function will cancel it. Whether the auto-focus is in progress * or not, this function will return the focus position to the default. * If the camera does not support auto-focus, this is a no-op. - * @hide */ public final void cancelAutoFocus() { @@ -917,11 +916,11 @@ public class Camera { } /** - * Sets the image format for preview pictures. + * Sets the image format for preview pictures. * <p>If this is never called, the default format will be * {@link android.graphics.PixelFormat#YCbCr_420_SP}, which * uses the NV21 encoding format.</p> - * + * * @param pixel_format the desired preview picture format, defined * by one of the {@link android.graphics.PixelFormat} constants. * (E.g., <var>PixelFormat.YCbCr_420_SP</var> (default), @@ -942,8 +941,8 @@ public class Camera { /** * Returns the image format for preview pictures got from * {@link PreviewCallback}. - * - * @return the {@link android.graphics.PixelFormat} int representing + * + * @return the {@link android.graphics.PixelFormat} int representing * the preview picture format. */ public int getPreviewFormat() { diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java index 0064bf2..06b0636 100644 --- a/core/java/android/pim/vcard/ContactStruct.java +++ b/core/java/android/pim/vcard/ContactStruct.java @@ -15,6 +15,7 @@ */ package android.pim.vcard; +import android.accounts.Account; import android.content.ContentProviderOperation; import android.content.ContentResolver; import android.content.ContentValues; @@ -416,7 +417,8 @@ public class ContactStruct { private List<String> mWebsiteList; private final int mVCardType; - + private final Account mAccount; + // Each Column of four properties has ISPRIMARY field // (See android.provider.Contacts) // If false even after the parsing loop, we choose the first entry as a "primary" @@ -429,9 +431,14 @@ public class ContactStruct { public ContactStruct() { this(VCardConfig.VCARD_TYPE_V21_GENERIC); } - + public ContactStruct(int vcardType) { + this(vcardType, null); + } + + public ContactStruct(int vcardType, Account account) { mVCardType = vcardType; + mAccount = account; } /** @@ -1021,7 +1028,12 @@ public class ContactStruct { new ArrayList<ContentProviderOperation>(); ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI); - builder.withValues(new ContentValues()); + if (mAccount != null) { + builder.withValue(RawContacts.ACCOUNT_NAME, mAccount.name); + builder.withValue(RawContacts.ACCOUNT_TYPE, mAccount.type); + } else { + builder.withValues(new ContentValues()); + } operationList.add(builder.build()); { @@ -1183,7 +1195,7 @@ public class ContactStruct { builder.withValue(Miscellaneous.BIRTHDAY, mBirthday); operationList.add(builder.build()); } - + try { resolver.applyBatch(ContactsContract.AUTHORITY, operationList); } catch (RemoteException e) { diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardDataBuilder.java index fd165e9..d2026d0 100644 --- a/core/java/android/pim/vcard/VCardDataBuilder.java +++ b/core/java/android/pim/vcard/VCardDataBuilder.java @@ -15,6 +15,7 @@ */ package android.pim.vcard; +import android.accounts.Account; import android.util.CharsetUtils; import android.util.Log; @@ -59,7 +60,8 @@ public class VCardDataBuilder implements VCardBuilder { private String mTargetCharset; private boolean mStrictLineBreakParsing; - private int mVCardType; + final private int mVCardType; + final private Account mAccount; // Just for testing. private long mTimePushIntoContentResolver; @@ -67,21 +69,22 @@ public class VCardDataBuilder implements VCardBuilder { private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>(); public VCardDataBuilder() { - this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC); + this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC, null); } /** * @hide */ public VCardDataBuilder(int vcardType) { - this(null, null, false, vcardType); + this(null, null, false, vcardType, null); } /** * @hide */ - public VCardDataBuilder(String charset, boolean strictLineBreakParsing, int vcardType) { - this(null, charset, strictLineBreakParsing, vcardType); + public VCardDataBuilder(String charset, + boolean strictLineBreakParsing, int vcardType, Account account) { + this(null, charset, strictLineBreakParsing, vcardType, account); } /** @@ -90,7 +93,8 @@ public class VCardDataBuilder implements VCardBuilder { public VCardDataBuilder(String sourceCharset, String targetCharset, boolean strictLineBreakParsing, - int vcardType) { + int vcardType, + Account account) { if (sourceCharset != null) { mSourceCharset = sourceCharset; } else { @@ -103,6 +107,7 @@ public class VCardDataBuilder implements VCardBuilder { } mStrictLineBreakParsing = strictLineBreakParsing; mVCardType = vcardType; + mAccount = account; } public void addEntryHandler(EntryHandler entryHandler) { @@ -136,7 +141,7 @@ public class VCardDataBuilder implements VCardBuilder { Log.e(LOG_TAG, "This is not VCARD!"); } - mCurrentContactStruct = new ContactStruct(mVCardType); + mCurrentContactStruct = new ContactStruct(mVCardType, mAccount); } public void endRecord() { diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java index 666efae..cc48aeb 100644 --- a/core/java/android/preference/DialogPreference.java +++ b/core/java/android/preference/DialogPreference.java @@ -31,6 +31,9 @@ import android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; import android.widget.TextView; /** @@ -297,10 +300,32 @@ public abstract class DialogPreference extends Preference implements if (state != null) { dialog.onRestoreInstanceState(state); } + if (needInputMethod()) { + requestInputMethod(dialog); + } dialog.setOnDismissListener(this); dialog.show(); } - + + /** + * Returns whether the preference needs to display a soft input method when the dialog + * is displayed. Default is false. Subclasses should override this method if they need + * the soft input method brought up automatically. + * @hide + */ + protected boolean needInputMethod() { + return false; + } + + /** + * Sets the required flags on the dialog window to enable input method window to show up. + */ + private void requestInputMethod(Dialog dialog) { + Window window = dialog.getWindow(); + window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + /** * Creates the content view for the dialog (if a custom content view is * required). By default, it inflates the dialog layout resource if it is diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java index a12704f..84ee950 100644 --- a/core/java/android/preference/EditTextPreference.java +++ b/core/java/android/preference/EditTextPreference.java @@ -169,6 +169,13 @@ public class EditTextPreference extends DialogPreference { return mEditText; } + /** @hide */ + @Override + protected boolean needInputMethod() { + // We want the input method to show, if possible, when dialog is displayed + return true; + } + @Override protected Parcelable onSaveInstanceState() { final Parcelable superState = super.onSaveInstanceState(); diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java index 181a529..667ec5a 100644 --- a/core/java/android/provider/Contacts.java +++ b/core/java/android/provider/Contacts.java @@ -542,7 +542,7 @@ public class Contacts { } return new ByteArrayInputStream(data); } finally { - cursor.close(); + if (cursor != null) cursor.close(); } } diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index b0ac7f4..afa0a7c 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -1529,7 +1529,7 @@ public final class ContactsContract { * called on a raw contact, it is marked for deletion and removed from its * aggregate contact. The sync adaptor deletes the raw contact on the server and * then calls ContactResolver.delete once more, this time setting the the - * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize + * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize * the data removal. * <P>Type: INTEGER</P> */ @@ -1686,6 +1686,13 @@ public final class ContactsContract { public static final String UNGROUPED_VISIBLE = "ungrouped_visible"; /** + * Read-only flag indicating if this {@link #SHOULD_SYNC} or any + * {@link Groups#SHOULD_SYNC} under this account have been marked as + * unsynced. + */ + public static final String ANY_UNSYNCED = "any_unsynced"; + + /** * Read-only count of {@link Contacts} from a specific source that have * no {@link CommonDataKinds.GroupMembership} entries. * <p> diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0bbd1fc..6d03095 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2758,11 +2758,19 @@ public final class Settings { /** * Controls whether Gmail will discard uphill operations that repeatedly fail. Value must be - * an integer where non-zero means true. Defaults to 1. + * an integer where non-zero means true. Defaults to 1. This flag controls Donut devices. */ public static final String GMAIL_DISCARD_ERROR_UPHILL_OP = "gmail_discard_error_uphill_op"; /** + * Controls whether Gmail will discard uphill operations that repeatedly fail. Value must be + * an integer where non-zero means true. Defaults to 1. This flag controls Eclair and + * future devices. + */ + public static final String GMAIL_DISCARD_ERROR_UPHILL_OP_NEW = + "gmail_discard_error_uphill_op_new"; + + /** * Controls how many attempts Gmail will try to upload an uphill operations before it * abandons the operation. Defaults to 20. */ diff --git a/core/java/android/service/wallpaper/WallpaperSettingsActivity.java b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java new file mode 100644 index 0000000..501947d --- /dev/null +++ b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package android.service.wallpaper; + +import android.content.res.Resources; +import android.os.Bundle; +import android.preference.PreferenceActivity; + +/** + * Base class for activities that will be used to configure the settings of + * a wallpaper. You should derive from this class to allow it to select the + * proper theme of the activity depending on how it is being used. + */ +public class WallpaperSettingsActivity extends PreferenceActivity { + /** + * This boolean extra in the launch intent indicates that the settings + * are being used while the wallpaper is in preview mode. + */ + final public static String EXTRA_PREVIEW_MODE + = "android.service.wallpaper.PREVIEW_MODE"; + + @Override + protected void onCreate(Bundle icicle) { + if (false) { + Resources.Theme theme = getTheme(); + if (getIntent().getBooleanExtra(EXTRA_PREVIEW_MODE, false)) { + theme.applyStyle(com.android.internal.R.style.PreviewWallpaperSettings, true); + } else { + theme.applyStyle(com.android.internal.R.style.ActiveWallpaperSettings, true); + } + } + super.onCreate(icicle); + } +} diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 94acd3f..e5985c1 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -458,11 +458,12 @@ public abstract class LayoutInflater { public final View createView(String name, String prefix, AttributeSet attrs) throws ClassNotFoundException, InflateException { Constructor constructor = sConstructorMap.get(name); + Class clazz = null; try { if (constructor == null) { // Class not found in the cache, see if it's real, and try to add it - Class clazz = mContext.getClassLoader().loadClass( + clazz = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name); if (mFilter != null && clazz != null) { @@ -480,7 +481,7 @@ public abstract class LayoutInflater { Boolean allowedState = mFilterMap.get(name); if (allowedState == null) { // New class -- remember whether it is allowed - Class clazz = mContext.getClassLoader().loadClass( + clazz = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name); boolean allowed = clazz != null && mFilter.onLoadClass(clazz); @@ -511,7 +512,7 @@ public abstract class LayoutInflater { } catch (Exception e) { InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " - + (constructor == null ? "<unknown>" : constructor.getClass().getName())); + + (clazz == null ? "<unknown>" : clazz.getName())); ie.initCause(e); throw ie; } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 8c12656..f67c4aa 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -500,6 +500,12 @@ public interface WindowManager extends ViewManager { */ public static final int FLAG_SHOW_WALLPAPER = 0x00100000; + /** Window flag: when set as a window is being added or made + * visible, once the window has been shown then the system will + * poke the power manager's user activity (as if the user had woken + * up the device) to turn the screen on. */ + public static final int FLAG_TURN_SCREEN_ON = 0x00200000; + /** Window flag: special flag to limit the size of the window to be * original size ([320x480] x density). Used to create window for applications * running under compatibility mode. diff --git a/core/java/android/webkit/PluginStub.java b/core/java/android/webkit/PluginStub.java index cbb36aa..3887d44 100644 --- a/core/java/android/webkit/PluginStub.java +++ b/core/java/android/webkit/PluginStub.java @@ -29,7 +29,7 @@ public interface PluginStub { /** * Return a custom embedded view to draw the plugin. - * @param npp The native NPP instance. + * @param NPP The native NPP instance. * @param context The current application's Context. * @return A custom View that will be managed by WebView. */ @@ -39,7 +39,7 @@ public interface PluginStub { * Return a custom full-screen view to be displayed when the user requests * a plugin display as full-screen. Note that the application may choose not * to display this View as completely full-screen. - * @param npp The native NPP instance. + * @param NPP The native NPP instance. * @param context The current application's Context. * @return A custom View that will be managed by the application. */ diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java index 95b3a12..a175be0 100644 --- a/core/java/android/webkit/WebTextView.java +++ b/core/java/android/webkit/WebTextView.java @@ -38,6 +38,7 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; @@ -430,18 +431,26 @@ import java.util.ArrayList; mGotTouchDown = true; break; case MotionEvent.ACTION_MOVE: + int slop = ViewConfiguration.get(mContext).getScaledTouchSlop(); Spannable buffer = getText(); int initialScrollX = Touch.getInitialScrollX(this, buffer); int initialScrollY = Touch.getInitialScrollY(this, buffer); super.onTouchEvent(event); - if (mScrollX != initialScrollX - || mScrollY != initialScrollY) { + if (Math.abs(mScrollX - initialScrollX) > slop + || Math.abs(mScrollY - initialScrollY) > slop) { if (mWebView != null) { mWebView.scrollFocusedTextInput(mScrollX, mScrollY); } mScrolled = true; return true; } + if (Math.abs((int) event.getX() - mDragStartX) < slop + && Math.abs((int) event.getY() - mDragStartY) < slop) { + // If the user has not scrolled further than slop, we should not + // send the drag. Instead, do nothing, and when the user lifts + // their finger, we will change the selection. + return true; + } if (mWebView != null) { // Only want to set the initial state once. if (!mDragSent) { diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 081f67a..abbbc00 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -420,6 +420,7 @@ public class WebView extends AbsoluteLayout private static final int STD_SPEED = 480; // pixels per second // time for the longest scroll animation private static final int MAX_DURATION = 750; // milliseconds + private static final int SLIDE_TITLE_DURATION = 300; // milliseconds private Scroller mScroller; private boolean mWrapContent; @@ -2416,10 +2417,18 @@ public class WebView extends AbsoluteLayout if ((dx | dy) == 0) { return false; } - - if (true && animate) { + // mobile sites prefer to scroll to (0, 1), thus the + 1 below + boolean slideTitle = getVisibleTitleHeight() > 0 + && y <= getTitleHeight() + 1; + if (DebugFlags.WEB_VIEW) { + Log.v(LOGTAG, "pinScrollTo slideTitle=" + slideTitle + + " getVisibleTitleHeight()=" + getVisibleTitleHeight() + + " animationDuration=" + animationDuration + " y=" + y); + } + if (slideTitle || animate) { // Log.d(LOGTAG, "startScroll: " + dx + " " + dy); - + if (slideTitle && animationDuration < SLIDE_TITLE_DURATION) + animationDuration = SLIDE_TITLE_DURATION; mScroller.startScroll(mScrollX, mScrollY, dx, dy, animationDuration > 0 ? animationDuration : computeDuration(dx, dy)); invalidate(); @@ -4791,8 +4800,11 @@ public class WebView extends AbsoluteLayout mMaxZoomScale = restoreState.mMaxScale; } setNewZoomScale(mLastScale, false); - setContentScrollTo(restoreState.mScrollX, - restoreState.mScrollY); + if (getVisibleTitleHeight() == 0 + || restoreState.mScrollY != 0) { + setContentScrollTo(restoreState.mScrollX, + restoreState.mScrollY); + } if (useWideViewport && settings.getLoadWithOverviewMode()) { if (restoreState.mViewScale == 0 diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java index 760b8ff..e55fbb8 100644 --- a/core/java/android/widget/ZoomButtonsController.java +++ b/core/java/android/widget/ZoomButtonsController.java @@ -249,7 +249,7 @@ public class ZoomButtonsController implements View.OnTouchListener { lp.height = LayoutParams.WRAP_CONTENT; lp.width = LayoutParams.FILL_PARENT; lp.type = LayoutParams.TYPE_APPLICATION_PANEL; - lp.format = PixelFormat.TRANSPARENT; + lp.format = PixelFormat.TRANSLUCENT; lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; mContainerLayoutParams = lp; diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java index fe01866..4ec597c 100644 --- a/core/java/com/android/internal/widget/ContactHeaderWidget.java +++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java @@ -42,6 +42,7 @@ import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.CheckBox; +import android.widget.FasttrackBadgeWidget; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; @@ -64,15 +65,13 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList private TextView mDisplayNameView; private TextView mPhoneticNameView; private CheckBox mStarredView; - private ImageView mPhotoView; + private FasttrackBadgeWidget mPhotoView; private ImageView mPresenceView; private TextView mStatusView; private int mNoPhotoResource; private QueryHandler mQueryHandler; - protected long mContactId; protected Uri mContactUri; - protected Uri mStatusUri; protected String[] mExcludeMimes = null; @@ -94,6 +93,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList Contacts.STARRED, Contacts.PHOTO_ID, Contacts.PRESENCE_STATUS, + Contacts._ID, + Contacts.LOOKUP_KEY, }; protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0; //TODO: We need to figure out how we're going to get the phonetic name. @@ -101,6 +102,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList protected static final int HEADER_STARRED_COLUMN_INDEX = 1; protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2; protected static final int HEADER_PRESENCE_STATUS_COLUMN_INDEX = 3; + protected static final int HEADER_CONTACT_ID_COLUMN_INDEX = 4; + protected static final int HEADER_LOOKUP_KEY_COLUMN_INDEX = 5; //Projection used for finding the most recent social status. protected static final String[] SOCIAL_PROJECTION = new String[] { @@ -113,18 +116,29 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList //Projection used for looking up contact id from phone number protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] { PhoneLookup._ID, + PhoneLookup.LOOKUP_KEY, }; protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0; + protected static final int PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1; //Projection used for looking up contact id from email address protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] { RawContacts.CONTACT_ID, + Contacts.LOOKUP_KEY, }; protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0; + protected static final int EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1; + protected static final String[] CONTACT_LOOKUP_PROJECTION = new String[] { + Contacts._ID, + }; + protected static final int CONTACT_LOOKUP_ID_COLUMN_INDEX = 0; private static final int TOKEN_CONTACT_INFO = 0; private static final int TOKEN_SOCIAL = 1; + private static final int TOKEN_PHONE_LOOKUP = 2; + private static final int TOKEN_EMAIL_LOOKUP = 3; + private static final int TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY = 4; public ContactHeaderWidget(Context context) { this(context, null); @@ -151,8 +165,7 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList mStarredView = (CheckBox)findViewById(R.id.star); mStarredView.setOnClickListener(this); - mPhotoView = (ImageView)findViewById(R.id.photo); - mPhotoView.setOnClickListener(this); + mPhotoView = (FasttrackBadgeWidget) findViewById(R.id.photo); mPhotoView.setOnLongClickListener(this); mPresenceView = (ImageView) findViewById(R.id.presence); @@ -217,12 +230,46 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { try{ - if (token == TOKEN_CONTACT_INFO) { - bindContactInfo(cursor); - invalidate(); - } else if (token == TOKEN_SOCIAL) { - bindSocial(cursor); - invalidate(); + switch (token) { + case TOKEN_CONTACT_INFO: { + bindContactInfo(cursor); + invalidate(); + break; + } + case TOKEN_SOCIAL: { + bindSocial(cursor); + invalidate(); + break; + } + case TOKEN_PHONE_LOOKUP: { + if (cursor != null && cursor.moveToFirst()) { + long contactId = cursor.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX); + String lookupKey = cursor.getString( + PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX); + bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey)); + } else { + setDisplayName((String) cookie, null); + } + break; + } + case TOKEN_EMAIL_LOOKUP: { + if (cursor != null && cursor.moveToFirst()) { + long contactId = cursor.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX); + String lookupKey = cursor.getString( + EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX); + bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey)); + } else { + setDisplayName((String) cookie, null); + } + break; + } + case TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY: { + if (cursor != null && cursor.moveToFirst()) { + long contactId = cursor.getLong(CONTACT_LOOKUP_ID_COLUMN_INDEX); + startSocialQuery(ContentUris.withAppendedId( + Activities.CONTENT_CONTACT_STATUS_URI, contactId)); + } + } } } finally { if (cursor != null) { @@ -300,33 +347,31 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList * Convenience method for binding all available data from an existing * contact. * - * @param contactId the contact id of the contact whose info should be displayed. + * @param conatctUri a {Contacts.CONTENT_LOOKUP_URI} style URI. */ - public void bindFromContactId(long contactId) { - mContactId = contactId; - mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId); + public void bindFromContactLookupUri(Uri contactLookupUri) { + mContactUri = contactLookupUri; - bindContactUri(mContactUri); - bindSocialUri(ContentUris.withAppendedId(Activities.CONTENT_CONTACT_STATUS_URI, mContactId)); - } + // Query for the contactId so we can do the social query. + mQueryHandler.startQuery(TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY, null, contactLookupUri, + CONTACT_LOOKUP_PROJECTION, null, null, null); - /** - * Convenience method for binding {@link Contacts} header details from a - * {@link Contacts#CONTENT_URI} reference. - */ - public void bindContactUri(Uri contactUri) { - mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION, - null, null, null); + startContactQuery(contactLookupUri); } /** - * Convenience method for binding {@link Activities} header details from a - * {@link Activities#CONTENT_CONTACT_STATUS_URI}. + * Convenience method for binding all available data from an existing + * contact. + * + * @param conatctUri a {Contacts.CONTENT_URI} style URI. */ - public void bindSocialUri(Uri contactSocial) { - mStatusUri = contactSocial; - mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, null, null, - null); + public void bindFromContactUri(Uri contactUri) { + mContactUri = contactUri; + long contactId = ContentUris.parseId(contactUri); + + startContactQuery(contactUri); + startSocialQuery(ContentUris.withAppendedId( + Activities.CONTENT_CONTACT_STATUS_URI, contactId)); } /** @@ -338,21 +383,9 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList * address, one of them will be chosen to bind to. */ public void bindFromEmail(String emailAddress) { - Cursor c = null; - try { - c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri - .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null); - if (c != null && c.moveToFirst()) { - long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX); - bindFromContactId(contactId); - } else { - setDisplayName(emailAddress, null); - } - } finally { - if (c != null) { - c.close(); - } - } + mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, emailAddress, + Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress)), + EMAIL_LOOKUP_PROJECTION, null, null, null); } /** @@ -364,22 +397,19 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList * number, one of them will be chosen to bind to. */ public void bindFromPhoneNumber(String number) { - Cursor c = null; - try { - c = mContentResolver.query( - Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)), - PHONE_LOOKUP_PROJECTION, null, null, null); - if (c != null && c.moveToFirst()) { - long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX); - bindFromContactId(contactId); - } else { - setDisplayName(number, null); - } - } finally { - if (c != null) { - c.close(); - } - } + mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number, + Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number), + PHONE_LOOKUP_PROJECTION, null, null, null); + } + + private void startSocialQuery(Uri contactSocial) { + mQueryHandler.startQuery(TOKEN_SOCIAL, null, contactSocial, SOCIAL_PROJECTION, null, null, + null); + } + + private void startContactQuery(Uri contactUri) { + mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION, + null, null, null); } /** @@ -390,6 +420,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList // TODO: Bring back phonetic name final String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX); + final long contactId = c.getLong(HEADER_CONTACT_ID_COLUMN_INDEX); + final String lookupKey = c.getString(HEADER_LOOKUP_KEY_COLUMN_INDEX); final String phoneticName = null; this.setDisplayName(displayName, null); @@ -402,6 +434,7 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList photoBitmap = loadPlaceholderPhoto(null); } mPhotoView.setImageBitmap(photoBitmap); + mPhotoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey)); //Set the presence status int presence = c.getInt(HEADER_PRESENCE_STATUS_COLUMN_INDEX); @@ -423,27 +456,11 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList return; } - switch (view.getId()) { - case R.id.star: { - // Toggle "starred" state - final ContentValues values = new ContentValues(1); - values.put(Contacts.STARRED, mStarredView.isChecked()); - mContentResolver.update(mContactUri, values, null, null); - break; - } - case R.id.photo: { - // Photo launches contact detail action - final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri); - final Rect target = getTargetRect(view); - intent.putExtra(Intents.EXTRA_TARGET_RECT, target); - intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL); - if (mExcludeMimes != null) { - // Exclude specific MIME-types when requested - intent.putExtra(Intents.EXTRA_EXCLUDE_MIMES, mExcludeMimes); - } - mContext.startActivity(intent); - break; - } + if (view.getId() == R.id.star) { + // Toggle "starred" state + final ContentValues values = new ContentValues(1); + values.put(Contacts.STARRED, mStarredView.isChecked()); + mContentResolver.update(mContactUri, values, null, null); } } diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java new file mode 100644 index 0000000..aff92b8 --- /dev/null +++ b/core/java/com/android/internal/widget/RotarySelector.java @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.os.Vibrator; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import static android.view.animation.AnimationUtils.currentAnimationTimeMillis; +import com.android.internal.R; + + +/** + * Custom view that presents up to two items that are selectable by rotating a semi-circle from + * left to right, or right to left. Used by incoming call screen, and the lock screen when no + * security pattern is set. + */ +public class RotarySelector extends View { + private static final String LOG_TAG = "RotarySelector"; + private static final boolean DBG = false; + + // Listener for onDialTrigger() callbacks. + private OnDialTriggerListener mOnDialTriggerListener; + + private float mDensity; + + // UI elements + private Drawable mBackground; + private Drawable mDimple; + + private Drawable mLeftHandleIcon; + private Drawable mRightHandleIcon; + + private Drawable mArrowShortLeftAndRight; + private Drawable mArrowLongLeft; // Long arrow starting on the left, pointing clockwise + private Drawable mArrowLongRight; // Long arrow starting on the right, pointing CCW + + // positions of the left and right handle + private int mLeftHandleX; + private int mRightHandleX; + + // current offset of user's dragging + private int mTouchDragOffset = 0; + + // state of the animation used to bring the handle back to its start position when + // the user lets go before triggering an action + private boolean mAnimating = false; + private long mAnimationEndTime; + private int mAnimatingDelta; + private AccelerateInterpolator mInterpolator; + + /** + * True after triggering an action if the user of {@link OnDialTriggerListener} wants to + * freeze the UI (until they transition to another screen). + */ + private boolean mFrozen = false; + + /** + * If the user is currently dragging something. + */ + private int mGrabbedState = NOTHING_GRABBED; + private static final int NOTHING_GRABBED = 0; + private static final int LEFT_HANDLE_GRABBED = 1; + private static final int RIGHT_HANDLE_GRABBED = 2; + + /** + * Whether the user has triggered something (e.g dragging the left handle all the way over to + * the right). + */ + private boolean mTriggered = false; + + // Vibration (haptic feedback) + private Vibrator mVibrator; + private static final long VIBRATE_SHORT = 60; // msec + private static final long VIBRATE_LONG = 100; // msec + + /** + * The drawable for the arrows need to be scrunched this many dips towards the rotary bg below + * it. + */ + private static final int ARROW_SCRUNCH_DIP = 6; + + /** + * How far inset the left and right circles should be + */ + private static final int EDGE_PADDING_DIP = 9; + + /** + * Dimensions of arc in background drawable. + */ + static final int OUTER_ROTARY_RADIUS_DIP = 390; + static final int ROTARY_STROKE_WIDTH_DIP = 83; + private static final int ANIMATION_DURATION_MILLIS = 300; + + private static final boolean DRAW_CENTER_DIMPLE = false; + + public RotarySelector(Context context) { + this(context, null); + } + + + /** + * Constructor used when this widget is created from a layout file. + */ + public RotarySelector(Context context, AttributeSet attrs) { + super(context, attrs); + if (DBG) log("IncomingCallDialWidget constructor..."); + + Resources r = getResources(); + mDensity = r.getDisplayMetrics().density; + if (DBG) log("- Density: " + mDensity); + + // Assets (all are BitmapDrawables). + mBackground = r.getDrawable(R.drawable.jog_dial_bg_cropped); + mDimple = r.getDrawable(R.drawable.jog_dial_dimple); + + mArrowLongLeft = r.getDrawable(R.drawable.jog_dial_arrow_long_left_green); + mArrowLongRight = r.getDrawable(R.drawable.jog_dial_arrow_long_right_red); + mArrowShortLeftAndRight = r.getDrawable(R.drawable.jog_dial_arrow_short_left_and_right); + + // Arrows: + // All arrow assets are the same size (they're the full width of + // the screen) regardless of which arrows are actually visible. + int arrowW = mArrowShortLeftAndRight.getIntrinsicWidth(); + int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight(); + mArrowShortLeftAndRight.setBounds(0, 0, arrowW, arrowH); + mArrowLongLeft.setBounds(0, 0, arrowW, arrowH); + mArrowLongRight.setBounds(0, 0, arrowW, arrowH); + + mInterpolator = new AccelerateInterpolator(); + } + + /** + * Sets the left handle icon to a given resource. + * + * The resource should refer to a Drawable object, or use 0 to remove + * the icon. + * + * @param resId the resource ID. + */ + public void setLeftHandleResource(int resId) { + Drawable d = null; + if (resId != 0) { + d = getResources().getDrawable(resId); + } + setLeftHandleDrawable(d); + } + + /** + * Sets the left handle icon to a given Drawable. + * + * @param d the Drawable to use as the icon, or null to remove the icon. + */ + public void setLeftHandleDrawable(Drawable d) { + mLeftHandleIcon = d; + invalidate(); + } + + /** + * Sets the right handle icon to a given resource. + * + * The resource should refer to a Drawable object, or use 0 to remove + * the icon. + * + * @param resId the resource ID. + */ + public void setRightHandleResource(int resId) { + Drawable d = null; + if (resId != 0) { + d = getResources().getDrawable(resId); + } + setRightHandleDrawable(d); + } + + /** + * Sets the right handle icon to a given Drawable. + * + * @param d the Drawable to use as the icon, or null to remove the icon. + */ + public void setRightHandleDrawable(Drawable d) { + mRightHandleIcon = d; + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int width = MeasureSpec.getSize(widthMeasureSpec); // screen width + + final int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight(); + final int backgroundH = mBackground.getIntrinsicHeight(); + + // by making the height less than arrow + bg, arrow and bg will be scrunched together, + // overlaying somewhat (though on transparent portions of the drawable). + // this works because the arrows are drawn from the top, and the rotary bg is drawn + // from the bottom. + final int arrowScrunch = (int) (ARROW_SCRUNCH_DIP * mDensity); + setMeasuredDimension(width, backgroundH + arrowH - arrowScrunch); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + mLeftHandleX = (int) (EDGE_PADDING_DIP * mDensity) + mDimple.getIntrinsicWidth() / 2; + mRightHandleX = + getWidth() - (int) (EDGE_PADDING_DIP * mDensity) - mDimple.getIntrinsicWidth() / 2; + } + +// private Paint mPaint = new Paint(); + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (DBG) { + log(String.format("onDraw: mAnimating=%s, mTouchDragOffset=%d, mGrabbedState=%d," + + "mFrozen=%s", + mAnimating, mTouchDragOffset, mGrabbedState, mFrozen)); + } + + final int height = getHeight(); + + // update animating state before we draw anything + if (mAnimating && !mFrozen) { + long millisLeft = mAnimationEndTime - currentAnimationTimeMillis(); + if (DBG) log("millisleft for animating: " + millisLeft); + if (millisLeft <= 0) { + reset(); + } else { + float interpolation = mInterpolator.getInterpolation( + (float) millisLeft / ANIMATION_DURATION_MILLIS); + mTouchDragOffset = (int) (mAnimatingDelta * interpolation); + } + } + + + // Background: + final int backgroundW = mBackground.getIntrinsicWidth(); + final int backgroundH = mBackground.getIntrinsicHeight(); + final int backgroundY = height - backgroundH; + if (DBG) log("- Background INTRINSIC: " + backgroundW + " x " + backgroundH); + mBackground.setBounds(0, backgroundY, + backgroundW, backgroundY + backgroundH); + if (DBG) log(" Background BOUNDS: " + mBackground.getBounds()); + mBackground.draw(canvas); + + + // Draw the correct arrow(s) depending on the current state: + Drawable currentArrow; + switch (mGrabbedState) { + case NOTHING_GRABBED: + currentArrow = mArrowShortLeftAndRight; + break; + case LEFT_HANDLE_GRABBED: + currentArrow = mArrowLongLeft; + break; + case RIGHT_HANDLE_GRABBED: + currentArrow = mArrowLongRight; + break; + default: + throw new IllegalStateException("invalid mGrabbedState: " + mGrabbedState); + } + currentArrow.draw(canvas); + + // debug: draw circle that should match the outer arc (good sanity check) +// mPaint.setColor(Color.RED); +// mPaint.setStyle(Paint.Style.STROKE); +// float or = OUTER_ROTARY_RADIUS_DIP * mDensity; +// canvas.drawCircle(getWidth() / 2, or + mBackground.getBounds().top, or, mPaint); + + final int outerRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP); + final int innerRadius = + (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity); + final int bgTop = mBackground.getBounds().top; + { + final int xOffset = mLeftHandleX + mTouchDragOffset; + final int drawableY = getYOnArc( + mBackground, + innerRadius, + outerRadius, + xOffset); + + drawCentered(mDimple, canvas, xOffset, drawableY + bgTop); + drawCentered(mLeftHandleIcon, canvas, xOffset, drawableY + bgTop); + } + + if (DRAW_CENTER_DIMPLE) { + final int xOffset = getWidth() / 2 + mTouchDragOffset; + final int drawableY = getYOnArc( + mBackground, + innerRadius, + outerRadius, + xOffset); + + drawCentered(mDimple, canvas, xOffset, drawableY + bgTop); + } + + { + final int xOffset = mRightHandleX + mTouchDragOffset; + final int drawableY = getYOnArc( + mBackground, + innerRadius, + outerRadius, + xOffset); + + drawCentered(mDimple, canvas, xOffset, drawableY + bgTop); + drawCentered(mRightHandleIcon, canvas, xOffset, drawableY + bgTop); + } + + if (mAnimating) invalidate(); + } + + /** + * Assuming drawable is a bounding box around a piece of an arc drawn by two concentric circles + * (as the background drawable for the rotary widget is), and given an x coordinate along the + * drawable, return the y coordinate of a point on the arc that is between the two concentric + * circles. The resulting y combined with the incoming x is a point along the circle in + * between the two concentric circles. + * + * @param drawable The drawable. + * @param innerRadius The radius of the circle that intersects the drawable at the bottom two + * corders of the drawable (top two corners in terms of drawing coordinates). + * @param outerRadius The radius of the circle who's top most point is the top center of the + * drawable (bottom center in terms of drawing coordinates). + * @param x The distance along the x axis of the desired point. + * @return The y coordinate, in drawing coordinates, that will place (x, y) along the circle + * in between the two concentric circles. + */ + private int getYOnArc(Drawable drawable, int innerRadius, int outerRadius, int x) { + + // the hypotenuse + final int halfWidth = (outerRadius - innerRadius) / 2; + final int middleRadius = innerRadius + halfWidth; + + // the bottom leg of the triangle + final int triangleBottom = (drawable.getIntrinsicWidth() / 2) - x; + + // "Our offense is like the pythagorean theorem: There is no answer!" - Shaquille O'Neal + final int triangleY = + (int) Math.sqrt(middleRadius * middleRadius - triangleBottom * triangleBottom); + + // convert to drawing coordinates: + // middleRadius - triangleY = + // the vertical distance from the outer edge of the circle to the desired point + // from there we add the distance from the top of the drawable to the middle circle + return middleRadius - triangleY + halfWidth; + } + + /** + * Handle touch screen events. + * + * @param event The motion event. + * @return True if the event was handled, false otherwise. + */ + @Override + public boolean onTouchEvent(MotionEvent event) { + if (mAnimating || mFrozen) { + return true; + } + + final int eventX = (int) event.getX(); + final int hitWindow = mDimple.getIntrinsicWidth(); + + final int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + if (DBG) log("touch-down"); + mTriggered = false; + if (mGrabbedState != NOTHING_GRABBED) { + reset(); + invalidate(); + } + if (eventX < mLeftHandleX + hitWindow) { + mTouchDragOffset = eventX - mLeftHandleX; + mGrabbedState = LEFT_HANDLE_GRABBED; + invalidate(); + vibrate(VIBRATE_SHORT); + } else if (eventX > mRightHandleX - hitWindow) { + mTouchDragOffset = eventX - mRightHandleX; + mGrabbedState = RIGHT_HANDLE_GRABBED; + invalidate(); + vibrate(VIBRATE_SHORT); + } + break; + + case MotionEvent.ACTION_MOVE: + if (DBG) log("touch-move"); + if (mGrabbedState == LEFT_HANDLE_GRABBED) { + mTouchDragOffset = eventX - mLeftHandleX; + invalidate(); + if (eventX >= mRightHandleX - EDGE_PADDING_DIP && !mTriggered) { + mTriggered = true; + mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE); + } + } else if (mGrabbedState == RIGHT_HANDLE_GRABBED) { + mTouchDragOffset = eventX - mRightHandleX; + invalidate(); + if (eventX <= mLeftHandleX + EDGE_PADDING_DIP && !mTriggered) { + mTriggered = true; + mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE); + } + } + break; + case MotionEvent.ACTION_UP: + if (DBG) log("touch-up"); + // handle animating back to start if they didn't trigger + if (mGrabbedState == LEFT_HANDLE_GRABBED + && Math.abs(eventX - mLeftHandleX) > 5) { + mAnimating = true; + mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS; + mAnimatingDelta = eventX - mLeftHandleX; + } else if (mGrabbedState == RIGHT_HANDLE_GRABBED + && Math.abs(eventX - mRightHandleX) > 5) { + mAnimating = true; + mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS; + mAnimatingDelta = eventX - mRightHandleX; + } + + mTouchDragOffset = 0; + mGrabbedState = NOTHING_GRABBED; + invalidate(); + break; + case MotionEvent.ACTION_CANCEL: + if (DBG) log("touch-cancel"); + reset(); + invalidate(); + break; + } + return true; + } + + private void reset() { + mAnimating = false; + mTouchDragOffset = 0; + mGrabbedState = NOTHING_GRABBED; + mTriggered = false; + } + + /** + * Triggers haptic feedback. + */ + private synchronized void vibrate(long duration) { + if (mVibrator == null) { + mVibrator = (android.os.Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); + } + mVibrator.vibrate(duration); + } + + /** + * Sets the bounds of the specified Drawable so that it's centered + * on the point (x,y), then draws it onto the specified canvas. + * TODO: is there already a utility method somewhere for this? + */ + private static void drawCentered(Drawable d, Canvas c, int x, int y) { + int w = d.getIntrinsicWidth(); + int h = d.getIntrinsicHeight(); + + // if (DBG) log("--> drawCentered: " + x + " , " + y + "; intrinsic " + w + " x " + h); + d.setBounds(x - (w / 2), y - (h / 2), + x + (w / 2), y + (h / 2)); + d.draw(c); + } + + + /** + * Registers a callback to be invoked when the dial + * is "triggered" by rotating it one way or the other. + * + * @param l the OnDialTriggerListener to attach to this view + */ + public void setOnDialTriggerListener(OnDialTriggerListener l) { + mOnDialTriggerListener = l; + } + + /** + * Dispatches a trigger event to our listener. + */ + private boolean dispatchTriggerEvent(int whichHandle) { + vibrate(VIBRATE_LONG); + if (mOnDialTriggerListener != null) { + return mOnDialTriggerListener.onDialTrigger(this, whichHandle); + } + return false; + } + + /** + * Interface definition for a callback to be invoked when the dial + * is "triggered" by rotating it one way or the other. + */ + public interface OnDialTriggerListener { + /** + * The dial was triggered because the user grabbed the left handle, + * and rotated the dial clockwise. + */ + public static final int LEFT_HANDLE = 1; + + /** + * The dial was triggered because the user grabbed the right handle, + * and rotated the dial counterclockwise. + */ + public static final int RIGHT_HANDLE = 2; + + /** + * @hide + * The center handle is currently unused. + */ + public static final int CENTER_HANDLE = 3; + + /** + * Called when the dial is triggered. + * + * @param v The view that was triggered + * @param whichHandle Which "dial handle" the user grabbed, + * either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}, or + * {@link #CENTER_HANDLE}. + * @return Whether the widget should freeze (e.g when the action goes to another screen, + * you want the UI to stay put until the transition occurs). + */ + boolean onDialTrigger(View v, int whichHandle); + } + + + // Debugging / testing code + + private void log(String msg) { + Log.d(LOG_TAG, msg); + } +} diff --git a/core/res/res/drawable-hdpi/title_bar_medium.png b/core/res/res/drawable-hdpi/title_bar_medium.png Binary files differnew file mode 100644 index 0000000..c13dd26 --- /dev/null +++ b/core/res/res/drawable-hdpi/title_bar_medium.png diff --git a/core/res/res/drawable-mdpi/title_bar_medium.png b/core/res/res/drawable-mdpi/title_bar_medium.png Binary files differnew file mode 100644 index 0000000..9d01f79 --- /dev/null +++ b/core/res/res/drawable-mdpi/title_bar_medium.png diff --git a/core/res/res/drawable/ic_jog_dial_answer.png b/core/res/res/drawable/ic_jog_dial_answer.png Binary files differnew file mode 100644 index 0000000..e2bc483 --- /dev/null +++ b/core/res/res/drawable/ic_jog_dial_answer.png diff --git a/core/res/res/drawable/ic_jog_dial_decline.png b/core/res/res/drawable/ic_jog_dial_decline.png Binary files differnew file mode 100644 index 0000000..81c76b5 --- /dev/null +++ b/core/res/res/drawable/ic_jog_dial_decline.png diff --git a/core/res/res/drawable/ic_jog_dial_silence_ringer.png b/core/res/res/drawable/ic_jog_dial_silence_ringer.png Binary files differnew file mode 100644 index 0000000..6d573e6 --- /dev/null +++ b/core/res/res/drawable/ic_jog_dial_silence_ringer.png diff --git a/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png Binary files differnew file mode 100644 index 0000000..3804c25 --- /dev/null +++ b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png diff --git a/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png Binary files differnew file mode 100644 index 0000000..62f8e15 --- /dev/null +++ b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png diff --git a/core/res/res/drawable/ic_jog_dial_unlock.png b/core/res/res/drawable/ic_jog_dial_unlock.png Binary files differnew file mode 100644 index 0000000..e697d91 --- /dev/null +++ b/core/res/res/drawable/ic_jog_dial_unlock.png diff --git a/core/res/res/drawable/jog_dial_arrow_long_left_green.png b/core/res/res/drawable/jog_dial_arrow_long_left_green.png Binary files differnew file mode 100644 index 0000000..334a8e0 --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_long_left_green.png diff --git a/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png Binary files differnew file mode 100644 index 0000000..2e011ca --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png diff --git a/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png Binary files differnew file mode 100644 index 0000000..323745e --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png diff --git a/core/res/res/drawable/jog_dial_arrow_long_right_red.png b/core/res/res/drawable/jog_dial_arrow_long_right_red.png Binary files differnew file mode 100644 index 0000000..1e97c9a --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_long_right_red.png diff --git a/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png Binary files differnew file mode 100644 index 0000000..3536e58 --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png diff --git a/core/res/res/drawable/jog_dial_arrow_short_left.png b/core/res/res/drawable/jog_dial_arrow_short_left.png Binary files differnew file mode 100644 index 0000000..4a4ab3ae --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_short_left.png diff --git a/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png b/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png Binary files differnew file mode 100644 index 0000000..987cfa7 --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png diff --git a/core/res/res/drawable/jog_dial_arrow_short_right.png b/core/res/res/drawable/jog_dial_arrow_short_right.png Binary files differnew file mode 100644 index 0000000..ee79875 --- /dev/null +++ b/core/res/res/drawable/jog_dial_arrow_short_right.png diff --git a/core/res/res/drawable/jog_dial_bg_cropped.png b/core/res/res/drawable/jog_dial_bg_cropped.png Binary files differnew file mode 100644 index 0000000..60d93d2 --- /dev/null +++ b/core/res/res/drawable/jog_dial_bg_cropped.png diff --git a/core/res/res/drawable/jog_dial_dimple.png b/core/res/res/drawable/jog_dial_dimple.png Binary files differnew file mode 100644 index 0000000..85d3a43 --- /dev/null +++ b/core/res/res/drawable/jog_dial_dimple.png diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml index 8d7e470..e800dfa 100644 --- a/core/res/res/layout/contact_header.xml +++ b/core/res/res/layout/contact_header.xml @@ -19,17 +19,17 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:background="@drawable/title_bar_tall" + android:background="@drawable/title_bar_medium" android:paddingRight="5dip" android:gravity="center_vertical"> - <ImageView android:id="@+id/photo" - android:layout_width="56dip" - android:layout_height="62dip" + <android.widget.FasttrackBadgeWidget android:id="@+id/photo" + android:layout_alignParentLeft="true" + android:layout_centerVertical="true" android:layout_marginRight="10dip" android:layout_marginLeft="10dip" - android:scaleType="fitCenter" - android:background="@drawable/fasttrack_badge_middle_large"/> + style="@*android:style/Widget.FasttrackBadgeWidget.WindowSmall" /> + /> <LinearLayout android:layout_width="0dip" diff --git a/core/res/res/layout/keyguard_screen_rotary_unlock.xml b/core/res/res/layout/keyguard_screen_rotary_unlock.xml new file mode 100644 index 0000000..cf97d04 --- /dev/null +++ b/core/res/res/layout/keyguard_screen_rotary_unlock.xml @@ -0,0 +1,136 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2009, 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. +*/ +--> + +<!-- This is the general lock screen which shows information about the + state of the device, as well as instructions on how to get past it + depending on the state of the device. It is the same for landscape + and portrait.--> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:id="@+id/root" + > + +<RelativeLayout + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:background="#A0000000" + > + + <TextView + android:id="@+id/carrier" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:layout_marginTop="20dip" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:attr/textColorSecondary" + /> + + <TextView + android:id="@+id/time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/carrier" + android:layout_centerHorizontal="true" + android:layout_marginTop="25dip" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textSize="55sp" + /> + + <TextView + android:id="@+id/date" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/time" + android:layout_centerHorizontal="true" + android:layout_marginTop="-12dip" + android:textAppearance="?android:attr/textAppearanceMedium" + /> + + <View + android:id="@+id/divider" + android:layout_width="fill_parent" + android:layout_height="1dip" + android:layout_marginTop="10dip" + android:layout_below="@id/date" + android:background="@android:drawable/divider_horizontal_dark" + /> + + <TextView + android:id="@+id/status1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/divider" + android:layout_centerHorizontal="true" + android:layout_marginTop="6dip" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:attr/textColorSecondary" + /> + + <TextView + android:id="@+id/status2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/status1" + android:layout_centerHorizontal="true" + android:layout_marginTop="6dip" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:attr/textColorSecondary" + /> + + <TextView + android:id="@+id/screenLocked" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/status2" + android:layout_centerHorizontal="true" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:attr/textColorSecondary" + android:gravity="center" + android:layout_marginTop="12dip" + /> + + <!-- By having the rotary selector hang below "screen locked" text, we get a layout more + robust for different screen sizes. On wvga, the widget should be flush with the bottom.--> + <com.android.internal.widget.RotarySelector + android:id="@+id/rotary" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@id/screenLocked" + android:layout_centerHorizontal="true" + android:layout_marginTop="24dip" + /> + + <!-- emergency call button shown when sim is missing or PUKd --> + <Button + android:id="@+id/emergencyCallButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@id/screenLocked" + android:layout_centerHorizontal="true" + android:layout_marginTop="24dip" + android:drawableLeft="@drawable/ic_emergency" + android:drawablePadding="8dip" + /> + +</RelativeLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 7aaf218..365363a 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -504,8 +504,10 @@ <!-- The keyboard type has changed, for example the user has plugged in an external keyboard. --> <flag name="keyboard" value="0x0010" /> - <!-- The keyboard accessibility has changed, for example the user has - slid the keyboard out to expose it. --> + <!-- The keyboard or navigation accessibility has changed, for example + the user has slid the keyboard out to expose it. Note that + inspite of its name, this applied to any accessibility: keyboard + or navigation. --> <flag name="keyboardHidden" value="0x0020" /> <!-- The navigation type has changed. Should never normally happen. --> <flag name="navigation" value="0x0040" /> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 560796a..c967c4c 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -18,13 +18,20 @@ */ --> <resources> - <drawable name="screen_background_light">#fff9f9f9</drawable> + <drawable name="screen_background_light">#ffffffff</drawable> <drawable name="screen_background_dark">#ff202020</drawable> <drawable name="status_bar_closed_default_background">#ff000000</drawable> <drawable name="status_bar_opened_default_background">#ff000000</drawable> <drawable name="search_bar_default_color">#ff000000</drawable> <drawable name="safe_mode_background">#60000000</drawable> + <!-- Background drawable that can be used for a transparent activity to + be able to display a dark UI: this darkens its background to make + a dark (default theme) UI more visible. --> <drawable name="screen_background_dark_transparent">#80000000</drawable> + <!-- Background drawable that can be used for a transparent activity to + be able to display a light UI: this lightens its background to make + a light UI more visible. --> + <drawable name="screen_background_light_transparent">#80ffffff</drawable> <color name="safe_mode_text">#80ffffff</color> <color name="white">#ffffffff</color> <color name="black">#ff000000</color> @@ -38,7 +45,7 @@ <color name="dim_foreground_dark_inverse">#323232</color> <color name="dim_foreground_dark_inverse_disabled">#80323232</color> <color name="hint_foreground_dark">#808080</color> - <color name="background_light">#fff9f9f9</color> + <color name="background_light">#ffffffff</color> <color name="bright_foreground_light">#ff000000</color> <color name="bright_foreground_light_inverse">#ffffffff</color> <color name="bright_foreground_light_disabled">#80000000</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 117e139..b710acb 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -35,6 +35,9 @@ <!-- The duration (in milliseconds) of a long animation. --> <integer name="config_longAnimTime">300</integer> + <!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION. + Please don't copy them, copy anything else. --> + <!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardward --> <!-- An Array of "[type-name],[associated radio-name],[priority] --> <string-array translatable="false" name="networkAttributes"> @@ -53,18 +56,40 @@ <item>"wifi,1,1"</item> <item>"mobile,0,1"</item> </string-array> - - <!-- The number of degrees to rotate the display when the keyboard is open. --> - <integer name="config_lidOpenRotation">90</integer> - - <!-- The number of degrees to rotate the display when the device is in a dock. --> - <integer name="config_dockedRotation">90</integer> - + <!-- Flag indicating whether the keyguard should be bypassed when the slider is open. This can be set or unset depending how easily the slider can be opened (for example, in a pocket or purse). --> <bool name="config_bypass_keyguard_if_slider_open">true</bool> + <!-- Flag indicating whether the device supports automatic brightness mode. --> + <bool name="config_automatic_brightness_available">false</bool> + + <!-- XXXXXX END OF RESOURCES USING WRONG NAMING CONVENTION --> + + <!-- The number of degrees to rotate the display when the keyboard is open. --> + <integer name="config_lidOpenRotation">90</integer> + + <!-- The number of degrees to rotate the display when the device is in a desk dock. + A value of -1 means no change in orientation by default. --> + <integer name="config_deskDockRotation">-1</integer> + + <!-- The number of degrees to rotate the display when the device is in a car dock. + A value of -1 means no change in orientation by default. --> + <integer name="config_carDockRotation">-1</integer> + + <!-- Indicate whether the lid state impacts the accessibility of + the physical keyboard. 0 means it doesn't, 1 means it is accessible + when the lid is open, 2 means it is accessible when the lid is + closed. The default is 1. --> + <integer name="config_lidKeyboardAccessibility">1</integer> + + <!-- Indicate whether the lid state impacts the accessibility of + the physical keyboard. 0 means it doesn't, 1 means it is accessible + when the lid is open, 2 means it is accessible when the lid is + closed. The default is 0. --> + <integer name="config_lidNavigationAccessibility">0</integer> + <!-- Vibrator pattern for feedback about a long screen/key press --> <integer-array name="config_longPressVibePattern"> <item>0</item> @@ -81,6 +106,4 @@ <item>30</item> </integer-array> - <!-- Flag indicating whether the device supports automatic brightness mode. --> - <bool name="config_automatic_brightness_available">false</bool> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index c4636f3..2bc2a0f 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1168,10 +1168,13 @@ <public type="style" name="Theme.Wallpaper" /> <public type="style" name="Theme.Wallpaper.NoTitleBar" /> <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" /> + <public type="style" name="Theme.WallpaperSettings" /> + <public type="style" name="Theme.Light.WallpaperSettings" /> <!-- Semi-transparent background that can be used when placing a dark themed UI on top of some arbitrary background (such as the wallpaper). This darkens the background sufficiently that the UI can be seen. --> <public type="drawable" name="screen_background_dark_transparent" /> + <public type="drawable" name="screen_background_light_transparent" /> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 69ddd63..bd79c75 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1962,7 +1962,7 @@ <string name="allow">Allow</string> <string name="deny">Deny</string> <string name="permission_request_notification_title">Permission Requested</string> - <string name="permission_request_notification_subtitle">for account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string> + <string name="permission_request_notification_with_subtitle">Permission Requested\nfor account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string> <!-- Label to show for a service that is running because it is an input method. --> <string name="input_method_binding_label">Input method</string> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index fae612c..69612e9 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -458,7 +458,6 @@ <style name="Widget.ListView.White" parent="Widget.AbsListView"> <item name="android:listSelector">@android:drawable/list_selector_background</item> - <item name="android:background">@android:color/white</item> <item name="android:divider">@android:drawable/divider_horizontal_bright_opaque</item> </style> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index 4f76c56..1aa48ee 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -303,6 +303,32 @@ <item name="android:windowContentOverlay">@null</item> </style> + <!-- Theme for a wallpaper's setting activity that is designed to be on + top of a dark background. --> + <style name="Theme.WallpaperSettings"> + <item name="android:windowBackground">@android:drawable/screen_background_dark_transparent</item> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item> + </style> + + <!-- Theme for a wallpaper's setting activity that is designed to be on + top of a light background. --> + <style name="Theme.Light.WallpaperSettings"> + <item name="android:windowBackground">@android:drawable/screen_background_light_transparent</item> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item> + </style> + + <!-- Style to apply on top of a wallpaper settings theme when it is being + shown on top of the real wallpaper --> + <style name="ActiveWallpaperSettings"> + </style> + + <!-- Style to apply on top of a wallpaper settings theme when it is being + shown on top of the real wallpaper --> + <style name="PreviewWallpaperSettings"> + </style> + <!-- Default theme for translucent activities, that is windows that allow you to see through them to the windows behind. This sets up the translucent flag and appropriate animations for your windows. --> diff --git a/data/etc/Android.mk b/data/etc/Android.mk index a32d8ea..041c5d3 100644 --- a/data/etc/Android.mk +++ b/data/etc/Android.mk @@ -32,3 +32,20 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions LOCAL_SRC_FILES := $(LOCAL_MODULE) include $(BUILD_PREBUILT) + +######################## +include $(CLEAR_VARS) + +LOCAL_MODULE := required_hardware.xml + +LOCAL_MODULE_TAGS := user + +LOCAL_MODULE_CLASS := ETC + +# This will install the file in /system/etc/permissions +# +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions + +LOCAL_SRC_FILES := $(LOCAL_MODULE) + +include $(BUILD_PREBUILT) diff --git a/data/etc/android.hardware.camera.flash-autofocus.xml b/data/etc/android.hardware.camera.flash-autofocus.xml new file mode 100644 index 0000000..55f1900 --- /dev/null +++ b/data/etc/android.hardware.camera.flash-autofocus.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- This is the standard set of features for a camera with a flash. Note + that this currently requires having auto-focus as well. --> +<permissions> + <feature name="android.hardware.camera" /> + <feature name="android.hardware.camera.autofocus" /> + <feature name="android.hardware.camera.flash" /> +</permissions> diff --git a/data/etc/android.hardware.sensor.light.xml b/data/etc/android.hardware.sensor.light.xml new file mode 100644 index 0000000..78b0fec --- /dev/null +++ b/data/etc/android.hardware.sensor.light.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- Feature for devices with an ambient light sensor. --> +<permissions> + <feature name="android.hardware.sensor.light" /> +</permissions> diff --git a/data/etc/android.hardware.sensor.proximity.xml b/data/etc/android.hardware.sensor.proximity.xml new file mode 100644 index 0000000..d1948de --- /dev/null +++ b/data/etc/android.hardware.sensor.proximity.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- Feature for devices with a proximity sensor. --> +<permissions> + <feature name="android.hardware.sensor.proximity" /> +</permissions> diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml new file mode 100644 index 0000000..72e0485 --- /dev/null +++ b/data/etc/android.hardware.telephony.cdma.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- This is the standard set of features for a CDMA phone. --> +<permissions> + <feature name="android.hardware.telephony" /> + <feature name="android.hardware.telephony.cdma" /> +</permissions> diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml new file mode 100644 index 0000000..ffde433 --- /dev/null +++ b/data/etc/android.hardware.telephony.gsm.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- This is the standard set of features for a GSM phone. --> +<permissions> + <feature name="android.hardware.telephony" /> + <feature name="android.hardware.telephony.gsm" /> +</permissions> diff --git a/data/etc/required_hardware.xml b/data/etc/required_hardware.xml new file mode 100644 index 0000000..896a148 --- /dev/null +++ b/data/etc/required_hardware.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 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. +--> + +<!-- These are the hardware features that all devices must possess. + These are always added for you by the build system, you do not need + to add them yourself. --> +<permissions> + <feature name="android.hardware.sensor.compass" /> + <feature name="android.hardware.sensor.accelerometer" /> + <feature name="android.hardware.bluetooth" /> + <feature name="android.hardware.wifi" /> +</permissions> diff --git a/docs/html/guide/topics/resources/resources-i18n.jd b/docs/html/guide/topics/resources/resources-i18n.jd index 85b89d1..ff9579f 100755 --- a/docs/html/guide/topics/resources/resources-i18n.jd +++ b/docs/html/guide/topics/resources/resources-i18n.jd @@ -441,7 +441,7 @@ resources for a fully specified configuration would look like this:</p> <pre> MyApp/ res/ - drawable-en-rUS-large-long-port-mdpi-finger-keysexposed-qwerty-dpad-480x320/ + drawable-en-rUS-large-long-port-mdpi-finger-keysexposed-qwerty-navexposed-dpad-480x320/ </pre> <p>More typically, you will only specify a few specific configuration options. You may drop any of the values from the @@ -575,6 +575,14 @@ MyApp/ <td><code>nokeys</code>, <code>qwerty</code>, <code>12key</code> </td> </tr> <tr> + <td>Whether the navigation keys are available to the user</td> + <td><p><code>navexposed</code>, <code>navhidden</code> + </p><p> + If the hardware's navigation keys are currently available to + the user, the navexposed resources will be used; if they are not + available (such as behind a closed lid), navhidden will be used.</p></td> + </tr> + <tr> <td>Primary non-touchscreen<br /> navigation method</td> <td><code>nonav</code>, <code>dpad</code>, <code>trackball</code>, <code>wheel</code> </td> diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 89db4fa..d35c5e3 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -140,6 +140,8 @@ public class RenderScript { native void nScriptSetTimeZone(int script, byte[] timeZone); native void nScriptSetType(int type, boolean writable, String name, int slot); native void nScriptSetRoot(boolean isRoot); + native void nScriptSetInvokable(String name, int slot); + native void nScriptInvoke(int id, int slot); native void nScriptCBegin(); native void nScriptCSetScript(byte[] script, int offset, int length); diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java index a402471..35791a3 100644 --- a/graphics/java/android/renderscript/Script.java +++ b/graphics/java/android/renderscript/Script.java @@ -25,6 +25,22 @@ public class Script extends BaseObj { boolean mIsRoot; Type[] mTypes; boolean[] mWritable; + Invokable[] mInvokables; + + public static class Invokable { + RenderScript mRS; + Script mScript; + int mSlot; + String mName; + + Invokable() { + mSlot = -1; + } + + public void execute() { + mRS.nScriptInvoke(mScript.mID, mSlot); + } + } Script(int id, RenderScript rs) { super(rs); @@ -61,12 +77,15 @@ public class Script extends BaseObj { Type[] mTypes; String[] mNames; boolean[] mWritable; + int mInvokableCount = 0; + Invokable[] mInvokables; Builder(RenderScript rs) { mRS = rs; mTypes = new Type[MAX_SLOT]; mNames = new String[MAX_SLOT]; mWritable = new boolean[MAX_SLOT]; + mInvokables = new Invokable[MAX_SLOT]; } public void setType(Type t, int slot) { @@ -79,6 +98,15 @@ public class Script extends BaseObj { mNames[slot] = name; } + public Invokable addInvokable(String func) { + Invokable i = new Invokable(); + i.mName = func; + i.mRS = mRS; + i.mSlot = mInvokableCount; + mInvokables[mInvokableCount++] = i; + return i; + } + public void setType(boolean writable, int slot) { mWritable[slot] = writable; } @@ -90,11 +118,20 @@ public class Script extends BaseObj { mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct); } } + for(int ct=0; ct < mInvokableCount; ct++) { + mRS.nScriptSetInvokable(mInvokables[ct].mName, ct); + } } void transferObject(Script s) { s.mIsRoot = mIsRoot; s.mTypes = mTypes; + s.mInvokables = new Invokable[mInvokableCount]; + for(int ct=0; ct < mInvokableCount; ct++) { + s.mInvokables[ct] = mInvokables[ct]; + s.mInvokables[ct].mScript = s; + } + s.mInvokables = null; } public void setRoot(boolean r) { diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index 90b5958..eae6f24 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -891,6 +891,29 @@ nScriptSetType(JNIEnv *_env, jobject _this, jint type, jboolean writable, jstrin } static void +nScriptSetInvoke(JNIEnv *_env, jobject _this, jstring _str, jint slot) +{ + RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); + LOG_API("nScriptSetInvoke, con(%p)", con); + const char* n = NULL; + if (_str) { + n = _env->GetStringUTFChars(_str, NULL); + } + rsScriptSetInvoke(con, n, slot); + if (n) { + _env->ReleaseStringUTFChars(_str, n); + } +} + +static void +nScriptInvoke(JNIEnv *_env, jobject _this, jint obj, jint slot) +{ + RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); + LOG_API("nScriptInvoke, con(%p), script(%p)", con, (void *)obj); + rsScriptInvoke(con, (RsScript)obj, slot); +} + +static void nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot) { RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); @@ -1366,6 +1389,8 @@ static JNINativeMethod methods[] = { {"nScriptSetTimeZone", "(I[B)V", (void*)nScriptSetTimeZone }, {"nScriptSetType", "(IZLjava/lang/String;I)V", (void*)nScriptSetType }, {"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot }, +{"nScriptSetInvokable", "(Ljava/lang/String;I)V", (void*)nScriptSetInvoke }, +{"nScriptInvoke", "(II)V", (void*)nScriptInvoke }, {"nScriptCBegin", "()V", (void*)nScriptCBegin }, {"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript }, diff --git a/include/media/stagefright/SoftwareRenderer.h b/include/media/stagefright/SoftwareRenderer.h index b61858c..1545493 100644 --- a/include/media/stagefright/SoftwareRenderer.h +++ b/include/media/stagefright/SoftwareRenderer.h @@ -45,6 +45,7 @@ private: void renderCbYCrY(const void *data, size_t size); void renderYUV420Planar(const void *data, size_t size); + void renderQCOMYUV420SemiPlanar(const void *data, size_t size); OMX_COLOR_FORMATTYPE mColorFormat; sp<ISurface> mISurface; diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index e524e2a..17ccad6 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -864,6 +864,13 @@ struct ResTable_config KEYSHIDDEN_SOFT = 0x0003, }; + enum { + MASK_NAVHIDDEN = 0x000c, + NAVHIDDEN_ANY = 0x0000, + NAVHIDDEN_NO = 0x0004, + NAVHIDDEN_YES = 0x0008, + }; + union { struct { uint8_t keyboard; @@ -1011,7 +1018,8 @@ struct ResTable_config if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION; if (density != o.density) diffs |= CONFIG_DENSITY; if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN; - if (((inputFlags^o.inputFlags)&MASK_KEYSHIDDEN) != 0) diffs |= CONFIG_KEYBOARD_HIDDEN; + if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0) + diffs |= CONFIG_KEYBOARD_HIDDEN; if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD; if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION; if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE; @@ -1082,6 +1090,11 @@ struct ResTable_config if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true; } + if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) { + if (!(inputFlags & MASK_NAVHIDDEN)) return false; + if (!(o.inputFlags & MASK_NAVHIDDEN)) return true; + } + if (keyboard != o.keyboard) { if (!keyboard) return false; if (!o.keyboard) return true; @@ -1225,6 +1238,18 @@ struct ResTable_config } } + const int navHidden = inputFlags & MASK_NAVHIDDEN; + const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN; + if (navHidden != oNavHidden) { + const int reqNavHidden = + requested->inputFlags & MASK_NAVHIDDEN; + if (reqNavHidden) { + + if (!navHidden) return false; + if (!oNavHidden) return true; + } + } + if ((keyboard != o.keyboard) && requested->keyboard) { return (keyboard); } @@ -1332,6 +1357,12 @@ struct ResTable_config return false; } } + const int navHidden = inputFlags&MASK_NAVHIDDEN; + const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN; + if (setNavHidden != 0 && navHidden != 0 + && navHidden != setNavHidden) { + return false; + } if (settings.keyboard != 0 && keyboard != 0 && keyboard != settings.keyboard) { return false; diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp index 4f7500f..add358b 100644 --- a/libs/audioflinger/AudioFlinger.cpp +++ b/libs/audioflinger/AudioFlinger.cpp @@ -2069,7 +2069,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( } } -AudioFlinger::PlaybackThread::TrackBase::~TrackBase() +AudioFlinger::ThreadBase::TrackBase::~TrackBase() { if (mCblk) { mCblk->~audio_track_cblk_t(); // destroy our shared-structure. @@ -2081,7 +2081,7 @@ AudioFlinger::PlaybackThread::TrackBase::~TrackBase() mClient.clear(); } -void AudioFlinger::PlaybackThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) +void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer) { buffer->raw = 0; mFrameCount = buffer->frameCount; @@ -2089,7 +2089,7 @@ void AudioFlinger::PlaybackThread::TrackBase::releaseBuffer(AudioBufferProvider: buffer->frameCount = 0; } -bool AudioFlinger::PlaybackThread::TrackBase::step() { +bool AudioFlinger::ThreadBase::TrackBase::step() { bool result; audio_track_cblk_t* cblk = this->cblk(); @@ -2101,7 +2101,7 @@ bool AudioFlinger::PlaybackThread::TrackBase::step() { return result; } -void AudioFlinger::PlaybackThread::TrackBase::reset() { +void AudioFlinger::ThreadBase::TrackBase::reset() { audio_track_cblk_t* cblk = this->cblk(); cblk->user = 0; @@ -2112,20 +2112,20 @@ void AudioFlinger::PlaybackThread::TrackBase::reset() { LOGV("TrackBase::reset"); } -sp<IMemory> AudioFlinger::PlaybackThread::TrackBase::getCblk() const +sp<IMemory> AudioFlinger::ThreadBase::TrackBase::getCblk() const { return mCblkMemory; } -int AudioFlinger::PlaybackThread::TrackBase::sampleRate() const { +int AudioFlinger::ThreadBase::TrackBase::sampleRate() const { return (int)mCblk->sampleRate; } -int AudioFlinger::PlaybackThread::TrackBase::channelCount() const { +int AudioFlinger::ThreadBase::TrackBase::channelCount() const { return (int)mCblk->channels; } -void* AudioFlinger::PlaybackThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { +void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { audio_track_cblk_t* cblk = this->cblk(); int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize; int8_t *bufferEnd = bufferStart + frames * cblk->frameSize; diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index ac2e738..87ad97c 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -297,6 +297,16 @@ ScriptSetType { param const char * name } +ScriptSetInvoke { + param const char * name + param uint32_t slot + } + +ScriptInvoke { + param RsScript s + param uint32_t slot + } + ScriptSetRoot { param bool isRoot } diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index fde31a1..99a085d 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -27,6 +27,8 @@ Script::Script() mEnviroment.mClearColor[2] = 0; mEnviroment.mClearColor[3] = 1; mEnviroment.mClearDepth = 1; + mEnviroment.mClearStencil = 0; + mEnviroment.mIsRoot = false; } Script::~Script() @@ -83,10 +85,23 @@ void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, bool writable, c } } +void rsi_ScriptSetInvoke(Context *rsc, const char *name, uint32_t slot) +{ + ScriptCState *ss = &rsc->mScriptC; + ss->mInvokableNames[slot] = name; +} + +void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot) +{ + Script *s = static_cast<Script *>(vs); + s->mEnviroment.mInvokables[slot](); +} + + void rsi_ScriptSetRoot(Context * rsc, bool isRoot) { ScriptCState *ss = &rsc->mScriptC; - ss->mEnviroment.mIsRoot = isRoot; + ss->mScript->mEnviroment.mIsRoot = isRoot; } diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h index 60f83a6..e40531e 100644 --- a/libs/rs/rsScript.h +++ b/libs/rs/rsScript.h @@ -34,6 +34,7 @@ class ProgramFragmentStore; class Script : public ObjectBase { public: + typedef void (* InvokeFunc_t)(void); Script(); virtual ~Script(); @@ -52,17 +53,22 @@ public: ObjectBaseRef<ProgramFragment> mFragment; //ObjectBaseRef<ProgramRaster> mRaster; ObjectBaseRef<ProgramFragmentStore> mFragmentStore; - + InvokeFunc_t mInvokables[MAX_SCRIPT_BANKS]; + const char * mScriptText; + uint32_t mScriptTextLength; }; Enviroment_t mEnviroment; uint32_t mCounstantBufferCount; + ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS]; ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS]; String8 mSlotNames[MAX_SCRIPT_BANKS]; bool mSlotWritable[MAX_SCRIPT_BANKS]; + + virtual bool run(Context *, uint32_t launchID) = 0; }; diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index 8230cbc..108ae5a 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -82,36 +82,27 @@ bool ScriptC::run(Context *rsc, uint32_t launchIndex) ScriptCState::ScriptCState() { + mScript = NULL; clear(); } ScriptCState::~ScriptCState() { - if (mAccScript) { - accDeleteScript(mAccScript); - } + delete mScript; + mScript = NULL; } void ScriptCState::clear() { - memset(&mProgram, 0, sizeof(mProgram)); - for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) { mConstantBufferTypes[ct].clear(); mSlotNames[ct].setTo(""); + mInvokableNames[ct].setTo(""); mSlotWritable[ct] = false; } - memset(&mEnviroment, 0, sizeof(mEnviroment)); - mEnviroment.mClearColor[0] = 0; - mEnviroment.mClearColor[1] = 0; - mEnviroment.mClearColor[2] = 0; - mEnviroment.mClearColor[3] = 1; - mEnviroment.mClearDepth = 1; - mEnviroment.mClearStencil = 0; - mEnviroment.mIsRoot = false; - - mAccScript = NULL; + delete mScript; + mScript = new ScriptC(); mInt32Defines.clear(); mFloatDefines.clear(); @@ -127,9 +118,9 @@ static ACCvoid* symbolLookup(ACCvoid* pContext, const ACCchar* name) return NULL; } -void ScriptCState::runCompiler(Context *rsc) +void ScriptCState::runCompiler(Context *rsc, ScriptC *s) { - mAccScript = accCreateScript(); + s->mAccScript = accCreateScript(); String8 tmp; rsc->appendNameDefines(&tmp); @@ -139,44 +130,51 @@ void ScriptCState::runCompiler(Context *rsc) appendTypes(&tmp); tmp.append("#line 1\n"); - const char* scriptSource[] = {tmp.string(), mProgram.mScriptText}; - int scriptLength[] = {tmp.length(), mProgram.mScriptTextLength} ; - accScriptSource(mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength); - accRegisterSymbolCallback(mAccScript, symbolLookup, NULL); - accCompileScript(mAccScript); - accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript); - accGetScriptLabel(mAccScript, "init", (ACCvoid**) &mProgram.mInit); - rsAssert(mProgram.mScript); + const char* scriptSource[] = {tmp.string(), s->mEnviroment.mScriptText}; + int scriptLength[] = {tmp.length(), s->mEnviroment.mScriptTextLength} ; + accScriptSource(s->mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength); + accRegisterSymbolCallback(s->mAccScript, symbolLookup, NULL); + accCompileScript(s->mAccScript); + accGetScriptLabel(s->mAccScript, "main", (ACCvoid**) &s->mProgram.mScript); + accGetScriptLabel(s->mAccScript, "init", (ACCvoid**) &s->mProgram.mInit); + rsAssert(s->mProgram.mScript); - if (!mProgram.mScript) { + if (!s->mProgram.mScript) { ACCchar buf[4096]; ACCsizei len; - accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf); + accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf); LOGE(buf); } - if (mProgram.mInit) { - mProgram.mInit(); + if (s->mProgram.mInit) { + s->mProgram.mInit(); } for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { if (mSlotNames[ct].length() > 0) { - accGetScriptLabel(mAccScript, + accGetScriptLabel(s->mAccScript, mSlotNames[ct].string(), - (ACCvoid**) &mProgram.mSlotPointers[ct]); - LOGE("var %s %p", mSlotNames[ct].string(), mProgram.mSlotPointers[ct]); + (ACCvoid**) &s->mProgram.mSlotPointers[ct]); + } + } + + for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { + if (mInvokableNames[ct].length() > 0) { + accGetScriptLabel(s->mAccScript, + mInvokableNames[ct].string(), + (ACCvoid**) &s->mEnviroment.mInvokables[ct]); } } - mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); - mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); - mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore()); + s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment()); + s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex()); + s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore()); - if (mProgram.mScript) { + if (s->mProgram.mScript) { const static int pragmaMax = 16; ACCsizei pragmaCount; ACCchar * str[pragmaMax]; - accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]); + accGetPragmas(s->mAccScript, &pragmaCount, pragmaMax, &str[0]); for (int ct=0; ct < pragmaCount; ct+=2) { if (!strcmp(str[ct], "version")) { @@ -188,12 +186,12 @@ void ScriptCState::runCompiler(Context *rsc) continue; } if (!strcmp(str[ct+1], "parent")) { - mEnviroment.mVertex.clear(); + s->mEnviroment.mVertex.clear(); continue; } ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]); if (pv != NULL) { - mEnviroment.mVertex.set(pv); + s->mEnviroment.mVertex.set(pv); continue; } LOGE("Unreconized value %s passed to stateVertex", str[ct+1]); @@ -208,12 +206,12 @@ void ScriptCState::runCompiler(Context *rsc) continue; } if (!strcmp(str[ct+1], "parent")) { - mEnviroment.mFragment.clear(); + s->mEnviroment.mFragment.clear(); continue; } ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]); if (pf != NULL) { - mEnviroment.mFragment.set(pf); + s->mEnviroment.mFragment.set(pf); continue; } LOGE("Unreconized value %s passed to stateFragment", str[ct+1]); @@ -224,13 +222,13 @@ void ScriptCState::runCompiler(Context *rsc) continue; } if (!strcmp(str[ct+1], "parent")) { - mEnviroment.mFragmentStore.clear(); + s->mEnviroment.mFragmentStore.clear(); continue; } ProgramFragmentStore * pfs = (ProgramFragmentStore *)rsc->lookupName(str[ct+1]); if (pfs != NULL) { - mEnviroment.mFragmentStore.set(pfs); + s->mEnviroment.mFragmentStore.set(pfs); continue; } LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]); @@ -351,33 +349,6 @@ void ScriptCState::appendTypes(String8 *str) s.append(";\n"); LOGD(s); str->append(s); -#if 0 - for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) { - const Component *c = e->getComponent(ct2); - tmp.setTo("#define "); - tmp.append(mSlotNames[ct]); - tmp.append("_"); - tmp.append(c->getComponentName()); - switch (c->getType()) { - case Component::FLOAT: - tmp.append(" loadF("); - break; - case Component::SIGNED: - sprintf(buf, " loadI%i(", c->getBits()); - tmp.append(buf); - break; - case Component::UNSIGNED: - sprintf(buf, " loadU%i(", c->getBits()); - tmp.append(buf); - break; - } - sprintf(buf, "%i, %i)\n", ct, ct2); - tmp.append(buf); - - LOGD(tmp); - str->append(tmp); - } -#endif } } } @@ -394,15 +365,16 @@ void rsi_ScriptCBegin(Context * rsc) void rsi_ScriptCSetScript(Context * rsc, void *vp) { - ScriptCState *ss = &rsc->mScriptC; - ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp); + rsAssert(0); + //ScriptCState *ss = &rsc->mScriptC; + //ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp); } void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) { ScriptCState *ss = &rsc->mScriptC; - ss->mProgram.mScriptText = text; - ss->mProgram.mScriptTextLength = len; + ss->mScript->mEnviroment.mScriptText = text; + ss->mScript->mEnviroment.mScriptTextLength = len; } @@ -410,14 +382,11 @@ RsScript rsi_ScriptCCreate(Context * rsc) { ScriptCState *ss = &rsc->mScriptC; - ss->runCompiler(rsc); + ScriptC *s = ss->mScript; + ss->mScript = NULL; - ScriptC *s = new ScriptC(); + ss->runCompiler(rsc, s); s->incUserRef(); - s->mAccScript = ss->mAccScript; - ss->mAccScript = NULL; - s->mEnviroment = ss->mEnviroment; - s->mProgram = ss->mProgram; for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get()); s->mSlotNames[ct] = ss->mSlotNames[ct]; diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index 8aa99ef..355f0c3 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -67,17 +67,15 @@ public: ScriptCState(); ~ScriptCState(); - ACCscript* mAccScript; - - ScriptC::Program_t mProgram; - Script::Enviroment_t mEnviroment; + ScriptC *mScript; ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS]; String8 mSlotNames[MAX_SCRIPT_BANKS]; bool mSlotWritable[MAX_SCRIPT_BANKS]; + String8 mInvokableNames[MAX_SCRIPT_BANKS]; void clear(); - void runCompiler(Context *rsc); + void runCompiler(Context *rsc, ScriptC *s); void appendVarDefines(String8 *str); void appendTypes(String8 *str); diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp index bbfc54b..38a897d 100644 --- a/libs/surfaceflinger/LayerBuffer.cpp +++ b/libs/surfaceflinger/LayerBuffer.cpp @@ -607,9 +607,10 @@ LayerBuffer::OverlaySource::~OverlaySource() void LayerBuffer::OverlaySource::onDraw(const Region& clip) const { + // this would be where the color-key would be set, should we need it. GLclampx red = 0; GLclampx green = 0; - GLclampx blue = 0x1818; + GLclampx blue = 0; mLayer.clearWithOpenGL(clip, red, green, blue, 0); } diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp index 4dab3a2..64522fb 100644 --- a/libs/ui/Surface.cpp +++ b/libs/ui/Surface.cpp @@ -497,11 +497,12 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) LOGE("error dequeuing a buffer (%s)", strerror(bufIdx)); return bufIdx; } - + + // below we make sure we AT LEAST have the usage flags we want const uint32_t usage(getUsage()); const sp<SurfaceBuffer>& backBuffer(mBuffers[bufIdx]); if (backBuffer == 0 || - uint32_t(backBuffer->usage) != usage || + ((uint32_t(backBuffer->usage) & usage) != usage) || mSharedBufferClient->needNewBuffer(bufIdx)) { err = getBufferLocked(bufIdx, usage); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 1dd644b..d6463a1 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -345,6 +345,9 @@ public class AudioManager { /** * Adjusts the volume of a particular stream by one step in a direction. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or @@ -370,6 +373,9 @@ public class AudioManager { * active, it will have the highest priority regardless of if the in-call * screen is showing. Another example, if music is playing in the background * and a call is not active, the music stream will be adjusted. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param direction The direction to adjust the volume. One of * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or @@ -391,6 +397,9 @@ public class AudioManager { /** * Adjusts the volume of the most relevant stream, or the given fallback * stream. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param direction The direction to adjust the volume. One of * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or @@ -541,6 +550,9 @@ public class AudioManager { * <p> * For a better user experience, applications MUST unmute a muted stream * in onPause() and mute is again in onResume() if appropriate. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param streamType The stream to be muted/unmuted. * @param state The required mute state: true for mute ON, false for mute OFF @@ -608,6 +620,9 @@ public class AudioManager { /** * Sets the setting for when the vibrate type should vibrate. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param vibrateType The type of vibrate. One of * {@link #VIBRATE_TYPE_NOTIFICATION} or @@ -630,6 +645,9 @@ public class AudioManager { /** * Sets the speakerphone on or off. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param on set <var>true</var> to turn on speakerphone; * <var>false</var> to turn it off @@ -660,6 +678,9 @@ public class AudioManager { /** * Request use of Bluetooth SCO headset for communications. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param on set <var>true</var> to use bluetooth SCO for communications; * <var>false</var> to not use bluetooth SCO for communications @@ -739,6 +760,9 @@ public class AudioManager { /** * Sets the microphone mute on or off. + * <p> + * This method should only be used by applications that replace the platform-wide + * management of audio settings or the main telephony application. * * @param on set <var>true</var> to mute the microphone; * <var>false</var> to turn mute off @@ -758,6 +782,13 @@ public class AudioManager { /** * Sets the audio mode. + * <p> + * The audio mode encompasses audio routing AND the behavior of + * the telephony layer. Therefore this method should only be used by applications that + * replace the platform-wide management of audio settings or the main telephony application. + * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony + * application when it places a phone call, as it will cause signals from the radio layer + * to feed the platform mixer. * * @param mode the requested audio mode (NORMAL, RINGTONE, or IN_CALL). * Informs the HAL about the current audio state so that diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index aba40b3..73b6483 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -16,8 +16,7 @@ package android.media; -import android.util.Log; - +import java.io.IOException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; @@ -25,171 +24,102 @@ import java.util.HashMap; import java.util.Map; /** - * Wrapper for native Exif library - * {@hide} + * This is a class for reading and writing Exif tags in a JPEG file. */ public class ExifInterface { - private static final String TAG = "ExifInterface"; - private String mFilename; - - // Constants used for the Orientation Exif tag. - public static final int ORIENTATION_UNDEFINED = 0; - public static final int ORIENTATION_NORMAL = 1; - - // Constants used for white balance - public static final int WHITEBALANCE_AUTO = 0; - public static final int WHITEBALANCE_MANUAL = 1; - - // left right reversed mirror - public static final int ORIENTATION_FLIP_HORIZONTAL = 2; - public static final int ORIENTATION_ROTATE_180 = 3; - - // upside down mirror - public static final int ORIENTATION_FLIP_VERTICAL = 4; - - // flipped about top-left <--> bottom-right axis - public static final int ORIENTATION_TRANSPOSE = 5; - - // rotate 90 cw to right it - public static final int ORIENTATION_ROTATE_90 = 6; - - // flipped about top-right <--> bottom-left axis - public static final int ORIENTATION_TRANSVERSE = 7; - - // rotate 270 to right it - public static final int ORIENTATION_ROTATE_270 = 8; // The Exif tag names public static final String TAG_ORIENTATION = "Orientation"; - public static final String TAG_DATETIME = "DateTime"; public static final String TAG_MAKE = "Make"; public static final String TAG_MODEL = "Model"; public static final String TAG_FLASH = "Flash"; public static final String TAG_IMAGE_WIDTH = "ImageWidth"; public static final String TAG_IMAGE_LENGTH = "ImageLength"; - public static final String TAG_GPS_LATITUDE = "GPSLatitude"; public static final String TAG_GPS_LONGITUDE = "GPSLongitude"; - public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef"; public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef"; public static final String TAG_WHITE_BALANCE = "WhiteBalance"; - private boolean mSavedAttributes = false; - private boolean mHasThumbnail = false; - private HashMap<String, String> mCachedAttributes = null; + // Constants used for the Orientation Exif tag. + public static final int ORIENTATION_UNDEFINED = 0; + public static final int ORIENTATION_NORMAL = 1; + public static final int ORIENTATION_FLIP_HORIZONTAL = 2; // left right reversed mirror + public static final int ORIENTATION_ROTATE_180 = 3; + public static final int ORIENTATION_FLIP_VERTICAL = 4; // upside down mirror + public static final int ORIENTATION_TRANSPOSE = 5; // flipped about top-left <--> bottom-right axis + public static final int ORIENTATION_ROTATE_90 = 6; // rotate 90 cw to right it + public static final int ORIENTATION_TRANSVERSE = 7; // flipped about top-right <--> bottom-left axis + public static final int ORIENTATION_ROTATE_270 = 8; // rotate 270 to right it + + // Constants used for white balance + public static final int WHITEBALANCE_AUTO = 0; + public static final int WHITEBALANCE_MANUAL = 1; static { System.loadLibrary("exif"); } - private static ExifInterface sExifObj = null; - /** - * Since the underlying jhead native code is not thread-safe, - * ExifInterface should use singleton interface instead of public - * constructor. - */ - private static synchronized ExifInterface instance() { - if (sExifObj == null) { - sExifObj = new ExifInterface(); - } + private String mFilename; + private HashMap<String, String> mAttributes; + private boolean mHasThumbnail = false; - return sExifObj; - } + // Because the underlying implementation (jhead) uses static variables, + // there can only be one user at a time for the native functions (and + // they cannot keep state in the native code across function calls). We + // use sLock the serialize the accesses. + private static Object sLock = new Object(); /** - * The following 3 static methods are handy routines for atomic operation - * of underlying jhead library. It retrieves EXIF data and then release - * ExifInterface immediately. + * Reads Exif tags from the specified JPEG file. */ - public static synchronized HashMap<String, String> loadExifData(String filename) { - ExifInterface exif = instance(); - HashMap<String, String> exifData = null; - if (exif != null) { - exif.setFilename(filename); - exifData = exif.getAttributes(); - } - return exifData; + public ExifInterface(String filename) throws IOException { + mFilename = filename; + loadAttributes(); } - public static synchronized void saveExifData(String filename, HashMap<String, String> exifData) { - ExifInterface exif = instance(); - if (exif != null) { - exif.setFilename(filename); - exif.saveAttributes(exifData); - } - } - - public static synchronized byte[] getExifThumbnail(String filename) { - ExifInterface exif = instance(); - if (exif != null) { - exif.setFilename(filename); - return exif.getThumbnail(); - } - return null; - } - - public void setFilename(String filename) { - if (mFilename == null || !mFilename.equals(filename)) { - mFilename = filename; - mCachedAttributes = null; - } + /** + * Returns the value of the specified tag or {@code null} if there + * is no such tag in the file. + * + * @param tag the name of the tag. + */ + public String getAttribute(String tag) { + return mAttributes.get(tag); } /** - * Given a HashMap of Exif tags and associated values, an Exif section in - * the JPG file is created and loaded with the tag data. saveAttributes() - * is expensive because it involves copying all the JPG data from one file - * to another and deleting the old file and renaming the other. It's best - * to collect all the attributes to write and make a single call rather - * than multiple calls for each attribute. You must call "commitChanges()" - * at some point to commit the changes. + * Set the value of the specified tag. + * + * @param tag the name of the tag. + * @param value the value of the tag. */ - public void saveAttributes(HashMap<String, String> attributes) { - // format of string passed to native C code: - // "attrCnt attr1=valueLen value1attr2=value2Len value2..." - // example: - // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO" - StringBuilder sb = new StringBuilder(); - int size = attributes.size(); - if (attributes.containsKey("hasThumbnail")) { - --size; - } - sb.append(size + " "); - for (Map.Entry<String, String> iter : attributes.entrySet()) { - String key = iter.getKey(); - if (key.equals("hasThumbnail")) { - // this is a fake attribute not saved as an exif tag - continue; - } - String val = iter.getValue(); - sb.append(key + "="); - sb.append(val.length() + " "); - sb.append(val); - } - String s = sb.toString(); - saveAttributesNative(mFilename, s); - commitChangesNative(mFilename); - mSavedAttributes = true; + public void setAttribute(String tag, String value) { + mAttributes.put(tag, value); } /** - * Returns a HashMap loaded with the Exif attributes of the file. The key - * is the standard tag name and the value is the tag's value: e.g. - * Model -> Nikon. Numeric values are returned as strings. + * Initialize mAttributes with the attributes from the file mFilename. + * + * mAttributes is a HashMap which stores the Exif attributes of the file. + * The key is the standard tag name and the value is the tag's value: e.g. + * Model -> Nikon. Numeric values are stored as strings. + * + * This function also initialize mHasThumbnail to indicate whether the + * file has a thumbnail inside. */ - public HashMap<String, String> getAttributes() { - if (mCachedAttributes != null) { - return mCachedAttributes; - } + private void loadAttributes() { // format of string passed from native C code: // "attrCnt attr1=valueLen value1attr2=value2Len value2..." // example: // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO" - mCachedAttributes = new HashMap<String, String>(); + mAttributes = new HashMap<String, String>(); - String attrStr = getAttributesNative(mFilename); + String attrStr; + synchronized (sLock) { + attrStr = getAttributesNative(mFilename); + } // get count int ptr = attrStr.indexOf(' '); @@ -215,17 +145,78 @@ public class ExifInterface { if (attrName.equals("hasThumbnail")) { mHasThumbnail = attrValue.equalsIgnoreCase("true"); } else { - mCachedAttributes.put(attrName, attrValue); + mAttributes.put(attrName, attrValue); } } - return mCachedAttributes; } /** - * Given a numerical white balance value, return a - * human-readable string describing it. + * Save the tag data into the JPEG file. This is expensive because it involves + * copying all the JPG data from one file to another and deleting the old file + * and renaming the other. It's best to use {@link #setAttribute(String,String)} to set all + * attributes to write and make a single call rather than multiple calls for + * each attribute. */ - public static String whiteBalanceToString(int whitebalance) { + public void saveAttributes() throws IOException { + // format of string passed to native C code: + // "attrCnt attr1=valueLen value1attr2=value2Len value2..." + // example: + // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO" + StringBuilder sb = new StringBuilder(); + int size = mAttributes.size(); + if (mAttributes.containsKey("hasThumbnail")) { + --size; + } + sb.append(size + " "); + for (Map.Entry<String, String> iter : mAttributes.entrySet()) { + String key = iter.getKey(); + if (key.equals("hasThumbnail")) { + // this is a fake attribute not saved as an exif tag + continue; + } + String val = iter.getValue(); + sb.append(key + "="); + sb.append(val.length() + " "); + sb.append(val); + } + String s = sb.toString(); + synchronized (sLock) { + saveAttributesNative(mFilename, s); + commitChangesNative(mFilename); + } + } + + /** + * Returns true if the JPEG file has a thumbnail. + */ + public boolean hasThumbnail() { + return mHasThumbnail; + } + + /** + * Returns the thumbnail inside the JPEG file, or {@code null} if there is no thumbnail. + */ + public byte[] getThumbnail() { + synchronized (sLock) { + return getThumbnailNative(mFilename); + } + } + + /** + * Returns a human-readable string describing the white balance value. Returns empty + * string if there is no white balance value or it is not recognized. + */ + public String getWhiteBalanceString() { + String value = getAttribute(TAG_WHITE_BALANCE); + if (value == null) return ""; + + int whitebalance; + try { + whitebalance = Integer.parseInt(value); + } catch (NumberFormatException ex) { + return ""; + } + switch (whitebalance) { case WHITEBALANCE_AUTO: return "Auto"; @@ -237,12 +228,21 @@ public class ExifInterface { } /** - * Given a numerical orientation, return a human-readable string describing - * the orientation. + * Returns a human-readable string describing the orientation value. Returns empty + * string if there is no orientation value or it it not recognized. */ - public static String orientationToString(int orientation) { - // TODO: this function needs to be localized and use string resource ids - // rather than strings + public String getOrientationString() { + // TODO: this function needs to be localized. + String value = getAttribute(TAG_ORIENTATION); + if (value == null) return ""; + + int orientation; + try { + orientation = Integer.parseInt(value); + } catch (NumberFormatException ex) { + return ""; + } + String orientationString; switch (orientation) { case ORIENTATION_NORMAL: @@ -277,48 +277,21 @@ public class ExifInterface { } /** - * Copies the thumbnail data out of the filename and puts it in the Exif - * data associated with the file used to create this object. You must call - * "commitChanges()" at some point to commit the changes. + * Returns the latitude and longitude value in a float array. The first element is + * the latitude, and the second element is the longitude. */ - public boolean appendThumbnail(String thumbnailFileName) { - if (!mSavedAttributes) { - throw new RuntimeException("Must call saveAttributes " - + "before calling appendThumbnail"); - } - mHasThumbnail = appendThumbnailNative(mFilename, thumbnailFileName); - return mHasThumbnail; - } - - public boolean hasThumbnail() { - if (!mSavedAttributes) { - getAttributes(); - } - return mHasThumbnail; - } - - public byte[] getThumbnail() { - return getThumbnailNative(mFilename); - } - - public static float[] getLatLng(HashMap<String, String> exifData) { - if (exifData == null) { - return null; - } - - String latValue = exifData.get(ExifInterface.TAG_GPS_LATITUDE); - String latRef = exifData.get(ExifInterface.TAG_GPS_LATITUDE_REF); - String lngValue = exifData.get(ExifInterface.TAG_GPS_LONGITUDE); - String lngRef = exifData.get(ExifInterface.TAG_GPS_LONGITUDE_REF); + public float[] getLatLong() { + String latValue = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE); + String latRef = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE_REF); + String lngValue = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE); + String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF); float[] latlng = null; if (latValue != null && latRef != null && lngValue != null && lngRef != null) { latlng = new float[2]; - latlng[0] = ExifInterface.convertRationalLatLonToFloat( - latValue, latRef); - latlng[1] = ExifInterface.convertRationalLatLonToFloat( - lngValue, lngRef); + latlng[0] = convertRationalLatLonToFloat(latValue, latRef); + latlng[1] = convertRationalLatLonToFloat(lngValue, lngRef); } return latlng; @@ -327,14 +300,12 @@ public class ExifInterface { private static SimpleDateFormat sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); - // Returns number of milliseconds since Jan. 1, 1970, midnight GMT. - // Returns -1 if the date time information if not available. - public static long getDateTime(HashMap<String, String> exifData) { - if (exifData == null) { - return -1; - } - - String dateTimeString = exifData.get(ExifInterface.TAG_DATETIME); + /** + * Returns number of milliseconds since Jan. 1, 1970, midnight GMT. + * Returns -1 if the date time information if not available. + */ + public long getDateTime() { + String dateTimeString = mAttributes.get(TAG_DATETIME); if (dateTimeString == null) return -1; ParsePosition pos = new ParsePosition(0); @@ -347,7 +318,7 @@ public class ExifInterface { } } - public static float convertRationalLatLonToFloat( + private static float convertRationalLatLonToFloat( String rationalString, String ref) { try { String [] parts = rationalString.split(","); @@ -377,42 +348,6 @@ public class ExifInterface { } } - public static String convertRationalLatLonToDecimalString( - String rationalString, String ref, boolean usePositiveNegative) { - float result = convertRationalLatLonToFloat(rationalString, ref); - - String preliminaryResult = String.valueOf(result); - if (usePositiveNegative) { - String neg = (ref.equals("S") || ref.equals("E")) ? "-" : ""; - return neg + preliminaryResult; - } else { - return preliminaryResult + String.valueOf((char) 186) + " " - + ref; - } - } - - public static String makeLatLongString(double d) { - d = Math.abs(d); - - int degrees = (int) d; - - double remainder = d - degrees; - int minutes = (int) (remainder * 60D); - // really seconds * 1000 - int seconds = (int) (((remainder * 60D) - minutes) * 60D * 1000D); - - String retVal = degrees + "/1," + minutes + "/1," + seconds + "/1000"; - return retVal; - } - - public static String makeLatStringRef(double lat) { - return lat >= 0D ? "N" : "S"; - } - - public static String makeLonStringRef(double lon) { - return lon >= 0D ? "W" : "E"; - } - private native boolean appendThumbnailNative(String fileName, String thumbnailFileName); diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index f6d30e0..d9127e7 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -719,16 +719,20 @@ public class MediaScanner values.put(Audio.Media.IS_MUSIC, music); values.put(Audio.Media.IS_PODCAST, podcasts); } else if (mFileType == MediaFile.FILE_TYPE_JPEG) { - HashMap<String, String> exifData = - ExifInterface.loadExifData(entry.mPath); - if (exifData != null) { - float[] latlng = ExifInterface.getLatLng(exifData); + ExifInterface exif = null; + try { + exif = new ExifInterface(entry.mPath); + } catch (IOException ex) { + // exif is null + } + if (exif != null) { + float[] latlng = exif.getLatLong(); if (latlng != null) { values.put(Images.Media.LATITUDE, latlng[0]); values.put(Images.Media.LONGITUDE, latlng[1]); } - long time = ExifInterface.getDateTime(exifData); + long time = exif.getDateTime(); if (time != -1) { values.put(Images.Media.DATE_TAKEN, time); } diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp index a1c478f..4ed6869 100644 --- a/media/libstagefright/omx/SoftwareRenderer.cpp +++ b/media/libstagefright/omx/SoftwareRenderer.cpp @@ -65,6 +65,8 @@ SoftwareRenderer::~SoftwareRenderer() { void SoftwareRenderer::render( const void *data, size_t size, void *platformPrivate) { + static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00; + switch (mColorFormat) { case OMX_COLOR_FormatYUV420Planar: return renderYUV420Planar(data, size); @@ -72,6 +74,9 @@ void SoftwareRenderer::render( case OMX_COLOR_FormatCbYCrY: return renderCbYCrY(data, size); + case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: + return renderQCOMYUV420SemiPlanar(data, size); + default: { LOGW("Cannot render color format %ld", mColorFormat); @@ -242,6 +247,76 @@ void SoftwareRenderer::renderCbYCrY( mIndex = 1 - mIndex; } +void SoftwareRenderer::renderQCOMYUV420SemiPlanar( + const void *data, size_t size) { + if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) { + LOGE("size is %d, expected %d", + size, (mDecodedHeight * mDecodedWidth * 3) / 2); + } + CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2); + + uint8_t *kAdjustedClip = initClip(); + + size_t offset = mIndex * mFrameSize; + + void *dst = (uint8_t *)mMemoryHeap->getBase() + offset; + + uint32_t *dst_ptr = (uint32_t *)dst; + + const uint8_t *src_y = (const uint8_t *)data; + + const uint8_t *src_u = + (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight; + + for (size_t y = 0; y < mDecodedHeight; ++y) { + for (size_t x = 0; x < mDecodedWidth; x += 2) { + signed y1 = (signed)src_y[x] - 16; + signed y2 = (signed)src_y[x + 1] - 16; + + signed u = (signed)src_u[x & ~1] - 128; + signed v = (signed)src_u[(x & ~1) + 1] - 128; + + signed u_b = u * 517; + signed u_g = -u * 100; + signed v_g = -v * 208; + signed v_r = v * 409; + + signed tmp1 = y1 * 298; + signed b1 = (tmp1 + u_b) / 256; + signed g1 = (tmp1 + v_g + u_g) / 256; + signed r1 = (tmp1 + v_r) / 256; + + signed tmp2 = y2 * 298; + signed b2 = (tmp2 + u_b) / 256; + signed g2 = (tmp2 + v_g + u_g) / 256; + signed r2 = (tmp2 + v_r) / 256; + + uint32_t rgb1 = + ((kAdjustedClip[b1] >> 3) << 11) + | ((kAdjustedClip[g1] >> 2) << 5) + | (kAdjustedClip[r1] >> 3); + + uint32_t rgb2 = + ((kAdjustedClip[b2] >> 3) << 11) + | ((kAdjustedClip[g2] >> 2) << 5) + | (kAdjustedClip[r2] >> 3); + + dst_ptr[x / 2] = (rgb2 << 16) | rgb1; + } + + src_y += mDecodedWidth; + + if (y & 1) { + src_u += mDecodedWidth; + } + + dst_ptr += mDecodedWidth / 2; + } + + mISurface->postBuffer(offset); + mIndex = 1 - mIndex; +} + uint8_t *SoftwareRenderer::initClip() { static const signed kClipMin = -278; static const signed kClipMax = 535; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java index a86ef8f9..ef211b3 100755 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java @@ -406,7 +406,7 @@ public class MediaNames { public static final String META_DATA_OTHERS [][] = { {"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null, null, null, "20080309T002415.000Z", null, - null, null, "1404928", "2", null}, + null, null, "63916", "2", null}, {"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null, null, null, null, null, null, null, "126540", "1", null}, @@ -424,7 +424,7 @@ public class MediaNames { null, null, "2005", "231180", "1", null}, {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", "2/0", "mp4 album Kung Fu Panda", "mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z", - "41", "Kung Fu Panda", "2008", "77113", "2", "mp4 composer"}, + "41", "Kung Fu Panda", "2008", "128521", "2", "mp4 composer"}, {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", "John Petrucci", null, null, "20070510T125223.000Z", null, null, "2005", "231180", "1", null}, diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index 705794a..f969a46 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -33,11 +33,45 @@ using namespace android; static void printGLString(const char *name, GLenum s) { + fprintf(stderr, "printGLString %s, %d\n", name, s); const char *v = (const char *)glGetString(s); - if (v) - printf("GL %s = %s\n", name, v); + int error = glGetError(); + fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error, + (unsigned int)v); + if ((v < (const char*) 0) || (v > (const char*) 0x1000)) + fprintf(stderr, "GL %s = %s\n", name, v); else - printf("GL %s = (null)\n", name); + fprintf(stderr, "GL %s = (null)\n", name); +} + +static const char* eglErrorToString[] = { + "EGL_SUCCESS", // 0x3000 12288 + "EGL_NOT_INITIALIZED", + "EGL_BAD_ACCESS", // 0x3002 12290 + "EGL_BAD_ALLOC", + "EGL_BAD_ATTRIBUTE", + "EGL_BAD_CONFIG", + "EGL_BAD_CONTEXT", // 0x3006 12294 + "EGL_BAD_CURRENT_SURFACE", + "EGL_BAD_DISPLAY", + "EGL_BAD_MATCH", + "EGL_BAD_NATIVE_PIXMAP", + "EGL_BAD_NATIVE_WINDOW", + "EGL_BAD_PARAMETER", // 0x300c 12300 + "EGL_BAD_SURFACE" +}; + +static void checkEglError(const char* op) { + for(EGLint error = eglGetError(); + error != EGL_SUCCESS; + error = eglGetError()) { + const char* errorString = "unknown"; + if (error >= EGL_SUCCESS && error <= EGL_BAD_SURFACE) { + errorString = eglErrorToString[error - EGL_SUCCESS]; + } + fprintf(stderr, "%s() returned eglError %s (0x%x)\n", op, + errorString, error); + } } int main(int argc, char** argv) @@ -63,19 +97,33 @@ int main(int argc, char** argv) EGLNativeWindowType window = 0; window = android_createDisplaySurface(); + checkEglError("<init>"); dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + checkEglError("eglGetDisplay"); eglInitialize(dpy, &majorVersion, &minorVersion); + checkEglError("eglInitialize"); + fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion); EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &config); + fprintf(stderr, "Chosen config: 0x%08x\n", (unsigned long) config); + + checkEglError("EGLUtils::selectConfigForNativeWindow"); surface = eglCreateWindowSurface(dpy, config, window, NULL); + checkEglError("eglCreateWindowSurface"); - EGLint gl2_0Attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + EGLint gl2_0Attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; context = eglCreateContext(dpy, config, NULL, gl2_0Attribs); + checkEglError("eglCreateContext"); eglMakeCurrent(dpy, surface, surface, context); + checkEglError("eglMakeCurrent"); eglQuerySurface(dpy, surface, EGL_WIDTH, &w); + checkEglError("eglQuerySurface"); eglQuerySurface(dpy, surface, EGL_HEIGHT, &h); + checkEglError("eglQuerySurface"); GLint dim = w<h ? w : h; + fprintf(stderr, "Window dimensions: %d x %d\n", w, h); + printGLString("Version", GL_VERSION); printGLString("Vendor", GL_VENDOR); printGLString("Renderer", GL_RENDERER); diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java index 30c25e0..60195b9 100644 --- a/services/java/com/android/server/DockObserver.java +++ b/services/java/com/android/server/DockObserver.java @@ -16,6 +16,7 @@ package com.android.server; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.os.Handler; @@ -111,6 +112,30 @@ class DockObserver extends UEventObserver { Intent intent = new Intent(Intent.ACTION_DOCK_EVENT); intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState); mContext.sendStickyBroadcast(intent); + + // Launch a dock activity + String category; + switch (mDockState) { + case Intent.EXTRA_DOCK_STATE_CAR: + category = Intent.CATEGORY_CAR_DOCK; + break; + case Intent.EXTRA_DOCK_STATE_DESK: + category = Intent.CATEGORY_DESK_DOCK; + break; + default: + category = null; + break; + } + if (category != null) { + intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(category); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, e.getCause()); + } + } } } }; diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 82cf1bc..45e0ceb 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -3611,9 +3611,18 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); - PackageInstalledInfo res; - synchronized (mInstallLock) { - res = installPackageLI(packageURI, flags, true, installerPackageName); + // Result object to be returned + PackageInstalledInfo res = new PackageInstalledInfo(); + res.returnCode = PackageManager.INSTALL_SUCCEEDED; + res.uid = -1; + res.pkg = null; + res.removedInfo = new PackageRemovedInfo(); + // Make a temporary copy of file from given packageURI + File tmpPackageFile = copyTempInstallFile(packageURI, res); + if (tmpPackageFile != null) { + synchronized (mInstallLock) { + installPackageLI(packageURI, flags, true, installerPackageName, tmpPackageFile, res); + } } if (observer != null) { try { @@ -3828,11 +3837,30 @@ class PackageManagerService extends IPackageManager.Stub { // Since we failed to install the new package we need to restore the old // package that we deleted. if(deletedPkg) { + File restoreFile = new File(deletedPackage.mPath); + if (restoreFile == null) { + Log.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName); + return; + } + File restoreTmpFile = createTempPackageFile(); + if (restoreTmpFile == null) { + Log.e(TAG, "Failed creating temp file when restoring pkg : " + pkgName); + return; + } + if (!FileUtils.copyFile(restoreFile, restoreTmpFile)) { + Log.e(TAG, "Failed copying temp file when restoring pkg : " + pkgName); + return; + } + PackageInstalledInfo restoreRes = new PackageInstalledInfo(); + restoreRes.removedInfo = new PackageRemovedInfo(); installPackageLI( - Uri.fromFile(new File(deletedPackage.mPath)), + Uri.fromFile(restoreFile), isForwardLocked(deletedPackage) ? PackageManager.INSTALL_FORWARD_LOCK - : 0, false, oldInstallerPackageName); + : 0, false, oldInstallerPackageName, restoreTmpFile, restoreRes); + if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) { + Log.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade"); + } } } } @@ -3995,50 +4023,36 @@ class PackageManagerService extends IPackageManager.Stub { return new File(mAppInstallDir, publicZipFileName); } - private PackageInstalledInfo installPackageLI(Uri pPackageURI, - int pFlags, boolean newInstall, String installerPackageName) { - File tmpPackageFile = null; - String pkgName = null; - boolean forwardLocked = false; - boolean replacingExistingPackage = false; - // Result object to be returned - PackageInstalledInfo res = new PackageInstalledInfo(); - res.returnCode = PackageManager.INSTALL_SUCCEEDED; - res.uid = -1; - res.pkg = null; - res.removedInfo = new PackageRemovedInfo(); + private File copyTempInstallFile(Uri pPackageURI, + PackageInstalledInfo res) { + File tmpPackageFile = createTempPackageFile(); + int retCode = PackageManager.INSTALL_SUCCEEDED; + if (tmpPackageFile == null) { + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + return null; + } - main_flow: try { - tmpPackageFile = createTempPackageFile(); - if (tmpPackageFile == null) { - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; + if (pPackageURI.getScheme().equals("file")) { + final File srcPackageFile = new File(pPackageURI.getPath()); + // We copy the source package file to a temp file and then rename it to the + // destination file in order to eliminate a window where the package directory + // scanner notices the new package file but it's not completely copied yet. + if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) { + Log.e(TAG, "Couldn't copy package file to temp file."); + retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } - tmpPackageFile.deleteOnExit(); // paranoia - if (pPackageURI.getScheme().equals("file")) { - final File srcPackageFile = new File(pPackageURI.getPath()); - // We copy the source package file to a temp file and then rename it to the - // destination file in order to eliminate a window where the package directory - // scanner notices the new package file but it's not completely copied yet. - if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) { - Log.e(TAG, "Couldn't copy package file to temp file."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - } else if (pPackageURI.getScheme().equals("content")) { - ParcelFileDescriptor fd; - try { - fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r"); - } catch (FileNotFoundException e) { - Log.e(TAG, "Couldn't open file descriptor from download service."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - if (fd == null) { - Log.e(TAG, "Couldn't open file descriptor from download service (null)."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } + } else if (pPackageURI.getScheme().equals("content")) { + ParcelFileDescriptor fd = null; + try { + fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r"); + } catch (FileNotFoundException e) { + Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e); + retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } + if (fd == null) { + Log.e(TAG, "Couldn't open file descriptor from download service (null)."); + retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + } else { if (Config.LOGV) { Log.v(TAG, "Opened file descriptor from download service."); } @@ -4049,14 +4063,34 @@ class PackageManagerService extends IPackageManager.Stub { // scanner notices the new package file but it's not completely copied yet. if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) { Log.e(TAG, "Couldn't copy package stream to temp file."); - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; + retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; } - } else { - Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI); - res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI; - break main_flow; } + } else { + Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI); + retCode = PackageManager.INSTALL_FAILED_INVALID_URI; + } + + res.returnCode = retCode; + if (retCode != PackageManager.INSTALL_SUCCEEDED) { + if (tmpPackageFile != null && tmpPackageFile.exists()) { + tmpPackageFile.delete(); + } + return null; + } + return tmpPackageFile; + } + + private void installPackageLI(Uri pPackageURI, + int pFlags, boolean newInstall, String installerPackageName, + File tmpPackageFile, PackageInstalledInfo res) { + String pkgName = null; + boolean forwardLocked = false; + boolean replacingExistingPackage = false; + // Result object to be returned + res.returnCode = PackageManager.INSTALL_SUCCEEDED; + + main_flow: try { pkgName = PackageParser.parsePackageName( tmpPackageFile.getAbsolutePath(), 0); if (pkgName == null) { @@ -4128,7 +4162,6 @@ class PackageManagerService extends IPackageManager.Stub { tmpPackageFile.delete(); } } - return res; } private int setPermissionsLI(String pkgName, diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 53ff78e..63bef54 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -665,6 +665,15 @@ public class WifiService extends IWifiManager.Stub { } } } + + for (WifiConfiguration.EnterpriseField field : + config.enterpriseFields) { + value = WifiNative.getNetworkVariableCommand(netId, + field.varName()); + if (!TextUtils.isEmpty(value)) { + field.setValue(value); + } + } } /** @@ -877,103 +886,20 @@ public class WifiService extends IWifiManager.Stub { break setVariables; } - if ((config.eap != null) && !WifiNative.setNetworkVariableCommand( + for (WifiConfiguration.EnterpriseField field + : config.enterpriseFields) { + String varName = field.varName(); + String value = field.value(); + if ((value != null) && !WifiNative.setNetworkVariableCommand( netId, - WifiConfiguration.eapVarName, - config.eap)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set eap: "+ - config.eap); - } - break setVariables; - } - - if ((config.phase2 != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.phase2VarName, - config.phase2)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set phase2: "+ - config.phase2); - } - break setVariables; - } - - if ((config.identity != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.identityVarName, - config.identity)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set identity: "+ - config.identity); - } - break setVariables; - } - - if ((config.anonymousIdentity != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.anonymousIdentityVarName, - config.anonymousIdentity)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set anonymousIdentity: "+ - config.anonymousIdentity); - } - break setVariables; - } - - if ((config.password != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.passwordVarName, - config.password)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set password: "+ - config.password); - } - break setVariables; - } - - if ((config.clientCert != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.clientCertVarName, - config.clientCert)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set clientCert: "+ - config.clientCert); - } - break setVariables; - } - - if ((config.caCert != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.caCertVarName, - config.caCert)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set caCert: "+ - config.caCert); - } - break setVariables; - } - - if ((config.privateKey != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.privateKeyVarName, - config.privateKey)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set privateKey: "+ - config.privateKey); - } - break setVariables; - } - - if ((config.privateKeyPasswd != null) && !WifiNative.setNetworkVariableCommand( - netId, - WifiConfiguration.privateKeyPasswdVarName, - config.privateKeyPasswd)) { - if (DBG) { - Log.d(TAG, config.SSID + ": failed to set privateKeyPasswd: "+ - config.privateKeyPasswd); + varName, + value)) { + if (DBG) { + Log.d(TAG, config.SSID + ": failed to set " + varName + + ": " + value); + } + break setVariables; } - break setVariables; } return netId; diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 8e85a6a..60496d6 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -442,6 +442,8 @@ public class WindowManagerService extends IWindowManager.Stub // Who is holding the screen on. Session mHoldingScreenOn; + boolean mTurnOnScreen; + /** * Whether the UI is currently running in touch mode (not showing * navigational focus because the user is directly pressing the screen). @@ -1244,12 +1246,6 @@ public class WindowManagerService extends IWindowManager.Stub "Skipping hidden or animating token: " + w); continue; } - // If this window's app token is ot fullscreen, also irrelevant. - if (!w.mAppToken.appFullscreen) { - if (DEBUG_WALLPAPER) Log.v(TAG, - "Skipping non-fullscreen token: " + w); - continue; - } } if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w + ": readyfordisplay=" + w.isReadyForDisplay() + " drawpending=" + w.mDrawPending @@ -2214,6 +2210,10 @@ public class WindowManagerService extends IWindowManager.Stub && !win.mCommitDrawPending && !mDisplayFrozen) { applyEnterAnimationLocked(win); } + if (displayed && (win.mAttrs.flags + & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) { + win.mTurnOnScreen = true; + } if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) { // To change the format, we need to re-build the surface. win.destroySurfaceLocked(); @@ -6485,6 +6485,7 @@ public class WindowManagerService extends IWindowManager.Stub int mLastLayer; boolean mHaveFrame; boolean mObscured; + boolean mTurnOnScreen; WindowState mNextOutsideTouch; @@ -7716,10 +7717,11 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mDestroying="); pw.print(mDestroying); pw.print(" mRemoved="); pw.println(mRemoved); } - if (mOrientationChanging || mAppFreezing) { + if (mOrientationChanging || mAppFreezing || mTurnOnScreen) { pw.print(prefix); pw.print("mOrientationChanging="); pw.print(mOrientationChanging); - pw.print(" mAppFreezing="); pw.println(mAppFreezing); + pw.print(" mAppFreezing="); pw.print(mAppFreezing); + pw.print(" mTurnOnScreen="); pw.println(mTurnOnScreen); } if (mHScale != 1 || mVScale != 1) { pw.print(prefix); pw.print("mHScale="); pw.print(mHScale); @@ -9788,6 +9790,12 @@ public class WindowManagerService extends IWindowManager.Stub Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen); mH.sendMessage(m); } + + if (mTurnOnScreen) { + mPowerManager.userActivity(SystemClock.uptimeMillis(), false, + LocalPowerManager.BUTTON_EVENT, true); + mTurnOnScreen = false; + } } void requestAnimationLocked(long delay) { @@ -9809,6 +9817,10 @@ public class WindowManagerService extends IWindowManager.Stub try { if (win.mSurface != null) { win.mSurface.show(); + if (win.mTurnOnScreen) { + win.mTurnOnScreen = false; + mTurnOnScreen = true; + } } return true; } catch (RuntimeException e) { diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index d680b8a..83552dd 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -1490,10 +1490,13 @@ public class StatusBarService extends IStatusBar.Stub /// ---------- Expanded View -------------- pixelFormat = PixelFormat.TRANSLUCENT; - if (false) { - bg = mExpandedView.getBackground(); - if (bg != null) { - pixelFormat = bg.getOpacity(); + bg = mExpandedView.getBackground(); + if (bg != null) { + pixelFormat = bg.getOpacity(); + if (pixelFormat != PixelFormat.TRANSLUCENT) { + // we want good-looking gradients, so we force a 8-bits per + // pixel format. + pixelFormat = PixelFormat.RGBX_8888; } } diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 4368464..2672c6d 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -129,6 +129,8 @@ public class PhoneNumberUtils return uri.getSchemeSpecificPart(); } + // TODO: We don't check for SecurityException here (requires + // READ_PHONE_STATE permission). if (scheme.equals("voicemail")) { return TelephonyManager.getDefault().getVoiceMailNumber(); } @@ -1179,6 +1181,35 @@ public class PhoneNumberUtils } /** + * isVoiceMailNumber: checks a given number against the voicemail + * number provided by the RIL and SIM card. The caller must have + * the READ_PHONE_STATE credential. + * + * @param number the number to look up. + * @return true if the number is in the list of voicemail. False + * otherwise, including if the caller does not have the permission + * to read the VM number. + * @hide TODO: pending API Council approval + */ + public static boolean isVoiceMailNumber(String number) { + String vmNumber; + + try { + vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(); + } catch (SecurityException ex) { + return false; + } + + // Strip the separators from the number before comparing it + // to the list. + number = extractNetworkPortion(number); + + // compare tolerates null so we need to make sure that we + // don't return true when both are null. + return !TextUtils.isEmpty(number) && compare(number, vmNumber); + } + + /** * Translates any alphabetic letters (i.e. [A-Za-z]) in the * specified phone number into the equivalent numeric digits, * according to the phone keypad letter mapping described in diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index e1bd1db..01b1746 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -100,10 +100,13 @@ public class CallerInfo { public Drawable cachedPhoto; public boolean isCachedPhotoCurrent; - // Don't keep checking VM if it's going to throw an exception for this proc. - private static boolean sSkipVmCheck = false; + private boolean mIsEmergency; + private boolean mIsVoiceMail; public CallerInfo() { + // TODO: Move all the basic initialization here? + mIsEmergency = false; + mIsVoiceMail = false; } /** @@ -216,38 +219,15 @@ public class CallerInfo { public static CallerInfo getCallerInfo(Context context, String number) { if (TextUtils.isEmpty(number)) { return null; - } else { - // Change the callerInfo number ONLY if it is an emergency number - // or if it is the voicemail number. If it is either, take a - // shortcut and skip the query. - if (PhoneNumberUtils.isEmergencyNumber(number)) { - CallerInfo ci = new CallerInfo(); - - // Note we're setting the phone number here (refer to javadoc - // comments at the top of CallerInfo class). - ci.phoneNumber = context.getString( - com.android.internal.R.string.emergency_call_dialog_number_for_display); - return ci; - } else { - try { - if (!sSkipVmCheck && PhoneNumberUtils.compare(number, - TelephonyManager.getDefault().getVoiceMailNumber())) { - CallerInfo ci = new CallerInfo(); - - // Note we're setting the phone number here (refer to javadoc - // comments at the top of CallerInfo class). - ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag(); - // TODO: FIND ANOTHER ICON - //info.photoResource = android.R.drawable.badge_voicemail; - return ci; - } - } catch (SecurityException ex) { - // Don't crash if this process doesn't have permission to - // retrieve VM number. It's still allowed to look up caller info. - // But don't try it again. - sSkipVmCheck = true; - } - } + } + + // Change the callerInfo number ONLY if it is an emergency number + // or if it is the voicemail number. If it is either, take a + // shortcut and skip the query. + if (PhoneNumberUtils.isEmergencyNumber(number)) { + return new CallerInfo().markAsEmergency(context); + } else if (PhoneNumberUtils.isVoiceMailNumber(number)) { + return new CallerInfo().markAsVoiceMail(); } Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)); @@ -296,6 +276,73 @@ public class CallerInfo { return callerID; } + // Accessors + + /** + * @return true if the caller info is an emergency number. + */ + public boolean isEmergencyNumber() { + return mIsEmergency; + } + + /** + * @return true if the caller info is a voicemail number. + */ + public boolean isVoiceMailNumber() { + return mIsVoiceMail; + } + + /** + * Mark this CallerInfo as an emergency call. + * @param context To lookup the localized 'Emergency Number' string. + * @return this instance. + */ + // TODO: Note we're setting the phone number here (refer to + // javadoc comments at the top of CallerInfo class) to a localized + // string 'Emergency Number'. This is pretty bad because we are + // making UI work here instead of just packaging the data. We + // should set the phone number to the dialed number and name to + // 'Emergency Number' and let the UI make the decision about what + // should be displayed. + /* package */ CallerInfo markAsEmergency(Context context) { + phoneNumber = context.getString( + com.android.internal.R.string.emergency_call_dialog_number_for_display); + photoResource = com.android.internal.R.drawable.picture_emergency; + mIsEmergency = true; + return this; + } + + + /** + * Mark this CallerInfo as a voicemail call. The voicemail label + * is obtained from the telephony manager. Caller must hold the + * READ_PHONE_STATE permission otherwise the phoneNumber will be + * set to null. + * @return this instance. + */ + // TODO: As in the emergency number handling, we end up writing a + // string in the phone number field. + /* package */ CallerInfo markAsVoiceMail() { + mIsVoiceMail = true; + + try { + String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag(); + + phoneNumber = voiceMailLabel; + } catch (SecurityException se) { + // Should never happen: if this process does not have + // permission to retrieve VM tag, it should not have + // permission to retrieve VM number and would not call + // this method. + // Leave phoneNumber untouched. + Log.e(TAG, "Cannot access VoiceMail.", se); + } + // TODO: There is no voicemail picture? + // FIXME: FIND ANOTHER ICON + // photoResource = android.R.drawable.badge_voicemail; + return this; + } + private static String normalize(String s) { if (s == null || s.length() > 0) { return s; @@ -303,4 +350,31 @@ public class CallerInfo { return null; } } + + /** + * @return a string debug representation of this instance. + */ + public String toString() { + return new StringBuilder(384) + .append("\nname: " + name) + .append("\nphoneNumber: " + phoneNumber) + .append("\ncnapName: " + cnapName) + .append("\nnumberPresentation: " + numberPresentation) + .append("\nnamePresentation: " + namePresentation) + .append("\ncontactExits: " + contactExists) + .append("\nphoneLabel: " + phoneLabel) + .append("\nnumberType: " + numberType) + .append("\nnumberLabel: " + numberLabel) + .append("\nphotoResource: " + photoResource) + .append("\nperson_id: " + person_id) + .append("\nneedUpdate: " + needUpdate) + .append("\ncontactRefUri: " + contactRefUri) + .append("\ncontactRingtoneUri: " + contactRefUri) + .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail) + .append("\ncachedPhoto: " + cachedPhoto) + .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent) + .append("\nemergency: " + mIsEmergency) + .append("\nvoicemail " + mIsVoiceMail) + .toString(); + } } diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 3d4f78c..802e79b 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -37,7 +37,7 @@ import android.util.Log; public class CallerInfoAsyncQuery { private static final boolean DBG = false; - private static final String LOG_TAG = "PHONE"; + private static final String LOG_TAG = "CallerInfoAsyncQuery"; private static final int EVENT_NEW_QUERY = 1; private static final int EVENT_ADD_LISTENER = 2; @@ -47,9 +47,6 @@ public class CallerInfoAsyncQuery { private CallerInfoAsyncQueryHandler mHandler; - // Don't keep checking VM if it's going to throw an exception for this proc. - private static boolean sSkipVmCheck = false; - /** * Interface for a CallerInfoAsyncQueryHandler result return. */ @@ -223,26 +220,11 @@ public class CallerInfoAsyncQuery { // voicemail number, and adjust other data (including photoResource) // accordingly. if (cw.event == EVENT_EMERGENCY_NUMBER) { - mCallerInfo = new CallerInfo(); // Note we're setting the phone number here (refer to javadoc // comments at the top of CallerInfo class). - mCallerInfo.phoneNumber = mQueryContext.getString(com.android.internal - .R.string.emergency_call_dialog_number_for_display); - mCallerInfo.photoResource = com.android.internal.R.drawable.picture_emergency; - + mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext); } else if (cw.event == EVENT_VOICEMAIL_NUMBER) { - mCallerInfo = new CallerInfo(); - try { - // Note we're setting the phone number here (refer to javadoc - // comments at the top of CallerInfo class). - mCallerInfo.phoneNumber = - TelephonyManager.getDefault().getVoiceMailAlphaTag(); - } catch (SecurityException ex) { - // Should never happen: if this process does not have - // permission to retrieve VM tag, it should not have - // permission to retrieve VM number and would not generate - // an EVENT_VOICEMAIL_NUMBER. But if it happens, don't crash. - } + mCallerInfo = new CallerInfo().markAsVoiceMail(); } else { mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor); // Use the number entered by the user for display. @@ -262,7 +244,7 @@ public class CallerInfoAsyncQuery { //notify the listener that the query is complete. if (cw.listener != null) { if (DBG) log("notifying listener: " + cw.listener.getClass().toString() + - " for token: " + token); + " for token: " + token + mCallerInfo); cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo); } } @@ -319,23 +301,10 @@ public class CallerInfoAsyncQuery { // check to see if these are recognized numbers, and use shortcuts if we can. if (PhoneNumberUtils.isEmergencyNumber(number)) { cw.event = EVENT_EMERGENCY_NUMBER; + } else if (PhoneNumberUtils.isVoiceMailNumber(number)) { + cw.event = EVENT_VOICEMAIL_NUMBER; } else { - String vmNumber = null; - if (!sSkipVmCheck){ - try { - vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(); - } catch (SecurityException ex) { - // Don't crash if this process doesn't have permission to - // retrieve VM number. It's still allowed to look up caller info. - // But don't try it again. - sSkipVmCheck = true; - } - } - if (PhoneNumberUtils.compare(number, vmNumber)) { - cw.event = EVENT_VOICEMAIL_NUMBER; - } else { - cw.event = EVENT_NEW_QUERY; - } + cw.event = EVENT_NEW_QUERY; } c.mHandler.startQuery (token, cw, contactRef, null, null, null, null); @@ -390,4 +359,3 @@ public class CallerInfoAsyncQuery { Log.d(LOG_TAG, msg); } } - diff --git a/telephony/tests/TelephonyTest/Android.mk b/telephony/tests/TelephonyTest/Android.mk new file mode 100644 index 0000000..1ef8448 --- /dev/null +++ b/telephony/tests/TelephonyTest/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := telephonytest + +include $(BUILD_PACKAGE) diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/TelephonyTest/AndroidManifest.xml new file mode 100644 index 0000000..b2a481b --- /dev/null +++ b/telephony/tests/TelephonyTest/AndroidManifest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Copyright (C) 2009 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.telephonytest"> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:label="TelephonyTest" + android:name="TelephonyTest"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> + <instrumentation android:name=".TelephonyUnitTestRunner" + android:targetPackage="com.android.telephonytest" + android:label="Telephony unit tests InstrumentationRunner"> + </instrumentation> + <uses-permission android:name="android.permission.READ_PHONE_STATE" /> +</manifest> diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java new file mode 100644 index 0000000..9e1af31 --- /dev/null +++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.telephonytest; + +import junit.framework.TestSuite; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; + +/** + * Instrumentation Test Runner for all Telephony unit tests. + * + * Running all tests: + * + * runtest telephony-unit + * or + * adb shell am instrument -w com.android.telephonytest/.TelephonyUnitTestRunner + */ + +public class TelephonyUnitTestRunner extends InstrumentationTestRunner { + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class); + suite.addTestSuite(com.android.telephonytest.unit.PhoneNumberUtilsUnitTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return TelephonyUnitTestRunner.class.getClassLoader(); + } +} diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java new file mode 100644 index 0000000..0f24f15 --- /dev/null +++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.telephonytest.unit; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import com.android.internal.telephony.CallerInfo; +import com.android.internal.telephony.CallerInfoAsyncQuery; +import android.util.Log; +import android.os.Looper; +import android.test.ActivityInstrumentationTestCase; +import android.util.StringBuilderPrinter; + +/* + * Check the CallerInfo utility class works as expected. + * + */ + +public class CallerInfoUnitTest extends AndroidTestCase { + private CallerInfo mInfo; + private Context mContext; + + private static final String kEmergencyNumber = "Emergency Number"; + private static final int kToken = 0xdeadbeef; + private static final String TAG = "CallerInfoUnitTest"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mContext = new MockContext(); + mInfo = new CallerInfo(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Checks the caller info instance is flagged as an emergency if + * the number is an emergency one. There is no test for the + * contact based constructors because emergency number are not in + * the contact DB. + */ + @SmallTest + public void testEmergencyIsProperlySet() throws Exception { + assertFalse(mInfo.isEmergencyNumber()); + + mInfo = CallerInfo.getCallerInfo(mContext, "911"); + assertIsValidEmergencyCallerInfo(); + + mInfo = CallerInfo.getCallerInfo(mContext, "tel:911"); + assertIsValidEmergencyCallerInfo(); + + + // This one hits the content resolver. + mInfo = CallerInfo.getCallerInfo(mContext, "18001234567"); + assertFalse(mInfo.isEmergencyNumber()); + } + + /** + * Same as testEmergencyIsProperlySet but uses the async query api. + */ + @SmallTest + public void testEmergencyIsProperlySetUsingAsyncQuery() throws Exception { + QueryRunner query; + + query = new QueryRunner("911"); + query.runAndCheckCompletion(); + assertIsValidEmergencyCallerInfo(); + + query = new QueryRunner("tel:911"); + query.runAndCheckCompletion(); + assertIsValidEmergencyCallerInfo(); + + query = new QueryRunner("18001234567"); + query.runAndCheckCompletion(); + assertFalse(mInfo.isEmergencyNumber()); + } + + /** + * For emergency caller info, phoneNumber should be set to the + * string emergency_call_dialog_number_for_display and the + * photoResource should be set to the picture_emergency drawable. + */ + @SmallTest + public void testEmergencyNumberAndPhotoAreSet() throws Exception { + mInfo = CallerInfo.getCallerInfo(mContext, "911"); + + assertIsValidEmergencyCallerInfo(); + } + + // TODO: Add more tests: + /** + * Check if the voice mail number cannot be retrieved that the + * original phone number is preserved. + */ + /** + * Check the markAs* methods work. + */ + + + // + // Helpers + // + + // Partial implementation of MockResources. + public class MockResources extends android.test.mock.MockResources + { + @Override + public String getString(int resId) throws Resources.NotFoundException { + switch (resId) { + case com.android.internal.R.string.emergency_call_dialog_number_for_display: + return kEmergencyNumber; + default: + throw new UnsupportedOperationException("Missing handling for resid " + resId); + } + } + } + + // Partial implementation of MockContext. + public class MockContext extends android.test.mock.MockContext { + private ContentResolver mResolver; + private Resources mResources; + + public MockContext() { + mResolver = new android.test.mock.MockContentResolver(); + mResources = new MockResources(); + } + + @Override + public ContentResolver getContentResolver() { + return mResolver; + } + + @Override + public Resources getResources() { + return mResources; + } + } + + /** + * Class to run a CallerInfoAsyncQuery in a separate thread, with + * its own Looper. We cannot use the main Looper because on the + * 1st quit the thread is maked dead, ie no further test can use + * it. Also there is not way to inject a Looper instance in the + * query, so we have to use a thread with its own looper. + */ + private class QueryRunner extends Thread + implements CallerInfoAsyncQuery.OnQueryCompleteListener { + private Looper mLooper; + private String mNumber; + private boolean mAsyncCompleted; + + public QueryRunner(String number) { + super(); + mNumber = number; + } + + // Run the query in the thread, wait for completion. + public void runAndCheckCompletion() throws InterruptedException { + start(); + join(); + assertTrue(mAsyncCompleted); + } + + @Override + public void run() { + Looper.prepare(); + mLooper = Looper.myLooper(); + mAsyncCompleted = false; + // The query will pick the thread local looper we've just prepared. + CallerInfoAsyncQuery.startQuery(kToken, mContext, mNumber, this, null); + mLooper.loop(); + } + + // Quit the Looper on the 1st callback + // (EVENT_EMERGENCY_NUMBER). There is another message + // (EVENT_END_OF_QUEUE) that will never be delivered because + // the test has exited. The corresponding stack trace + // "Handler{xxxxx} sending message to a Handler on a dead + // thread" can be ignored. + public void onQueryComplete(int token, Object cookie, CallerInfo info) { + mAsyncCompleted = true; + mInfo = info; + mLooper.quit(); + } + } + + /** + * Fail if mInfo does not contain a valid emergency CallerInfo instance. + */ + private void assertIsValidEmergencyCallerInfo() throws Exception { + assertTrue(mInfo.isEmergencyNumber()); + + // For emergency caller info, phoneNumber should be set to the + // string emergency_call_dialog_number_for_display and the + // photoResource should be set to the picture_emergency drawable. + assertEquals(kEmergencyNumber, mInfo.phoneNumber); + assertEquals(com.android.internal.R.drawable.picture_emergency, mInfo.photoResource); + + // The name should be null + assertNull(mInfo.name); + assertEquals(0, mInfo.namePresentation); + assertNull(mInfo.cnapName); + assertEquals(0, mInfo.numberPresentation); + + assertFalse(mInfo.contactExists); + assertEquals(0, mInfo.person_id); + assertFalse(mInfo.needUpdate); + assertNull(mInfo.contactRefUri); + + assertNull(mInfo.phoneLabel); + assertEquals(0, mInfo.numberType); + assertNull(mInfo.numberLabel); + + assertNull(mInfo.contactRingtoneUri); + assertFalse(mInfo.shouldSendToVoicemail); + + assertNull(mInfo.cachedPhoto); + assertFalse(mInfo.isCachedPhotoCurrent); + } +} diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java new file mode 100644 index 0000000..2d3c548 --- /dev/null +++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.telephonytest.unit; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import android.telephony.PhoneNumberUtils; +import android.telephony.TelephonyManager; + +/* + * Check the PhoneNumberUtils utility class works as expected. + * + */ + +public class PhoneNumberUtilsUnitTest extends AndroidTestCase { + private String mVoiceMailNumber; + private static final String TAG = "PhoneNumberUtilsUnitTest"; + + @Override + protected void setUp() throws Exception { + super.setUp(); + // FIXME: Why are we getting a security exception here? The + // permission is declared in the manifest.... + // mVoiceMailNumber = TelephonyManager.getDefault().getVoiceMailNumber(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Basic checks for the VoiceMail number. + * Assumes READ_PHONE_STATE permission and we don't have it. + */ + // TODO: Figure out why we don't have the permission declared in the manifest. + @SmallTest + public void testWithNumberNotEqualToVoiceMail() throws Exception { + assertFalse(PhoneNumberUtils.isVoiceMailNumber("911")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber("tel:911")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber("")); + assertFalse(PhoneNumberUtils.isVoiceMailNumber(null)); + // FIXME: + // assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber)); + } + +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java index 8fea967..395e572 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java @@ -96,7 +96,9 @@ public class FileFilter { // Android layout tests are stored in "layout_tests". The following two // tests expect "LayoutTests" in their output. "storage/domstorage/localstorage/iframe-events.html", - "storage/domstorage/sessionstorage/iframe-events.html" + "storage/domstorage/sessionstorage/iframe-events.html", + // below tests (failed or crashes) are filtered out temporarily due to prioritizing + "editing/selection/move-left-right.html", }; static void fillIgnoreResultSet() { diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java index cc2f1f5..85e0422 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java @@ -1,5 +1,23 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.dumprendertree; +import com.android.dumprendertree.forwarder.ForwardService; + import android.util.Log; import java.io.BufferedOutputStream; @@ -12,6 +30,12 @@ import java.io.IOException; public class FsUtils { private static final String LOGTAG = "FsUtils"; + static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/"; + static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/"; + static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/"; + static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/"; + static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/"; + private FsUtils() { //no creation of instances } @@ -77,4 +101,24 @@ public class FsUtils { return status; } + public static String getTestUrl(String path) { + String url = null; + if (!path.startsWith(HTTP_TESTS_PREFIX)) { + url = "file://" + path; + } else { + ForwardService.getForwardService().startForwardService(); + if (path.startsWith(HTTPS_TESTS_PREFIX)) { + // still cut the URL after "http/tests/" + url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length()); + } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX) + && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX) + && !path.startsWith(HTTP_WML_TESTS_PREFIX)) { + url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length()); + } else { + url = "file://" + path; + } + } + return url; + } + } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java index e4c8716..235e10e 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java @@ -19,6 +19,7 @@ package com.android.dumprendertree; import com.android.dumprendertree.TestShellActivity.DumpDataType; import com.android.dumprendertree.forwarder.AdbUtils; import com.android.dumprendertree.forwarder.ForwardServer; +import com.android.dumprendertree.forwarder.ForwardService; import android.app.Instrumentation; import android.content.Intent; @@ -143,17 +144,6 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt"; static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py"; - static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/"; - static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/"; - static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/"; - static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/"; - static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/"; - - - static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com"; - static final String FORWARD_HOST_CONF = "/sdcard/drt_forward_host.txt"; - private ForwardServer fs8000, fs8080, fs8443; - private MyTestRecorder mResultRecorder; private Vector<String> mTestList; private boolean mRebaselineResults; @@ -162,45 +152,6 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh public LayoutTestsAutoTest() { super("com.android.dumprendertree", TestShellActivity.class); - - int addr = getForwardHostAddr(); - if(addr != -1) { - fs8000 = new ForwardServer(8000, addr, 8000); - fs8080 = new ForwardServer(8080, addr, 8080); - fs8443 = new ForwardServer(8443, addr, 8443); - } - } - - private int getForwardHostAddr() { - int addr = -1; - String host = null; - File forwardHostConf = new File(FORWARD_HOST_CONF); - if (forwardHostConf.isFile()) { - BufferedReader hostReader = null; - try { - hostReader = new BufferedReader(new FileReader(forwardHostConf)); - host = hostReader.readLine(); - Log.v(LOGTAG, "read forward host from file: " + host); - } catch (IOException ioe) { - Log.v(LOGTAG, "cannot read forward host from file", ioe); - } finally { - if (hostReader != null) { - try { - hostReader.close(); - } catch (IOException ioe) { - // burn!!! - } - } - } - } - if (host == null || host.length() == 0) - host = DEFAULT_TEST_HOST; - try { - addr = AdbUtils.resolve(host); - } catch (IOException ioe) { - Log.e(LOGTAG, "failed to resolve server address", ioe); - } - return addr; } // This function writes the result of the layout test to @@ -366,7 +317,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh Intent intent = new Intent(Intent.ACTION_VIEW); intent.setClass(activity, TestShellActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test)); + intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(test)); intent.putExtra(TestShellActivity.RESULT_FILE, resultFile); intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout); activity.startActivity(intent); @@ -450,49 +401,10 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh } FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE"); - if(fs8000 != null) - fs8000.stop(); - if(fs8080 != null) - fs8080.stop(); - if(fs8443 != null) - fs8443.stop(); - + ForwardService.getForwardService().stopForwardService(); activity.finish(); } - private void startForwardServerIfNeeded() { - try { - if(fs8000 != null) - fs8000.start(); - if(fs8080 != null) - fs8080.start(); - if(fs8443 != null) - fs8443.start(); - } catch (IOException ioe) { - Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe); - } - } - - private String getTestUrl(String path) { - String url = null; - if (!path.startsWith(HTTP_TESTS_PREFIX)) { - url = "file://" + path; - } else { - startForwardServerIfNeeded(); - if (path.startsWith(HTTPS_TESTS_PREFIX)) { - // still cut the URL after "http/tests/" - url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length()); - } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX) - && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX) - && !path.startsWith(HTTP_WML_TESTS_PREFIX)) { - url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length()); - } else { - url = "file://" + path; - } - } - return url; - } - private String getTestPath() { LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation(); diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java index 71d9758..50b7c3f 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.dumprendertree; import android.app.Activity; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java index 995c129..fbce78a 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.dumprendertree; import android.app.Activity; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 663df83..074d90f 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -16,6 +16,8 @@ package com.android.dumprendertree; +import com.android.dumprendertree.forwarder.ForwardService; + import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -184,6 +186,7 @@ public class TestShellActivity extends Activity implements LayoutTestController } catch (IOException ioe) { Log.w(LOGTAG, "Failed to close test list file.", ioe); } + ForwardService.getForwardService().stopForwardService(); finished(); } @@ -215,10 +218,9 @@ public class TestShellActivity extends Activity implements LayoutTestController builder.create().show(); return; } - url = "file://" + url; Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - intent.putExtra(TestShellActivity.TEST_URL, url); + intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url)); intent.putExtra(TIMEOUT_IN_MILLIS, 10000); executeIntent(intent); } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java index 9a3e9c2..c2ecf3a 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.dumprendertree.forwarder; import android.util.Log; @@ -44,7 +60,6 @@ public class AdbUtils { DataInputStream dis = new DataInputStream(localSocket.getInputStream()); OutputStream os = localSocket.getOutputStream(); int count_read = 0; - byte[] buf = new byte[128]; if (localSocket == null || dis == null || os == null) return -1; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java index 74e018e..14f8fbe 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.dumprendertree.forwarder; import android.util.Log; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java new file mode 100644 index 0000000..8b7de6e --- /dev/null +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dumprendertree.forwarder; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +import android.util.Log; + +public class ForwardService { + + private ForwardServer fs8000, fs8080, fs8443; + + private static ForwardService inst; + + private static final String LOGTAG = "ForwardService"; + + private static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com"; + + private static final String FORWARD_HOST_CONF = "/sdcard/drt_forward_host.txt"; + + private ForwardService() { + int addr = getForwardHostAddr(); + if (addr != -1) { + fs8000 = new ForwardServer(8000, addr, 8000); + fs8080 = new ForwardServer(8080, addr, 8080); + fs8443 = new ForwardServer(8443, addr, 8443); + } + } + + public static ForwardService getForwardService() { + if (inst == null) { + inst = new ForwardService(); + } + return inst; + } + + public void startForwardService() { + try { + if (fs8000 != null) + fs8000.start(); + if (fs8080 != null) + fs8080.start(); + if (fs8443 != null) + fs8443.start(); + } catch (IOException ioe) { + Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe); + return; + } + } + + public void stopForwardService() { + if (fs8000 != null) { + fs8000.stop(); + fs8000 = null; + } + if (fs8080 != null) { + fs8080.stop(); + fs8080 = null; + } + if (fs8443 != null) { + fs8443.stop(); + fs8443 = null; + } + Log.v(LOGTAG, "forwarders stopped."); + } + + private static int getForwardHostAddr() { + int addr = -1; + String host = null; + File forwardHostConf = new File(FORWARD_HOST_CONF); + if (forwardHostConf.isFile()) { + BufferedReader hostReader = null; + try { + hostReader = new BufferedReader(new FileReader(forwardHostConf)); + host = hostReader.readLine(); + Log.v(LOGTAG, "read forward host from file: " + host); + } catch (IOException ioe) { + Log.v(LOGTAG, "cannot read forward host from file", ioe); + } finally { + if (hostReader != null) { + try { + hostReader.close(); + } catch (IOException ioe) { + // burn!!! + } + } + } + } + if (host == null || host.length() == 0) + host = DEFAULT_TEST_HOST; + try { + addr = AdbUtils.resolve(host); + } catch (IOException ioe) { + Log.e(LOGTAG, "failed to resolve server address", ioe); + } + return addr; + } +} diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java index e1e04a7..a1f3cdf 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.dumprendertree.forwarder; import android.util.Log; diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index b00d8b0..b6b0e63 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -187,6 +187,13 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) return 0; } + // navigation hidden + if (getNavHiddenName(part.string(), &config)) { + *axis = AXIS_NAVHIDDEN; + *value = config.inputFlags; + return 0; + } + // navigation if (getNavigationName(part.string(), &config)) { *axis = AXIS_NAVIGATION; @@ -217,7 +224,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) Vector<String8> parts; String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den; - String8 touch, key, keysHidden, nav, size, vers; + String8 touch, key, keysHidden, nav, navHidden, size, vers; const char *p = dir; const char *q; @@ -393,6 +400,19 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) //printf("not keyboard: %s\n", part.string()); } + // navigation hidden + if (getNavHiddenName(part.string())) { + navHidden = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not navHidden: %s\n", part.string()); + } + if (getNavigationName(part.string())) { nav = part; @@ -443,6 +463,7 @@ success: this->touchscreen = touch; this->keysHidden = keysHidden; this->keyboard = key; + this->navHidden = navHidden; this->navigation = nav; this->screenSize = size; this->version = vers; @@ -476,6 +497,8 @@ AaptGroupEntry::toString() const s += ","; s += keyboard; s += ","; + s += navHidden; + s += ","; s += navigation; s += ","; s += screenSize; @@ -528,6 +551,10 @@ AaptGroupEntry::toDirName(const String8& resType) const s += "-"; s += keyboard; } + if (this->navHidden != "") { + s += "-"; + s += navHidden; + } if (this->navigation != "") { s += "-"; s += navigation; @@ -852,6 +879,30 @@ bool AaptGroupEntry::getKeyboardName(const char* name, return false; } +bool AaptGroupEntry::getNavHiddenName(const char* name, + ResTable_config* out) +{ + uint8_t mask = 0; + uint8_t value = 0; + if (strcmp(name, kWildcardName) == 0) { + mask = out->MASK_NAVHIDDEN; + value = out->NAVHIDDEN_ANY; + } else if (strcmp(name, "navexposed") == 0) { + mask = out->MASK_NAVHIDDEN; + value = out->NAVHIDDEN_NO; + } else if (strcmp(name, "navhidden") == 0) { + mask = out->MASK_NAVHIDDEN; + value = out->NAVHIDDEN_YES; + } + + if (mask != 0) { + if (out) out->inputFlags = (out->inputFlags&~mask) | value; + return true; + } + + return false; +} + bool AaptGroupEntry::getNavigationName(const char* name, ResTable_config* out) { @@ -953,6 +1004,7 @@ int AaptGroupEntry::compare(const AaptGroupEntry& o) const if (v == 0) v = touchscreen.compare(o.touchscreen); if (v == 0) v = keysHidden.compare(o.keysHidden); if (v == 0) v = keyboard.compare(o.keyboard); + if (v == 0) v = navHidden.compare(o.navHidden); if (v == 0) v = navigation.compare(o.navigation); if (v == 0) v = screenSize.compare(o.screenSize); if (v == 0) v = version.compare(o.version); @@ -973,6 +1025,7 @@ ResTable_config AaptGroupEntry::toParams() const getTouchscreenName(touchscreen.string(), ¶ms); getKeysHiddenName(keysHidden.string(), ¶ms); getKeyboardName(keyboard.string(), ¶ms); + getNavHiddenName(navHidden.string(), ¶ms); getNavigationName(navigation.string(), ¶ms); getScreenSizeName(screenSize.string(), ¶ms); getVersionName(version.string(), ¶ms); diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 865efd1..26500a3 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -37,6 +37,7 @@ enum { AXIS_TOUCHSCREEN, AXIS_KEYSHIDDEN, AXIS_KEYBOARD, + AXIS_NAVHIDDEN, AXIS_NAVIGATION, AXIS_SCREENSIZE, AXIS_VERSION @@ -64,6 +65,7 @@ public: String8 touchscreen; String8 keysHidden; String8 keyboard; + String8 navHidden; String8 navigation; String8 screenSize; String8 version; @@ -83,6 +85,7 @@ public: static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL); static bool getKeyboardName(const char* name, ResTable_config* out = NULL); static bool getNavigationName(const char* name, ResTable_config* out = NULL); + static bool getNavHiddenName(const char* name, ResTable_config* out = NULL); static bool getScreenSizeName(const char* name, ResTable_config* out = NULL); static bool getVersionName(const char* name, ResTable_config* out = NULL); diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index f85aadd..954930e 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -42,24 +42,51 @@ public class WifiConfiguration implements Parcelable { public static final String priorityVarName = "priority"; /** {@hide} */ public static final String hiddenSSIDVarName = "scan_ssid"; + + /** {@hide} */ + public class EnterpriseField { + private String varName; + private String value; + + private EnterpriseField(String varName) { + this.varName = varName; + this.value = null; + } + + public void setValue(String value) { + this.value = value; + } + + public String varName() { + return varName; + } + + public String value() { + return value; + } + } + /** {@hide} */ - public static final String eapVarName = "eap"; + public EnterpriseField eap = new EnterpriseField("eap"); /** {@hide} */ - public static final String phase2VarName = "phase2"; + public EnterpriseField phase2 = new EnterpriseField("phase2"); /** {@hide} */ - public static final String identityVarName = "identity"; + public EnterpriseField identity = new EnterpriseField("anonymous_identity"); /** {@hide} */ - public static final String anonymousIdentityVarName = "anonymous_identity"; + public EnterpriseField anonymous_identity = new EnterpriseField("anonymous_identity"); /** {@hide} */ - public static final String passwordVarName = "password"; + public EnterpriseField password = new EnterpriseField("password"); /** {@hide} */ - public static final String clientCertVarName = "client_cert"; + public EnterpriseField client_cert = new EnterpriseField("client_cert"); /** {@hide} */ - public static final String caCertVarName = "ca_cert"; + public EnterpriseField private_key = new EnterpriseField("private_key"); /** {@hide} */ - public static final String privateKeyVarName = "private_key"; + public EnterpriseField ca_cert = new EnterpriseField("ca_cert"); + /** {@hide} */ - public static final String privateKeyPasswdVarName = "private_key_passwd"; + public EnterpriseField[] enterpriseFields = { + eap, phase2, identity, anonymous_identity, password, client_cert, + private_key, ca_cert }; /** * Recognized key management schemes. @@ -267,44 +294,6 @@ public class WifiConfiguration implements Parcelable { */ public BitSet allowedGroupCiphers; - /* The following fields are used for EAP/IEEE8021X authentication */ - - /** - * The eap mode should be PEAP, TLS or TTLS. - * {@hide} - */ - public String eap; - /** - * The phase2 authenication could be PAP, MSCHAP, MSCHAP2, GTC. - * {@hide} - */ - public String phase2; - /** - * The identity of the user in string, - * which is used for the authentication. - * {@hide} - */ - public String identity; - /** {@hide} */ - public String anonymousIdentity; - /** {@hide} */ - public String password; - /** The path of the client certificate file. - * {@hide} - */ - public String clientCert; - /** The path of the CA certificate file. - * {@hide} - */ - public String caCert; - /** The path of the private key file. - * {@hide} - */ - public String privateKey; - /** The password of the private key file if encrypted. - * {@hide} - */ - public String privateKeyPasswd; public WifiConfiguration() { networkId = -1; @@ -320,15 +309,9 @@ public class WifiConfiguration implements Parcelable { wepKeys = new String[4]; for (int i = 0; i < wepKeys.length; i++) wepKeys[i] = null; - eap = null; - phase2 = null; - identity = null; - anonymousIdentity = null; - password = null; - clientCert = null; - caCert = null; - privateKey = null; - privateKeyPasswd = null; + for (EnterpriseField field : enterpriseFields) { + field.setValue(null); + } } public String toString() { @@ -403,41 +386,11 @@ public class WifiConfiguration implements Parcelable { if (this.preSharedKey != null) { sbuf.append('*'); } - sbuf.append('\n').append(" eap: "); - if (this.eap != null) { - sbuf.append(eap); - } - sbuf.append('\n').append(" phase2: "); - if (this.phase2 != null) { - sbuf.append(phase2); - } - sbuf.append('\n').append(" Identity: "); - if (this.identity != null) { - sbuf.append(identity); - } - sbuf.append('\n').append(" AnonymousIdentity: "); - if (this.anonymousIdentity != null) { - sbuf.append(anonymousIdentity); - } - sbuf.append('\n').append(" Password: "); - if (this.password != null) { - sbuf.append(password); - } - sbuf.append('\n').append(" ClientCert: "); - if (this.clientCert != null) { - sbuf.append(clientCert); - } - sbuf.append('\n').append(" CaCert: "); - if (this.caCert != null) { - sbuf.append(caCert); - } - sbuf.append('\n').append(" PrivateKey: "); - if (this.privateKey != null) { - sbuf.append(privateKey); - } - sbuf.append('\n').append(" PrivateKeyPasswd: "); - if (this.privateKeyPasswd != null) { - sbuf.append(privateKeyPasswd); + + for (EnterpriseField field : enterpriseFields) { + sbuf.append('\n').append(" " + field.varName() + ": "); + String value = field.value(); + if (value != null) sbuf.append(value); } sbuf.append('\n'); return sbuf.toString(); @@ -497,15 +450,10 @@ public class WifiConfiguration implements Parcelable { writeBitSet(dest, allowedAuthAlgorithms); writeBitSet(dest, allowedPairwiseCiphers); writeBitSet(dest, allowedGroupCiphers); - dest.writeString(eap); - dest.writeString(phase2); - dest.writeString(identity); - dest.writeString(anonymousIdentity); - dest.writeString(password); - dest.writeString(clientCert); - dest.writeString(caCert); - dest.writeString(privateKey); - dest.writeString(privateKeyPasswd); + + for (EnterpriseField field : enterpriseFields) { + dest.writeString(field.value()); + } } /** Implement the Parcelable interface {@hide} */ @@ -528,15 +476,10 @@ public class WifiConfiguration implements Parcelable { config.allowedAuthAlgorithms = readBitSet(in); config.allowedPairwiseCiphers = readBitSet(in); config.allowedGroupCiphers = readBitSet(in); - config.eap = in.readString(); - config.phase2 = in.readString(); - config.identity = in.readString(); - config.anonymousIdentity = in.readString(); - config.password = in.readString(); - config.clientCert = in.readString(); - config.caCert = in.readString(); - config.privateKey = in.readString(); - config.privateKeyPasswd = in.readString(); + + for (EnterpriseField field : config.enterpriseFields) { + field.setValue(in.readString()); + } return config; } |