Merge "Audio Effect Framework: add effect suspend/restore"
diff --git a/Android.mk b/Android.mk
index ea8314c..752a5f8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -183,6 +183,7 @@
media/java/android/media/IAudioFocusDispatcher.aidl \
media/java/android/media/IMediaScannerListener.aidl \
media/java/android/media/IMediaScannerService.aidl \
+ media/java/android/media/IRemoteControlClient.aidl \
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6cef3a7..876d555 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15,6 +15,7 @@
field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
+ field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -1031,6 +1032,7 @@
field public static final int translationY = 16843555; // 0x1010323
field public static final int type = 16843169; // 0x10101a1
field public static final int typeface = 16842902; // 0x1010096
+ field public static final int uiOptions = 16843682; // 0x10103a2
field public static final int uncertainGestureColor = 16843382; // 0x1010276
field public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
field public static final int unselectedAlpha = 16843278; // 0x101020e
@@ -1524,15 +1526,15 @@
field public static final int TextAppearance_Holo_Small = 16974081; // 0x1030101
field public static final int TextAppearance_Holo_Small_Inverse = 16974082; // 0x1030102
field public static final int TextAppearance_Holo_Widget = 16974085; // 0x1030105
- field public static final int TextAppearance_Holo_Widget_ActionBar_Menu = 16974113; // 0x1030121
+ field public static final int TextAppearance_Holo_Widget_ActionBar_Menu = 16974112; // 0x1030120
field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle = 16974099; // 0x1030113
- field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle_Inverse = 16974110; // 0x103011e
+ field public static final int TextAppearance_Holo_Widget_ActionBar_Subtitle_Inverse = 16974109; // 0x103011d
field public static final int TextAppearance_Holo_Widget_ActionBar_Title = 16974098; // 0x1030112
- field public static final int TextAppearance_Holo_Widget_ActionBar_Title_Inverse = 16974109; // 0x103011d
+ field public static final int TextAppearance_Holo_Widget_ActionBar_Title_Inverse = 16974108; // 0x103011c
field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle = 16974101; // 0x1030115
- field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle_Inverse = 16974112; // 0x1030120
+ field public static final int TextAppearance_Holo_Widget_ActionMode_Subtitle_Inverse = 16974111; // 0x103011f
field public static final int TextAppearance_Holo_Widget_ActionMode_Title = 16974100; // 0x1030114
- field public static final int TextAppearance_Holo_Widget_ActionMode_Title_Inverse = 16974111; // 0x103011f
+ field public static final int TextAppearance_Holo_Widget_ActionMode_Title_Inverse = 16974110; // 0x103011e
field public static final int TextAppearance_Holo_Widget_Button = 16974086; // 0x1030106
field public static final int TextAppearance_Holo_Widget_DropDownHint = 16974091; // 0x103010b
field public static final int TextAppearance_Holo_Widget_DropDownItem = 16974092; // 0x103010c
@@ -1586,6 +1588,7 @@
field public static final int Theme_Holo_Dialog_NoActionBar_MinWidth = 16973938; // 0x1030072
field public static final int Theme_Holo_InputMethod = 16973951; // 0x103007f
field public static final int Theme_Holo_Light = 16973934; // 0x103006e
+ field public static final int Theme_Holo_Light_DarkActionBar = 16974105; // 0x1030119
field public static final int Theme_Holo_Light_Dialog = 16973939; // 0x1030073
field public static final int Theme_Holo_Light_DialogWhenLarge = 16973945; // 0x1030079
field public static final int Theme_Holo_Light_DialogWhenLarge_NoActionBar = 16973946; // 0x103007a
@@ -1595,17 +1598,9 @@
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
field public static final int Theme_Holo_Light_NoActionBar_Fullscreen = 16974065; // 0x10300f1
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
- field public static final int Theme_Holo_Light_SolidActionBar = 16974122; // 0x103012a
- field public static final int Theme_Holo_Light_SolidActionBar_Inverse = 16974123; // 0x103012b
- field public static final int Theme_Holo_Light_SolidActionBar_Inverse_SplitActionBarWhenNarrow = 16974126; // 0x103012e
- field public static final int Theme_Holo_Light_SolidActionBar_SplitActionBarWhenNarrow = 16974125; // 0x103012d
- field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974106; // 0x103011a
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
- field public static final int Theme_Holo_SolidActionBar = 16974121; // 0x1030129
- field public static final int Theme_Holo_SolidActionBar_SplitActionBarWhenNarrow = 16974124; // 0x103012c
- field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974105; // 0x1030119
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
field public static final int Theme_InputMethod = 16973908; // 0x1030054
@@ -1656,7 +1651,7 @@
field public static final int Widget_GridView = 16973874; // 0x1030032
field public static final int Widget_Holo = 16973962; // 0x103008a
field public static final int Widget_Holo_ActionBar = 16974004; // 0x10300b4
- field public static final int Widget_Holo_ActionBar_Solid = 16974114; // 0x1030122
+ field public static final int Widget_Holo_ActionBar_Solid = 16974113; // 0x1030121
field public static final int Widget_Holo_ActionBar_TabBar = 16974071; // 0x10300f7
field public static final int Widget_Holo_ActionBar_TabText = 16974070; // 0x10300f6
field public static final int Widget_Holo_ActionBar_TabView = 16974069; // 0x10300f5
@@ -1668,7 +1663,7 @@
field public static final int Widget_Holo_AutoCompleteTextView = 16973968; // 0x1030090
field public static final int Widget_Holo_Button = 16973963; // 0x103008b
field public static final int Widget_Holo_Button_Borderless = 16974050; // 0x10300e2
- field public static final int Widget_Holo_Button_Borderless_Small = 16974107; // 0x103011b
+ field public static final int Widget_Holo_Button_Borderless_Small = 16974106; // 0x103011a
field public static final int Widget_Holo_Button_Inset = 16973965; // 0x103008d
field public static final int Widget_Holo_Button_Small = 16973964; // 0x103008c
field public static final int Widget_Holo_Button_Toggle = 16973966; // 0x103008e
@@ -1686,22 +1681,22 @@
field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
field public static final int Widget_Holo_Light = 16974005; // 0x10300b5
field public static final int Widget_Holo_Light_ActionBar = 16974049; // 0x10300e1
- field public static final int Widget_Holo_Light_ActionBar_Solid = 16974115; // 0x1030123
- field public static final int Widget_Holo_Light_ActionBar_Solid_Inverse = 16974116; // 0x1030124
+ field public static final int Widget_Holo_Light_ActionBar_Solid = 16974114; // 0x1030122
+ field public static final int Widget_Holo_Light_ActionBar_Solid_Inverse = 16974115; // 0x1030123
field public static final int Widget_Holo_Light_ActionBar_TabBar = 16974074; // 0x10300fa
- field public static final int Widget_Holo_Light_ActionBar_TabBar_Inverse = 16974117; // 0x1030125
+ field public static final int Widget_Holo_Light_ActionBar_TabBar_Inverse = 16974116; // 0x1030124
field public static final int Widget_Holo_Light_ActionBar_TabText = 16974073; // 0x10300f9
- field public static final int Widget_Holo_Light_ActionBar_TabText_Inverse = 16974119; // 0x1030127
+ field public static final int Widget_Holo_Light_ActionBar_TabText_Inverse = 16974118; // 0x1030126
field public static final int Widget_Holo_Light_ActionBar_TabView = 16974072; // 0x10300f8
- field public static final int Widget_Holo_Light_ActionBar_TabView_Inverse = 16974118; // 0x1030126
+ field public static final int Widget_Holo_Light_ActionBar_TabView_Inverse = 16974117; // 0x1030125
field public static final int Widget_Holo_Light_ActionButton = 16974045; // 0x10300dd
field public static final int Widget_Holo_Light_ActionButton_CloseMode = 16974048; // 0x10300e0
field public static final int Widget_Holo_Light_ActionButton_Overflow = 16974046; // 0x10300de
field public static final int Widget_Holo_Light_ActionMode = 16974047; // 0x10300df
- field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974120; // 0x1030128
+ field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
- field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974108; // 0x103011c
+ field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
field public static final int Widget_Holo_Light_Button_Toggle = 16974009; // 0x10300b9
@@ -5637,6 +5632,7 @@
field public static final int SCREEN_ORIENTATION_SENSOR_PORTRAIT = 7; // 0x7
field public static final int SCREEN_ORIENTATION_UNSPECIFIED = -1; // 0xffffffff
field public static final int SCREEN_ORIENTATION_USER = 2; // 0x2
+ field public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1; // 0x1
field public int configChanges;
field public int flags;
field public int launchMode;
@@ -5646,6 +5642,7 @@
field public java.lang.String targetActivity;
field public java.lang.String taskAffinity;
field public int theme;
+ field public int uiOptions;
}
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -5696,6 +5693,7 @@
field public int targetSdkVersion;
field public java.lang.String taskAffinity;
field public int theme;
+ field public int uiOptions;
field public int uid;
}
@@ -23162,6 +23160,7 @@
method public abstract void setTitle(java.lang.CharSequence);
method public abstract void setTitleColor(int);
method public void setType(int);
+ method public void setUiOptions(int);
method public abstract void setVolumeControlStream(int);
method public void setWindowAnimations(int);
method public void setWindowManager(android.view.WindowManager, android.os.IBinder, java.lang.String);
@@ -24136,7 +24135,7 @@
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
- field public static final int RESULT_ATTR_LOOKS_TYPO = 2; // 0x2
+ field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2
}
public final class TextInfo implements android.os.Parcelable {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d5b669e..98b867d 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4399,6 +4399,9 @@
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
+ if (info.uiOptions != 0) {
+ mWindow.setUiOptions(info.uiOptions);
+ }
mUiThread = Thread.currentThread();
mMainThread = aThread;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8931675..c566104 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2503,6 +2503,7 @@
mAvailThumbnailBitmap = thumbnail;
thumbnail = null;
}
+ cv.setBitmap(null);
}
} catch (Exception e) {
diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java
index 7b9bd60..8eb9ba4 100644
--- a/core/java/android/app/LauncherActivity.java
+++ b/core/java/android/app/LauncherActivity.java
@@ -314,6 +314,7 @@
icon.draw(canvas);
icon.setBounds(mOldBounds);
icon = new BitmapDrawable(getResources(), thumb);
+ canvas.setBitmap(null);
} else if (iconWidth < width && iconHeight < height) {
final Bitmap.Config c = Bitmap.Config.ARGB_8888;
final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
@@ -326,6 +327,7 @@
icon.draw(canvas);
icon.setBounds(mOldBounds);
icon = new BitmapDrawable(getResources(), thumb);
+ canvas.setBitmap(null);
}
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 4858f14..bba329d 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -433,7 +433,19 @@
* the mode from the theme will be used.
*/
public int softInputMode;
-
+
+ /**
+ * The desired extra UI options for this activity and its main window.
+ * Set from the {@link android.R.attr#uiOptions} attribute in the
+ * activity's manifest.
+ */
+ public int uiOptions = 0;
+
+ /**
+ * Flag for use with uiOptions.
+ */
+ public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1;
+
public ActivityInfo() {
}
@@ -448,6 +460,7 @@
screenOrientation = orig.screenOrientation;
configChanges = orig.configChanges;
softInputMode = orig.softInputMode;
+ uiOptions = orig.uiOptions;
}
/**
@@ -479,6 +492,9 @@
+ " configChanges=0x" + Integer.toHexString(configChanges)
+ " softInputMode=0x" + Integer.toHexString(softInputMode));
}
+ if (uiOptions != 0) {
+ pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
+ }
super.dumpBack(pw, prefix);
}
@@ -503,6 +519,7 @@
dest.writeInt(screenOrientation);
dest.writeInt(configChanges);
dest.writeInt(softInputMode);
+ dest.writeInt(uiOptions);
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -526,5 +543,6 @@
screenOrientation = source.readInt();
configChanges = source.readInt();
softInputMode = source.readInt();
+ uiOptions = source.readInt();
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index ddb6ef0..65a8750 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -91,6 +91,13 @@
public String backupAgentName;
/**
+ * The default extra UI options for activities in this application.
+ * Set from the {@link android.R.attr#uiOptions} attribute in the
+ * activity's manifest.
+ */
+ public int uiOptions = 0;
+
+ /**
* Value for {@link #flags}: if set, this application is installed in the
* device's system image.
*/
@@ -456,6 +463,9 @@
if (descriptionRes != 0) {
pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
}
+ if (uiOptions != 0) {
+ pw.println(prefix + "uiOptions=0x" + Integer.toHexString(uiOptions));
+ }
super.dumpBack(pw, prefix);
}
@@ -509,6 +519,7 @@
installLocation = orig.installLocation;
manageSpaceActivityName = orig.manageSpaceActivityName;
descriptionRes = orig.descriptionRes;
+ uiOptions = orig.uiOptions;
}
@@ -547,6 +558,7 @@
dest.writeString(manageSpaceActivityName);
dest.writeString(backupAgentName);
dest.writeInt(descriptionRes);
+ dest.writeInt(uiOptions);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -584,6 +596,7 @@
manageSpaceActivityName = source.readString();
backupAgentName = source.readString();
descriptionRes = source.readInt();
+ uiOptions = source.readInt();
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 53d6bb1..b6c64cb 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1645,6 +1645,9 @@
}
}
+ ai.uiOptions = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestApplication_uiOptions, 0);
+
sa.recycle();
if (outError[0] != null) {
@@ -1850,6 +1853,10 @@
a.info.theme = sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestActivity_theme, 0);
+ a.info.uiOptions = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
+ a.info.applicationInfo.uiOptions);
+
String str;
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
@@ -2091,6 +2098,7 @@
info.screenOrientation = target.info.screenOrientation;
info.taskAffinity = target.info.taskAffinity;
info.theme = target.info.theme;
+ info.uiOptions = target.info.uiOptions;
Activity a = new Activity(mParseActivityAliasArgs, info);
if (outError[0] != null) {
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 7336550..5501f38 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -119,22 +119,22 @@
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- if (DBG) {
+ if (VDBG) {
mMdst.log("MdstHandler connected");
}
mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj;
} else {
- if (DBG) {
+ if (VDBG) {
mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1);
}
}
break;
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- mMdst.log("Disconnected from DataStateTracker");
+ if (VDBG) mMdst.log("Disconnected from DataStateTracker");
mMdst.mDataConnectionTrackerAc = null;
break;
default: {
- mMdst.log("Ignorning unknown message=" + msg);
+ if (VDBG) mMdst.log("Ignorning unknown message=" + msg);
break;
}
}
@@ -221,13 +221,13 @@
mLinkProperties = intent.getParcelableExtra(
Phone.DATA_LINK_PROPERTIES_KEY);
if (mLinkProperties == null) {
- log("CONNECTED event did not supply link properties.");
+ loge("CONNECTED event did not supply link properties.");
mLinkProperties = new LinkProperties();
}
mLinkCapabilities = intent.getParcelableExtra(
Phone.DATA_LINK_CAPABILITIES_KEY);
if (mLinkCapabilities == null) {
- log("CONNECTED event did not supply link capabilities.");
+ loge("CONNECTED event did not supply link capabilities.");
mLinkCapabilities = new LinkCapabilities();
}
setDetailedState(DetailedState.CONNECTED, reason, apnName);
@@ -238,7 +238,7 @@
if (TextUtils.equals(reason, Phone.REASON_LINK_PROPERTIES_CHANGED)) {
mLinkProperties = intent.getParcelableExtra(Phone.DATA_LINK_PROPERTIES_KEY);
if (mLinkProperties == null) {
- log("No link property in LINK_PROPERTIES change event.");
+ loge("No link property in LINK_PROPERTIES change event.");
mLinkProperties = new LinkProperties();
}
// Just update reason field in this NetworkInfo
@@ -269,7 +269,7 @@
setDetailedState(DetailedState.FAILED, reason, apnName);
} else if (intent.getAction().
equals(DataConnectionTracker.ACTION_DATA_CONNECTION_TRACKER_MESSENGER)) {
- if (DBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
+ if (VDBG) log(mApnType + " got ACTION_DATA_CONNECTION_TRACKER_MESSENGER");
mMessenger = intent.getParcelableExtra(DataConnectionTracker.EXTRA_MESSENGER);
AsyncChannel ac = new AsyncChannel();
ac.connect(mContext, MobileDataStateTracker.this.mHandler, mMessenger);
@@ -437,7 +437,7 @@
*/
for (int retry = 0; retry < 2; retry++) {
if (mPhoneService == null) {
- log("Ignoring mobile radio request because could not acquire PhoneService");
+ loge("Ignoring mobile radio request because could not acquire PhoneService");
break;
}
@@ -448,7 +448,7 @@
}
}
- log("Could not set radio power to " + (turnOn ? "on" : "off"));
+ loge("Could not set radio power to " + (turnOn ? "on" : "off"));
return false;
}
@@ -457,12 +457,12 @@
*/
public void setDataEnable(boolean enabled) {
try {
- log("setDataEnable: E enabled=" + enabled);
+ if (DBG) log("setDataEnable: E enabled=" + enabled);
mDataConnectionTrackerAc.sendMessage(DataConnectionTracker.CMD_SET_DATA_ENABLE,
enabled ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
- log("setDataEnable: X enabled=" + enabled);
+ if (VDBG) log("setDataEnable: X enabled=" + enabled);
} catch (Exception e) {
- log("setDataEnable: X mAc was null" + e);
+ loge("setDataEnable: X mAc was null" + e);
}
}
@@ -473,15 +473,15 @@
public void setDependencyMet(boolean met) {
Bundle bundle = Bundle.forPair(DataConnectionTracker.APN_TYPE_KEY, mApnType);
try {
- log("setDependencyMet: E met=" + met);
+ if (DBG) log("setDependencyMet: E met=" + met);
Message msg = Message.obtain();
msg.what = DataConnectionTracker.CMD_SET_DEPENDENCY_MET;
msg.arg1 = (met ? DataConnectionTracker.ENABLED : DataConnectionTracker.DISABLED);
msg.setData(bundle);
mDataConnectionTrackerAc.sendMessage(msg);
- log("setDependencyMet: X met=" + met);
+ if (VDBG) log("setDependencyMet: X met=" + met);
} catch (NullPointerException e) {
- log("setDependencyMet: X mAc was null" + e);
+ loge("setDependencyMet: X mAc was null" + e);
}
}
@@ -508,7 +508,7 @@
*/
for (int retry = 0; retry < 2; retry++) {
if (mPhoneService == null) {
- log("Ignoring feature request because could not acquire PhoneService");
+ loge("Ignoring feature request because could not acquire PhoneService");
break;
}
@@ -523,7 +523,7 @@
}
}
- log("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
+ loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\"");
return Phone.APN_REQUEST_FAILED;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 935281a5..ad76928 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10221,6 +10221,7 @@
}
canvas.restoreToCount(restoreCount);
+ canvas.setBitmap(null);
if (attachInfo != null) {
// Restore the cached Canvas for our siblings
@@ -10289,9 +10290,9 @@
mPrivateFlags = flags;
canvas.restoreToCount(restoreCount);
+ canvas.setBitmap(null);
if (attachInfo != null) {
- canvas.setBitmap(null);
// Restore the cached Canvas for our siblings
attachInfo.mCanvas = canvas;
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index dbcbd6e..9520958 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -220,6 +220,7 @@
private final int mMaximumDrawingCacheSize;
private final int mOverscrollDistance;
private final int mOverflingDistance;
+ private final boolean mFadingMarqueeEnabled;
private boolean sHasPermanentMenuKey;
private boolean sHasPermanentMenuKeySet;
@@ -246,6 +247,7 @@
mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
mOverscrollDistance = OVERSCROLL_DISTANCE;
mOverflingDistance = OVERFLING_DISTANCE;
+ mFadingMarqueeEnabled = true;
}
/**
@@ -297,6 +299,9 @@
sHasPermanentMenuKey = false;
}
}
+
+ mFadingMarqueeEnabled = res.getBoolean(
+ com.android.internal.R.bool.config_ui_enableFadingMarquee);
}
/**
@@ -673,4 +678,12 @@
public boolean hasPermanentMenuKey() {
return sHasPermanentMenuKey;
}
+
+ /**
+ * @hide
+ * @return Whether or not marquee should use fading edges.
+ */
+ public boolean isFadingMarqueeEnabled() {
+ return mFadingMarqueeEnabled;
+ }
}
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 96e550e..65e72c9 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1094,6 +1094,9 @@
}
public void post(Object... data) {
+ if (data[1] != null) {
+ ((Canvas) data[1]).setBitmap(null);
+ }
if (data[0] != null) {
((Bitmap) data[0]).recycle();
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index e07085c..6ac679c 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1213,5 +1213,10 @@
* @see android.app.Activity#getVolumeControlStream()
*/
public abstract int getVolumeControlStream();
-
+
+ /**
+ * Set extra options that will influence the UI for this window.
+ * @param uiOptions Flags specifying extra options for this window.
+ */
+ public void setUiOptions(int uiOptions) { }
}
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index 3332f1e..ed0f89d 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -34,9 +34,9 @@
/**
* Flag of the attributes of the suggestions that can be obtained by
* {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested
- * word looks a typo.
+ * word looks like a typo.
*/
- public static final int RESULT_ATTR_LOOKS_TYPO = 0x0002;
+ public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 0x0002;
private final int mSuggestionsAttributes;
private final String[] mSuggestions;
private final boolean mSuggestionsAvailable;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f4fd551..7620a63 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -8405,9 +8405,9 @@
}
}
- // Called by JNI to invalidate the View, given rectangle coordinates in
- // content space
- private void pageSwapCallback() {
+ /** @hide Called by JNI when pages are swapped (only occurs with hardware
+ * acceleration) */
+ protected void pageSwapCallback() {
if (inEditingMode()) {
didUpdateWebTextViewDimensions(ANYWHERE);
}
@@ -8426,11 +8426,11 @@
WebViewCore.ViewState viewState = draw.mViewState;
boolean isPictureAfterFirstLayout = viewState != null;
- // Request a callback on pageSwap (to reposition the webtextview)
- boolean registerPageSwapCallback =
- !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
-
if (updateBaseLayer) {
+ // Request a callback on pageSwap (to reposition the webtextview)
+ boolean registerPageSwapCallback =
+ !mZoomManager.isFixedLengthAnimationInProgress() && inEditingMode();
+
setBaseLayer(draw.mBaseLayer, draw.mInvalRegion,
getSettings().getShowVisualIndicator(),
isPictureAfterFirstLayout, registerPageSwapCallback);
@@ -9084,6 +9084,16 @@
}
}
+ /** @hide send content invalidate */
+ protected void contentInvalidateAll() {
+ mWebViewCore.sendMessage(EventHub.CONTENT_INVALIDATE_ALL);
+ }
+
+ /** @hide call pageSwapCallback upon next page swap */
+ protected void registerPageSwapCallback() {
+ nativeRegisterPageSwapCallback();
+ }
+
/**
* Begin collecting per-tile profiling data
*
@@ -9245,6 +9255,7 @@
private native void nativeStopGL();
private native Rect nativeSubtractLayers(Rect content);
private native int nativeTextGeneration();
+ private native void nativeRegisterPageSwapCallback();
private native void nativeTileProfilingStart();
private native float nativeTileProfilingStop();
private native void nativeTileProfilingClear();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8d8023b..400cdbd 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -999,6 +999,7 @@
static final int DUMP_V8COUNTERS = 173;
static final int SET_JS_FLAGS = 174;
+ static final int CONTENT_INVALIDATE_ALL = 175;
// Geolocation
static final int GEOLOCATION_PERMISSIONS_PROVIDE = 180;
@@ -1503,6 +1504,10 @@
nativeSetJsFlags((String)msg.obj);
break;
+ case CONTENT_INVALIDATE_ALL:
+ nativeContentInvalidateAll();
+ break;
+
case SAVE_WEBARCHIVE:
WebView.SaveWebArchiveMessage saveMessage =
(WebView.SaveWebArchiveMessage)msg.obj;
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index c4ba7c8..4b08f2d 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -1406,6 +1406,7 @@
v.setTranslationX(translationX);
drawOutline(mCanvas, bitmap);
+ mCanvas.setBitmap(null);
return bitmap;
}
@@ -1417,6 +1418,7 @@
dest.drawColor(0, PorterDuff.Mode.CLEAR);
dest.setMatrix(mIdentityMatrix);
dest.drawBitmap(mask, xy[0], xy[1], mHolographicPaint);
+ mMaskCanvas.setBitmap(null);
mask.recycle();
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ab66676..65ee745 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -999,7 +999,8 @@
setEllipsize(TextUtils.TruncateAt.END);
break;
case 4:
- setHorizontalFadingEdgeEnabled(true);
+ setHorizontalFadingEdgeEnabled(
+ ViewConfiguration.get(context).isFadingMarqueeEnabled());
setEllipsize(TextUtils.TruncateAt.MARQUEE);
break;
}
@@ -3067,7 +3068,8 @@
if (text instanceof Spanned &&
((Spanned) text).getSpanStart(TextUtils.TruncateAt.MARQUEE) >= 0) {
- setHorizontalFadingEdgeEnabled(true);
+ setHorizontalFadingEdgeEnabled(
+ ViewConfiguration.get(mContext).isFadingMarqueeEnabled());
setEllipsize(TextUtils.TruncateAt.MARQUEE);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f99a94c..21c3f1e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -294,12 +294,21 @@
<!-- Allows an application to read/write the voicemails owned by its own
package. -->
+ <!-- TODO: delete this permission when dependent content provider &
+ application code has been migrated to use ADD_VOICEMAIL instead -->
<permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="dangerous"
android:label="@string/permlab_readWriteOwnVoicemail"
android:description="@string/permdesc_readWriteOwnVoicemail" />
+ <!-- Allows an application to add voicemails into the system. -->
+ <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
+ android:permissionGroup="android.permission-group.PERSONAL_INFO"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_addVoicemail"
+ android:description="@string/permdesc_addVoicemail" />
+
<!-- ======================================= -->
<!-- Permissions for accessing location info -->
<!-- ======================================= -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dd16bd0..847afa0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -710,6 +710,22 @@
<enum name="preferExternal" value="2" />
</attr>
+ <!-- Extra options for an activity's UI. If specified on the application
+ tag these will be considered defaults for all activities in the
+ application. -->
+ <attr name="uiOptions">
+ <!-- No extra UI options. -->
+ <flag name="none" value="0" />
+ <!-- Split the options menu into a separate bar at the bottom of
+ the screen when severely constrained for horizontal space.
+ (e.g. portrait mode on a phone.) Instead of a small number
+ of action buttons appearing in the action bar at the top
+ of the screen, the action bar will split into the top navigation
+ section and the bottom menu section. Menu items will not be
+ split across the two bars; they will always appear together. -->
+ <flag name="splitActionBarWhenNarrow" value="1" />
+ </attr>
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -812,6 +828,7 @@
application is running, the user will be informed of this.
@hide -->
<attr name="cantSaveState" format="boolean" />
+ <attr name="uiOptions" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
@@ -1302,6 +1319,7 @@
<attr name="windowSoftInputMode" />
<attr name="immersive" />
<attr name="hardwareAccelerated" />
+ <attr name="uiOptions" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 65dce49..73443a0 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -84,6 +84,9 @@
specified for -large and -xlarge configurations. -->
<dimen name="config_prefDialogWidth">320dp</dimen>
+ <!-- Enables or disables fading edges when marquee is enabled in TextView. -->
+ <bool name="config_ui_enableFadingMarquee">true</bool>
+
<!-- Whether dialogs should close automatically when the user touches outside
of them. This should not normally be modified. -->
<bool name="config_closeDialogWhenTouchOutside">false</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 87e9249..2dfe453 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1783,11 +1783,11 @@
<public type="attr" name="minResizeHeight" />
<public type="attr" name="actionBarWidgetTheme" />
+ <public type="attr" name="uiOptions" />
<public type="style" name="TextAppearance.SuggestionHighlight" />
- <public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
- <public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
+ <public type="style" name="Theme.Holo.Light.DarkActionBar" />
<public type="style" name="Widget.Holo.Button.Borderless.Small" />
<public type="style" name="Widget.Holo.Light.Button.Borderless.Small" />
<public type="style" name="TextAppearance.Holo.Widget.ActionBar.Title.Inverse" />
@@ -1802,12 +1802,6 @@
<public type="style" name="Widget.Holo.Light.ActionBar.TabView.Inverse" />
<public type="style" name="Widget.Holo.Light.ActionBar.TabText.Inverse" />
<public type="style" name="Widget.Holo.Light.ActionMode.Inverse" />
- <public type="style" name="Theme.Holo.SolidActionBar" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar.Inverse" />
- <public type="style" name="Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar.SplitActionBarWhenNarrow" />
- <public type="style" name="Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow" />
<public type="integer" name="status_bar_notification_info_maxnum" />
<public type="string" name="status_bar_notification_info_overflow" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c5aa4b2..a6c92f2 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2166,6 +2166,14 @@
voicemails that its associated service can access.</string>
<!-- Title of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permlab_addVoicemail">add voicemail</string>
+ <!-- Description of an application permission, listed so the user can choose whether
+ they want to allow the application to do this. [CHAR LIMIT=NONE] -->
+ <string name="permdesc_addVoicemail">Allows the application to add messages
+ to your voicemail inbox.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_writeGeolocationPermissions">Modify Browser geolocation permissions</string>
<!-- Description of an application permission, listed so the user can choose whether
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3e7c5ca..2b1b693 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -1207,7 +1207,7 @@
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
<item name="windowIsFloating">false</item>
- <item name="windowContentOverlay">@null</item>
+ <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
<item name="windowShowWallpaper">false</item>
<item name="windowTitleStyle">@android:style/WindowTitle.Holo</item>
<item name="windowTitleSize">25dip</item>
@@ -1337,7 +1337,7 @@
<item name="actionBarTabTextStyle">@style/Widget.Holo.Light.ActionBar.TabText</item>
<item name="actionModeStyle">@style/Widget.Holo.Light.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Holo.Light.ActionButton.CloseMode</item>
- <item name="actionBarStyle">@android:style/Widget.Holo.Light.ActionBar</item>
+ <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid</item>
<item name="actionBarSize">@dimen/action_bar_default_height</item>
<item name="actionModePopupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow.ActionMode</item>
<item name="actionBarWidgetTheme">@null</item>
@@ -1384,22 +1384,10 @@
</style>
- <!-- Variant of the holographic (dark) theme that has a solid (opaque) action bar. -->
- <style name="Theme.Holo.SolidActionBar">
- <item name="android:actionBarStyle">@android:style/Widget.Holo.ActionBar.Solid</item>
- <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
- </style>
-
- <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar. -->
- <style name="Theme.Holo.Light.SolidActionBar">
- <item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid</item>
- <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
- </style>
-
<!-- Variant of the holographic (light) theme that has a solid (opaque) action bar
with an inverse color profile. The dark action bar sharply stands out against
the light content. -->
- <style name="Theme.Holo.Light.SolidActionBar.Inverse">
+ <style name="Theme.Holo.Light.DarkActionBar">
<item name="android:windowContentOverlay">@android:drawable/title_bar_shadow</item>
<item name="android:actionBarStyle">@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse</item>
<item name="actionBarWidgetTheme">@android:style/Theme.Holo</item>
@@ -1427,30 +1415,6 @@
<item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_dark</item>
</style>
- <!-- Variant of the holographic (dark) theme that has a solid
- (opaque) action bar. The action bar will split across both
- the top and bottom of the screen when the screen is
- especially constrained for horizontal space. -->
- <style name="Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
- <!-- Variant of the holographic (light) theme that has a solid
- (opaque) action bar. The action bar will split across both
- the top and bottom of the screen when the screen is
- especially constrained for horizontal space. -->
- <style name="Theme.Holo.Light.SolidActionBar.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
- <!-- Variant of the holographic (light) theme that has a solid (opaque) action bar
- with an inverse color profile. The dark action bar sharply stands out against
- the light content. The action bar will split across both the top and bottom of
- the screen when the screen is especially constrained for horizontal space. -->
- <style name="Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
<!-- Variant of the holographic (dark) theme with no action bar. -->
<style name="Theme.Holo.NoActionBar">
<item name="android:windowActionBar">false</item>
@@ -1654,18 +1618,4 @@
<style name="Theme.Holo.Wallpaper.NoTitleBar">
<item name="android:windowNoTitle">true</item>
</style>
-
- <!-- Variant of the holographic (dark) theme with an action bar that
- splits across the top and bottom of the activity when constrained
- for horizontal space. -->
- <style name="Theme.Holo.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
-
- <!-- Variant of the holographic (light) theme with an action bar that
- splits across the top and bottom of the activity when constrained
- for horizontal space. -->
- <style name="Theme.Holo.Light.SplitActionBarWhenNarrow">
- <item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
- </style>
</resources>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 40d54bb..3fc6463 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -567,6 +567,7 @@
canvas.setBitmap(bitmap);
canvas.drawBitmap(source, srcR, dstR, paint);
+ canvas.setBitmap(null);
return bitmap;
}
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9bf3de8..9acf99b 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -44,9 +44,11 @@
///////////////////////////////////////////////////////////////////////////////
Font::Font(FontRenderer* state, uint32_t fontId, float fontSize,
- int flags, uint32_t italicStyle, uint32_t scaleX) :
+ int flags, uint32_t italicStyle, uint32_t scaleX,
+ SkPaint::Style style, uint32_t strokeWidth) :
mState(state), mFontId(fontId), mFontSize(fontSize),
- mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX) {
+ mFlags(flags), mItalicStyle(italicStyle), mScaleX(scaleX),
+ mStyle(style), mStrokeWidth(mStrokeWidth) {
}
@@ -283,19 +285,22 @@
}
Font* Font::create(FontRenderer* state, uint32_t fontId, float fontSize,
- int flags, uint32_t italicStyle, uint32_t scaleX) {
+ int flags, uint32_t italicStyle, uint32_t scaleX,
+ SkPaint::Style style, uint32_t strokeWidth) {
Vector<Font*> &activeFonts = state->mActiveFonts;
for (uint32_t i = 0; i < activeFonts.size(); i++) {
Font* font = activeFonts[i];
if (font->mFontId == fontId && font->mFontSize == fontSize &&
font->mFlags == flags && font->mItalicStyle == italicStyle &&
- font->mScaleX == scaleX) {
+ font->mScaleX == scaleX && font->mStyle == style &&
+ (style == SkPaint::kFill_Style || font->mStrokeWidth == strokeWidth)) {
return font;
}
}
- Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle, scaleX);
+ Font* newFont = new Font(state, fontId, fontSize, flags, italicStyle,
+ scaleX, style, strokeWidth);
activeFonts.push(newFont);
return newFont;
}
@@ -690,7 +695,11 @@
uint32_t italicStyle = *(uint32_t*) &skewX;
const float scaleXFloat = paint->getTextScaleX();
uint32_t scaleX = *(uint32_t*) &scaleXFloat;
- mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle, scaleX);
+ SkPaint::Style style = paint->getStyle();
+ const float strokeWidthFloat = paint->getStrokeWidth();
+ uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
+ mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
+ scaleX, style, strokeWidth);
const float maxPrecacheFontSize = 40.0f;
bool isNewFont = currentNumFonts != mActiveFonts.size();
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 24ed6fa..1922812 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -82,7 +82,8 @@
* Creates a new font associated with the specified font state.
*/
static Font* create(FontRenderer* state, uint32_t fontId, float fontSize,
- int flags, uint32_t italicStyle, uint32_t scaleX);
+ int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style,
+ uint32_t strokeWidth);
protected:
friend class FontRenderer;
@@ -128,7 +129,7 @@
};
Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle,
- uint32_t scaleX);
+ uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth);
// Cache of glyphs
DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
@@ -157,6 +158,8 @@
int mFlags;
uint32_t mItalicStyle;
uint32_t mScaleX;
+ SkPaint::Style mStyle;
+ uint32_t mStrokeWidth;
};
///////////////////////////////////////////////////////////////////////////////
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7258e11..731d1f3 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1646,7 +1646,8 @@
IAudioService service = getService();
try {
status = service.requestAudioFocus(streamType, durationHint, mICallBack,
- mAudioFocusDispatcher, getIdForAudioFocusListener(l));
+ mAudioFocusDispatcher, getIdForAudioFocusListener(l),
+ mContext.getPackageName() /* package name */);
} catch (RemoteException e) {
Log.e(TAG, "Can't call requestAudioFocus() from AudioService due to "+e);
}
@@ -1682,7 +1683,9 @@
* in the application manifest.
*/
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
- //TODO enforce the rule about the receiver being declared in the manifest
+ if (eventReceiver == null) {
+ return;
+ }
IAudioService service = getService();
try {
service.registerMediaButtonEventReceiver(eventReceiver);
@@ -1697,6 +1700,9 @@
* that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
*/
public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
+ if (eventReceiver == null) {
+ return;
+ }
IAudioService service = getService();
try {
service.unregisterMediaButtonEventReceiver(eventReceiver);
@@ -1706,6 +1712,126 @@
}
/**
+ * @hide
+ * Registers the remote control client for providing information to display on the remotes.
+ * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
+ * that will receive the media button intent, and associated with the remote control
+ * client. This method has no effect if
+ * {@link #registerMediaButtonEventReceiver(ComponentName)} hasn't been called
+ * with the same eventReceiver, or if
+ * {@link #unregisterMediaButtonEventReceiver(ComponentName)} has been called.
+ * @param rcClient the client associated with the event receiver, responsible for providing
+ * the information to display on the remote control.
+ */
+ public void registerRemoteControlClient(ComponentName eventReceiver,
+ IRemoteControlClient rcClient) {
+ if (eventReceiver == null) {
+ return;
+ }
+ IAudioService service = getService();
+ try {
+ service.registerRemoteControlClient(eventReceiver, rcClient,
+ // used to match media button event receiver and audio focus
+ mContext.getPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in registerRemoteControlClient"+e);
+ }
+ }
+
+ /**
+ * @hide
+ * @param eventReceiver
+ */
+ public void unregisterRemoteControlClient(ComponentName eventReceiver) {
+ if (eventReceiver == null) {
+ return;
+ }
+ IAudioService service = getService();
+ try {
+ // unregistering a IRemoteControlClient is equivalent to setting it to null
+ service.registerRemoteControlClient(eventReceiver, null, mContext.getPackageName());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e);
+ }
+ }
+
+ /**
+ * @hide
+ * Definitions of constants to be used in {@link android.media.IRemoteControlClient}.
+ */
+ public final class RemoteControlParameters {
+ public final static int PLAYSTATE_STOPPED = 1;
+ public final static int PLAYSTATE_PAUSED = 2;
+ public final static int PLAYSTATE_PLAYING = 3;
+ public final static int PLAYSTATE_FAST_FORWARDING = 4;
+ public final static int PLAYSTATE_REWINDING = 5;
+ public final static int PLAYSTATE_SKIPPING_FORWARDS = 6;
+ public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7;
+ public final static int PLAYSTATE_BUFFERING = 8;
+
+ public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
+ public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
+ public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
+ public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
+ public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
+ public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
+ public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
+ public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
+ }
+
+ /**
+ * @hide
+ * Broadcast intent action indicating that the displays on the remote controls
+ * should be updated because a new remote control client is now active. If there is no
+ * {@link #EXTRA_REMOTE_CONTROL_CLIENT}, the remote control display should be cleared
+ * because there is no valid client to supply it with information.
+ *
+ * @see #EXTRA_REMOTE_CONTROL_CLIENT
+ */
+ public static final String REMOTE_CONTROL_CLIENT_CHANGED =
+ "android.media.REMOTE_CONTROL_CLIENT_CHANGED";
+
+ /**
+ * @hide
+ * The IRemoteControlClient monotonically increasing generation counter.
+ *
+ * @see #REMOTE_CONTROL_CLIENT_CHANGED_ACTION
+ */
+ public static final String EXTRA_REMOTE_CONTROL_CLIENT =
+ "android.media.EXTRA_REMOTE_CONTROL_CLIENT";
+
+ /**
+ * @hide
+ * FIXME to be changed to address Neel's comments
+ * Force a refresh of the remote control client associated with the event receiver.
+ * @param eventReceiver
+ */
+ public void refreshRemoteControlDisplay(ComponentName eventReceiver) {
+ IAudioService service = getService();
+ try {
+ service.refreshRemoteControlDisplay(eventReceiver);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in refreshRemoteControlDisplay"+e);
+ }
+ }
+
+ /**
+ * @hide
+ * FIXME API to be used by implementors of remote controls, not a candidate for SDK
+ */
+ public void registerRemoteControlObserver() {
+
+ }
+
+ /**
+ * @hide
+ * FIXME API to be used by implementors of remote controls, not a candidate for SDK
+ */
+ public void unregisterRemoteControlObserver() {
+
+ }
+
+ /**
* @hide
* Reload audio settings. This method is called by Settings backup
* agent when audio settings are restored and causes the AudioService
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 682560a..3e786c3 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -55,6 +55,7 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -113,6 +114,8 @@
private static final int MSG_SET_FORCE_USE = 10;
private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 11;
private static final int MSG_BT_HEADSET_CNCT_FAILED = 12;
+ private static final int MSG_RCDISPLAY_CLEAR = 13;
+ private static final int MSG_RCDISPLAY_UPDATE = 14;
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
// Timeout for connection to bluetooth headset service
@@ -371,7 +374,9 @@
// Register for media button intent broadcasts.
intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
- intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ // Workaround for bug on priority setting
+ //intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ intentFilter.setPriority(Integer.MAX_VALUE);
context.registerReceiver(mMediaButtonReceiver, intentFilter);
// Register for phone state monitoring
@@ -885,7 +890,8 @@
requestAudioFocus(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
- IN_VOICE_COMM_FOCUS_ID /*clientId*/);
+ IN_VOICE_COMM_FOCUS_ID /*clientId*/,
+ "system");
}
}
@@ -897,7 +903,8 @@
requestAudioFocus(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
- IN_VOICE_COMM_FOCUS_ID /*clientId*/);
+ IN_VOICE_COMM_FOCUS_ID /*clientId*/,
+ "system");
}
// if exiting call
else if (newMode == AudioSystem.MODE_NORMAL) {
@@ -2155,6 +2162,33 @@
persistMediaButtonReceiver( (ComponentName) msg.obj );
break;
+ case MSG_RCDISPLAY_CLEAR:
+ Log.i(TAG, "Clear remote control display");
+ Intent clearIntent = new Intent(AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
+ // no extra means no IRemoteControlClient, which is a request to clear
+ clearIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcast(clearIntent);
+ break;
+
+ case MSG_RCDISPLAY_UPDATE:
+ synchronized(mCurrentRcLock) {
+ if (mCurrentRcClientRef.get() == null) {
+ // the remote control display owner has changed between the
+ // the message to update the display was sent, and the time it
+ // gets to be processed (now)
+ } else {
+ mCurrentRcClientGen++;
+ Log.i(TAG, "Display/update remote control ");
+ Intent rcClientIntent = new Intent(
+ AudioManager.REMOTE_CONTROL_CLIENT_CHANGED);
+ rcClientIntent.putExtra(AudioManager.EXTRA_REMOTE_CONTROL_CLIENT,
+ mCurrentRcClientGen);
+ rcClientIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ mContext.sendBroadcast(rcClientIntent);
+ }
+ }
+ break;
+
case MSG_BT_HEADSET_CNCT_FAILED:
resetBluetoothSco();
break;
@@ -2567,23 +2601,25 @@
private static class FocusStackEntry {
public int mStreamType = -1;// no stream type
- public boolean mIsTransportControlReceiver = false;
public IAudioFocusDispatcher mFocusDispatcher = null;
public IBinder mSourceRef = null;
public String mClientId;
public int mFocusChangeType;
+ public String mPackageName;
+ public int mCallingUid;
public FocusStackEntry() {
}
- public FocusStackEntry(int streamType, int duration, boolean isTransportControlReceiver,
- IAudioFocusDispatcher afl, IBinder source, String id) {
+ public FocusStackEntry(int streamType, int duration,
+ IAudioFocusDispatcher afl, IBinder source, String id, String pn, int uid) {
mStreamType = streamType;
- mIsTransportControlReceiver = isTransportControlReceiver;
mFocusDispatcher = afl;
mSourceRef = source;
mClientId = id;
mFocusChangeType = duration;
+ mPackageName = pn;
+ mCallingUid = uid;
}
}
@@ -2600,13 +2636,15 @@
while(stackIterator.hasNext()) {
FocusStackEntry fse = stackIterator.next();
pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId
- + " -- duration: " +fse.mFocusChangeType);
+ + " -- duration: " + fse.mFocusChangeType
+ + " -- uid: " + fse.mCallingUid);
}
}
}
/**
* Helper function:
+ * Called synchronized on mAudioFocusLock
* Remove a focus listener from the focus stack.
* @param focusListenerToRemove the focus listener
* @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
@@ -2621,6 +2659,10 @@
if (signal) {
// notify the new top of the stack it gained focus
notifyTopOfAudioFocusStack();
+ // there's a new top of the stack, let the remote control know
+ synchronized(mRCStack) {
+ checkUpdateRemoteControlDisplay();
+ }
}
} else {
// focus is abandoned by a client that's not at the top of the stack,
@@ -2639,6 +2681,7 @@
/**
* Helper function:
+ * Called synchronized on mAudioFocusLock
* Remove focus listeners from the focus stack for a particular client.
*/
private void removeFocusStackEntryForClient(IBinder cb) {
@@ -2658,6 +2701,10 @@
// we removed an entry at the top of the stack:
// notify the new top of the stack it gained focus.
notifyTopOfAudioFocusStack();
+ // there's a new top of the stack, let the remote control know
+ synchronized(mRCStack) {
+ checkUpdateRemoteControlDisplay();
+ }
}
}
@@ -2700,7 +2747,7 @@
/** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
- IAudioFocusDispatcher fd, String clientId) {
+ IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId);
// the main stream type for the audio focus request is currently not used. It may
// potentially be used to handle multiple stream type-dependent audio focuses.
@@ -2743,8 +2790,13 @@
removeFocusStackEntry(clientId, false);
// push focus requester at the top of the audio focus stack
- mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, false, fd, cb,
- clientId));
+ mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
+ clientId, callingPackageName, Binder.getCallingUid()));
+
+ // there's a new top of the stack, let the remote control know
+ synchronized(mRCStack) {
+ checkUpdateRemoteControlDisplay();
+ }
}//synchronized(mAudioFocusLock)
// handle the potential premature death of the new holder of the focus
@@ -2831,19 +2883,100 @@
}
}
- private static class RemoteControlStackEntry {
- public ComponentName mReceiverComponent;// always non null
- // TODO implement registration expiration?
- //public int mRegistrationTime;
+ private final static Object mCurrentRcLock = new Object();
+ /**
+ * The one remote control client to be polled for display information.
+ * This object is never null, but its reference might.
+ * Access protected by mCurrentRcLock.
+ */
+ private static SoftReference<IRemoteControlClient> mCurrentRcClientRef =
+ new SoftReference<IRemoteControlClient>(null);
- public RemoteControlStackEntry() {
- }
+ /**
+ * A monotonically increasing generation counter for mCurrentRcClientRef.
+ * Only accessed with a lock on mCurrentRcLock.
+ */
+ private static int mCurrentRcClientGen = 0;
- public RemoteControlStackEntry(ComponentName r) {
- mReceiverComponent = r;
+ /**
+ * Returns the current remote control client.
+ * @param rcClientId the counter value that matches the extra
+ * {@link AudioManager#EXTRA_REMOTE_CONTROL_CLIENT} in the
+ * {@link AudioManager#REMOTE_CONTROL_CLIENT_CHANGED} event
+ * @return the current IRemoteControlClient from which information to display on the remote
+ * control can be retrieved, or null if rcClientId doesn't match the current generation
+ * counter.
+ */
+ public static IRemoteControlClient getRemoteControlClient(int rcClientId) {
+ synchronized(mCurrentRcLock) {
+ if (rcClientId == mCurrentRcClientGen) {
+ return mCurrentRcClientRef.get();
+ } else {
+ return null;
+ }
}
}
+ /**
+ * Inner class to monitor remote control client deaths, and remove the client for the
+ * remote control stack if necessary.
+ */
+ private class RcClientDeathHandler implements IBinder.DeathRecipient {
+ private IBinder mCb; // To be notified of client's death
+ private ComponentName mRcEventReceiver;
+
+ RcClientDeathHandler(IBinder cb, ComponentName eventReceiver) {
+ mCb = cb;
+ mRcEventReceiver = eventReceiver;
+ }
+
+ public void binderDied() {
+ Log.w(TAG, " RemoteControlClient died");
+ // remote control client died, make sure the displays don't use it anymore
+ // by setting its remote control client to null
+ registerRemoteControlClient(mRcEventReceiver, null, null/*ignored*/);
+ }
+
+ public IBinder getBinder() {
+ return mCb;
+ }
+ }
+
+ private static class RemoteControlStackEntry {
+ /** the target for the ACTION_MEDIA_BUTTON events */
+ public ComponentName mReceiverComponent;// always non null
+ public String mCallingPackageName;
+ public int mCallingUid;
+
+ /** provides access to the information to display on the remote control */
+ public SoftReference<IRemoteControlClient> mRcClientRef;
+ public RcClientDeathHandler mRcClientDeathHandler;
+
+ public RemoteControlStackEntry(ComponentName r) {
+ mReceiverComponent = r;
+ mCallingUid = -1;
+ mRcClientRef = new SoftReference<IRemoteControlClient>(null);
+ }
+
+ public void unlinkToRcClientDeath() {
+ if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
+ try {
+ mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
+ } catch (java.util.NoSuchElementException e) {
+ // not much we can do here
+ Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * The stack of remote control event receivers.
+ * Code sections and methods that modify the remote control event receiver stack are
+ * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
+ * stack, audio focus or RC, can lead to a change in the remote control display
+ */
private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
/**
@@ -2855,8 +2988,10 @@
synchronized(mRCStack) {
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
while(stackIterator.hasNext()) {
- RemoteControlStackEntry fse = stackIterator.next();
- pw.println(" receiver:" + fse.mReceiverComponent);
+ RemoteControlStackEntry rcse = stackIterator.next();
+ pw.println(" receiver: " + rcse.mReceiverComponent +
+ " -- client: " + rcse.mRcClientRef.get() +
+ " -- uid: " + rcse.mCallingUid);
}
}
}
@@ -2909,6 +3044,7 @@
ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
registerMediaButtonEventReceiver(receiverComponentName);
}
+ // upon restoring (e.g. after boot), do we want to refresh all remotes?
}
/**
@@ -2921,14 +3057,20 @@
return;
}
Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+ RemoteControlStackEntry rcse = null;
+ boolean wasInsideStack = false;
while(stackIterator.hasNext()) {
- RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+ rcse = (RemoteControlStackEntry)stackIterator.next();
if(rcse.mReceiverComponent.equals(newReceiver)) {
+ wasInsideStack = true;
stackIterator.remove();
break;
}
}
- mRCStack.push(new RemoteControlStackEntry(newReceiver));
+ if (!wasInsideStack) {
+ rcse = new RemoteControlStackEntry(newReceiver);
+ }
+ mRCStack.push(rcse);
// post message to persist the default media button receiver
mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
@@ -2950,13 +3092,88 @@
}
}
+ /**
+ * Helper function:
+ * Called synchronized on mRCStack
+ */
+ private boolean isCurrentRcController(ComponentName eventReceiver) {
+ if (!mRCStack.empty() && mRCStack.peek().mReceiverComponent.equals(eventReceiver)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Helper function:
+ * Called synchronized on mRCStack
+ */
+ private void clearRemoteControlDisplay() {
+ synchronized(mCurrentRcLock) {
+ mCurrentRcClientRef.clear();
+ }
+ mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
+ }
+
+ /**
+ * Helper function:
+ * Called synchronized on mRCStack
+ * mRCStack.empty() is false
+ */
+ private void updateRemoteControlDisplay() {
+ RemoteControlStackEntry rcse = mRCStack.peek();
+ // this is where we enforce opt-in for information display on the remote controls
+ // with the new AudioManager.registerRemoteControlClient() API
+ if (rcse.mRcClientRef.get() == null) {
+ // FIXME remove log before release: this warning will be displayed for every AF change
+ Log.w(TAG, "Can't update remote control display with null remote control client");
+ clearRemoteControlDisplay();
+ return;
+ }
+ synchronized(mCurrentRcLock) {
+ mCurrentRcClientRef = rcse.mRcClientRef;
+ }
+ mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 0, 0, rcse) );
+ }
+
+ /**
+ * Helper function:
+ * Called synchronized on mFocusLock, then mRCStack
+ * Check whether the remote control display should be updated, triggers the update if required
+ */
+ private void checkUpdateRemoteControlDisplay() {
+ // determine whether the remote control display should be refreshed
+ // if either stack is empty, there is a mismatch, so clear the RC display
+ if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
+ clearRemoteControlDisplay();
+ return;
+ }
+ // if the top of the two stacks belong to different packages, there is a mismatch, clear
+ if ((mRCStack.peek().mCallingPackageName != null)
+ && (mFocusStack.peek().mPackageName != null)
+ && !(mRCStack.peek().mCallingPackageName.compareTo(
+ mFocusStack.peek().mPackageName) == 0)) {
+ clearRemoteControlDisplay();
+ return;
+ }
+ // if the audio focus didn't originate from the same Uid as the one in which the remote
+ // control information will be retrieved, clear
+ if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) {
+ clearRemoteControlDisplay();
+ return;
+ }
+ // refresh conditions were verified: update the remote controls
+ updateRemoteControlDisplay();
+ }
/** see AudioManager.registerMediaButtonEventReceiver(ComponentName eventReceiver) */
public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Log.i(TAG, " Remote Control registerMediaButtonEventReceiver() for " + eventReceiver);
- synchronized(mRCStack) {
- pushMediaButtonReceiver(eventReceiver);
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ pushMediaButtonReceiver(eventReceiver);
+ checkUpdateRemoteControlDisplay();
+ }
}
}
@@ -2964,11 +3181,74 @@
public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Log.i(TAG, " Remote Control unregisterMediaButtonEventReceiver() for " + eventReceiver);
- synchronized(mRCStack) {
- removeMediaButtonReceiver(eventReceiver);
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ boolean topOfStackWillChange = isCurrentRcController(eventReceiver);
+ removeMediaButtonReceiver(eventReceiver);
+ if (topOfStackWillChange) {
+ checkUpdateRemoteControlDisplay();
+ }
+ }
}
}
+ /** see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) */
+ public void registerRemoteControlClient(ComponentName eventReceiver,
+ IRemoteControlClient rcClient, String callingPackageName) {
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ // store the new display information
+ Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+ while(stackIterator.hasNext()) {
+ RemoteControlStackEntry rcse = stackIterator.next();
+ if(rcse.mReceiverComponent.equals(eventReceiver)) {
+ // already had a remote control client?
+ if (rcse.mRcClientDeathHandler != null) {
+ // stop monitoring the old client's death
+ rcse.unlinkToRcClientDeath();
+ }
+ // save the new remote control client
+ rcse.mRcClientRef = new SoftReference<IRemoteControlClient>(rcClient);
+ rcse.mCallingPackageName = callingPackageName;
+ rcse.mCallingUid = Binder.getCallingUid();
+ if (rcClient == null) {
+ break;
+ }
+ // monitor the new client's death
+ IBinder b = rcClient.asBinder();
+ RcClientDeathHandler rcdh =
+ new RcClientDeathHandler(b, rcse.mReceiverComponent);
+ try {
+ b.linkToDeath(rcdh, 0);
+ } catch (RemoteException e) {
+ // remote control client is DOA, disqualify it
+ Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
+ rcse.mRcClientRef.clear();
+ }
+ rcse.mRcClientDeathHandler = rcdh;
+ break;
+ }
+ }
+ // if the eventReceiver is at the top of the stack
+ // then check for potential refresh of the remote controls
+ if (isCurrentRcController(eventReceiver)) {
+ checkUpdateRemoteControlDisplay();
+ }
+ }
+ }
+ }
+
+ /** see AudioManager.refreshRemoteControlDisplay(ComponentName er) */
+ public void refreshRemoteControlDisplay(ComponentName eventReceiver) {
+ synchronized(mAudioFocusLock) {
+ synchronized(mRCStack) {
+ // only refresh if the eventReceiver is at the top of the stack
+ if (isCurrentRcController(eventReceiver)) {
+ checkUpdateRemoteControlDisplay();
+ }
+ }
+ }
+ }
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index e3bd7b4..1a05f152 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -18,6 +18,9 @@
import android.content.ComponentName;
import android.media.IAudioFocusDispatcher;
+import android.media.IRemoteControlClient;
+import android.net.Uri;
+import android.os.Bundle;
/**
* {@hide}
@@ -77,7 +80,7 @@
boolean isBluetoothScoOn();
int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb, IAudioFocusDispatcher l,
- String clientId);
+ String clientId, String callingPackageName);
int abandonAudioFocus(IAudioFocusDispatcher l, String clientId);
@@ -87,6 +90,11 @@
void unregisterMediaButtonEventReceiver(in ComponentName eventReceiver);
+ void registerRemoteControlClient(in ComponentName eventReceiver,
+ in IRemoteControlClient rcClient, in String callingPackageName);
+
+ void refreshRemoteControlDisplay(in ComponentName eventReceiver);
+
void startBluetoothSco(IBinder cb);
void stopBluetoothSco(IBinder cb);
diff --git a/media/java/android/media/IRemoteControlClient.aidl b/media/java/android/media/IRemoteControlClient.aidl
new file mode 100644
index 0000000..a49371c
--- /dev/null
+++ b/media/java/android/media/IRemoteControlClient.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.graphics.Bitmap;
+
+/**
+ * {@hide}
+ */
+interface IRemoteControlClient
+{
+ /**
+ * Called by a remote control to retrieve a String of information to display.
+ * @param field the identifier for a metadata field to retrieve. Valid values are
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER},
+ * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
+ * @return null if the given field is not supported, or the String matching the metadata field.
+ */
+ String getMetadataString(int field);
+
+ /**
+ * Returns the current playback state.
+ * @return one of the following values:
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_STOPPED},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_PAUSED},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_PLAYING},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_FAST_FORWARDING},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_REWINDING},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_SKIPPING_FORWARDS},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_SKIPPING_BACKWARDS},
+ * {@link android.media.AudioManager.RemoteControl#PLAYSTATE_BUFFERING}.
+ */
+ int getPlaybackState();
+
+ /**
+ * Returns the flags for the media transport control buttons this client supports.
+ * @see {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PREVIOUS},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_REWIND},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PLAY},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PLAY_PAUSE},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_PAUSE},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_STOP},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_FAST_FORWARD},
+ * {@link android.media.AudioManager.RemoteControl#FLAG_KEY_MEDIA_NEXT}
+ */
+ int getTransportControlFlags();
+
+ Bitmap getAlbumArt(int width, int height);
+}
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 7c181ee..078d4af 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -387,6 +387,7 @@
if (recycle) {
source.recycle();
}
+ c.setBitmap(null);
return b2;
}
float bitmapWidthF = source.getWidth();
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index 6b0fb12..5bfdcdb 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -3761,6 +3761,7 @@
final Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(tempBitmap, new Rect(0, 0, newWidth, newHeight),
new Rect(0, 0, width, height), sResizePaint);
+ canvas.setBitmap(null);
}
if (tempBitmap != null) {
@@ -3837,6 +3838,7 @@
final Canvas canvas = new Canvas(bitmaps[i]);
canvas.drawBitmap(tempBitmap, new Rect(0, 0, newWidth, newHeight),
new Rect(0, 0, width, height), sResizePaint);
+ canvas.setBitmap(null);
}
}
diff --git a/media/java/android/media/videoeditor/MediaImageItem.java b/media/java/android/media/videoeditor/MediaImageItem.java
index 73cc7e2..f0cc1fe 100755
--- a/media/java/android/media/videoeditor/MediaImageItem.java
+++ b/media/java/android/media/videoeditor/MediaImageItem.java
@@ -1008,6 +1008,7 @@
srcBitmap.getHeight()),
new Rect(0, 0, (int)bitmapWidth,
(int)bitmapHeight), sResizePaint);
+ canvas.setBitmap(null);
/**
* Release the source bitmap
*/
diff --git a/media/java/android/media/videoeditor/OverlayFrame.java b/media/java/android/media/videoeditor/OverlayFrame.java
index 131f5f0..d159df2 100755
--- a/media/java/android/media/videoeditor/OverlayFrame.java
+++ b/media/java/android/media/videoeditor/OverlayFrame.java
@@ -420,6 +420,7 @@
}
overlayCanvas.drawBitmap(overlayBitmap, srcRect, destRect, sResizePaint);
+ overlayCanvas.setBitmap(null);
/*
* Write to the dest file
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ac73351..a4f3922 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -976,11 +976,6 @@
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
video_def->xFramerate = 0; // No need for output port
- // FIXME:
- // Revmoe this workaround after work is done.
- if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) {
- video_def->xFramerate = (frameRate << 16);
- }
video_def->nBitrate = bitRate; // Q16 format
video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 3f547fd..4c7f84e 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1073,6 +1073,15 @@
return gl;
}
+ public void purgeBuffers() {
+ mEgl.eglMakeCurrent(mEglDisplay,
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,
+ EGL10.EGL_NO_CONTEXT);
+ mEgl.eglMakeCurrent(mEglDisplay,
+ mEglSurface, mEglSurface,
+ mEglContext);
+ }
+
/**
* Display the current render surface.
* @return false if the context has been lost.
@@ -1415,6 +1424,7 @@
if (LOG_RENDERER) {
Log.w("GLThread", "onSurfaceChanged(" + w + ", " + h + ")");
}
+ mEglHelper.purgeBuffers();
mRenderer.onSurfaceChanged(gl, w, h);
sizeChanged = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index c896046..d74b548 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -501,6 +501,7 @@
new RectF(mGlowBitmapPaddingLeftPx, mGlowBitmapPaddingTopPx,
outBitmap.getWidth() - mGlowBitmapPaddingRightPx,
outBitmap.getHeight() - mGlowBitmapPaddingBottomPx), paint);
+ canvas.setBitmap(null);
}
return outBitmap;
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 3a47e6e..fc21929 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -294,6 +294,7 @@
c.rotate(360f - degrees);
c.translate(-dims[0] / 2, -dims[1] / 2);
c.drawBitmap(mScreenBitmap, 0, 0, null);
+ c.setBitmap(null);
mScreenBitmap = ss;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
index 51fc7c2..3276e1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ExpandedView.java
@@ -16,16 +16,9 @@
package com.android.systemui.statusbar.phone;
-import android.animation.LayoutTransition;
import android.content.Context;
import android.util.AttributeSet;
-import android.view.Display;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.WindowManager;
import android.widget.LinearLayout;
-import android.util.Slog;
-
public class ExpandedView extends LinearLayout {
PhoneStatusBar mService;
@@ -38,8 +31,6 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
- setLayerType(LAYER_TYPE_HARDWARE, null);
}
/** We want to shrink down to 0, and ignore the background. */
@@ -49,7 +40,7 @@
}
@Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int height = bottom - top;
if (height != mPrevHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 18026f1..d25a827 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -16,12 +16,10 @@
package com.android.systemui.statusbar.phone;
-import android.app.Service;
import android.app.ActivityManagerNative;
import android.app.Dialog;
import android.app.Notification;
import android.app.PendingIntent;
-import android.app.Service;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -30,6 +28,7 @@
import android.content.res.Resources;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
@@ -65,16 +64,12 @@
import android.widget.RemoteViews;
import android.widget.ScrollView;
import android.widget.TextView;
-import android.widget.FrameLayout;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Set;
import com.android.internal.statusbar.StatusBarIcon;
-import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.systemui.R;
@@ -186,7 +181,6 @@
boolean mAnimating;
long mCurAnimationTime;
- float mDisplayHeight;
float mAnimY;
float mAnimVel;
float mAnimAccel;
@@ -201,6 +195,8 @@
// tracking calls to View.setSystemUiVisibility()
int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
+ final Point mDisplaySize = new Point();
+
private class ExpandedDialog extends Dialog {
ExpandedDialog(Context context) {
super(context, com.android.internal.R.style.Theme_Light_NoTitleBar);
@@ -246,8 +242,11 @@
Resources res = context.getResources();
+ mDisplay.getSize(mDisplaySize);
loadDimens();
+ mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);
+
ExpandedView expanded = (ExpandedView)View.inflate(context,
R.layout.status_bar_expanded, null);
expanded.mService = this;
@@ -1149,7 +1148,7 @@
if (mAnimating) {
y = (int)mAnimY;
} else {
- y = mDisplay.getHeight()-1;
+ y = mDisplaySize.y-1;
}
// Let the fling think that we're open so it goes in the right direction
// and doesn't try to re-open the windowshade.
@@ -1205,7 +1204,7 @@
if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
incrementAnim();
if (SPEW) Slog.d(TAG, "doAnimation after mAnimY=" + mAnimY);
- if (mAnimY >= mDisplay.getHeight()-1) {
+ if (mAnimY >= mDisplaySize.y-1) {
if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
mAnimating = false;
updateExpandedViewPos(EXPANDED_FULL_OPEN);
@@ -1291,7 +1290,6 @@
void performFling(int y, float vel, boolean always) {
mAnimatingReveal = false;
- mDisplayHeight = mDisplay.getHeight();
mAnimY = y;
mAnimVel = vel;
@@ -1301,7 +1299,7 @@
if (mExpanded) {
if (!always && (
vel > 200.0f
- || (y > (mDisplayHeight-25) && vel > -200.0f))) {
+ || (y > (mDisplaySize.y-25) && vel > -200.0f))) {
// We are expanded, but they didn't move sufficiently to cause
// us to retract. Animate back to the expanded position.
mAnimAccel = 2000.0f;
@@ -1319,7 +1317,7 @@
} else {
if (always || (
vel > 200.0f
- || (y > (mDisplayHeight/2) && vel > -200.0f))) {
+ || (y > (mDisplaySize.y/2) && vel > -200.0f))) {
// We are collapsed, and they moved enough to allow us to
// expand. Animate in the notifications.
mAnimAccel = 2000.0f;
@@ -1371,14 +1369,14 @@
mViewDelta = mAbsPos[1] + mTrackingView.getHeight() - y;
}
if ((!mExpanded && y < hitSize) ||
- (mExpanded && y > (mDisplay.getHeight()-hitSize))) {
+ (mExpanded && y > (mDisplaySize.y-hitSize))) {
// We drop events at the edge of the screen to make the windowshade come
// down by accident less, especially when pushing open a device with a keyboard
// that rotates (like g1 and droid)
int x = (int)event.getRawX();
final int edgeBorder = mEdgeBorder;
- if (x >= edgeBorder && x < mDisplay.getWidth() - edgeBorder) {
+ if (x >= edgeBorder && x < mDisplaySize.x - edgeBorder) {
prepareTracking(y, !mExpanded);// opening if we're not already fully visible
mVelocityTracker.addMovement(event);
}
@@ -1626,10 +1624,9 @@
+ ", mAnimAccel=" + mAnimAccel);
pw.println(" mCurAnimationTime=" + mCurAnimationTime
+ " mAnimLastTime=" + mAnimLastTime);
- pw.println(" mDisplayHeight=" + mDisplayHeight
- + " mAnimatingReveal=" + mAnimatingReveal
+ pw.println(" mAnimatingReveal=" + mAnimatingReveal
+ " mViewDelta=" + mViewDelta);
- pw.println(" mDisplayHeight=" + mDisplayHeight);
+ pw.println(" mDisplaySize=" + mDisplaySize);
pw.println(" mExpandedParams: " + mExpandedParams);
pw.println(" mExpandedView: " + viewInfo(mExpandedView));
pw.println(" mExpandedDialog: " + mExpandedDialog);
@@ -1721,17 +1718,13 @@
void onTrackingViewAttached() {
WindowManager.LayoutParams lp;
int pixelFormat;
- Drawable bg;
/// ---------- Expanded View --------------
pixelFormat = PixelFormat.TRANSLUCENT;
- final int disph = mDisplay.getHeight();
lp = mExpandedDialog.getWindow().getAttributes();
- lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
- lp.height = getExpandedHeight();
lp.x = 0;
- mTrackingPosition = lp.y = -disph; // sufficiently large negative
+ mTrackingPosition = lp.y = mDisplaySize.y; // sufficiently large negative
lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
lp.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -1741,9 +1734,9 @@
lp.format = pixelFormat;
lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
lp.setTitle("StatusBarExpanded");
- mExpandedDialog.getWindow().setAttributes(lp);
- mExpandedDialog.getWindow().setFormat(pixelFormat);
mExpandedParams = lp;
+ updateExpandedSize();
+ mExpandedDialog.getWindow().setFormat(pixelFormat);
mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
mExpandedDialog.setContentView(mExpandedView,
@@ -1751,7 +1744,6 @@
ViewGroup.LayoutParams.MATCH_PARENT));
mExpandedDialog.getWindow().setBackgroundDrawable(null);
mExpandedDialog.show();
- FrameLayout hack = (FrameLayout)mExpandedView.getParent();
}
void setDateViewVisibility(boolean visible, int anim) {
@@ -1768,6 +1760,20 @@
}
}
+ void updateExpandedInvisiblePosition() {
+ if (mTrackingView != null) {
+ mTrackingPosition = -mDisplaySize.y;
+ if (mTrackingParams != null) {
+ mTrackingParams.y = mTrackingPosition;
+ WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
+ }
+ }
+ if (mExpandedParams != null) {
+ mExpandedParams.y = -mDisplaySize.y;
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ }
+ }
+
void updateExpandedViewPos(int expandedPosition) {
if (SPEW) {
Slog.d(TAG, "updateExpandedViewPos before expandedPosition=" + expandedPosition
@@ -1776,22 +1782,12 @@
}
int h = mStatusBarView.getHeight();
- int disph = mDisplay.getHeight();
+ int disph = mDisplaySize.y;
// If the expanded view is not visible, make sure they're still off screen.
// Maybe the view was resized.
if (!mExpandedVisible) {
- if (mTrackingView != null) {
- mTrackingPosition = -disph;
- if (mTrackingParams != null) {
- mTrackingParams.y = mTrackingPosition;
- WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
- }
- }
- if (mExpandedParams != null) {
- mExpandedParams.y = -disph;
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
- }
+ updateExpandedInvisiblePosition();
return;
}
@@ -1816,14 +1812,21 @@
WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
if (mExpandedParams != null) {
- mCloseView.getLocationInWindow(mPositionTmp);
- final int closePos = mPositionTmp[1];
+ if (mCloseView.getWindowVisibility() == View.VISIBLE) {
+ mCloseView.getLocationInWindow(mPositionTmp);
+ final int closePos = mPositionTmp[1];
- mExpandedContents.getLocationInWindow(mPositionTmp);
- final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+ mExpandedContents.getLocationInWindow(mPositionTmp);
+ final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
- mExpandedParams.y = pos + mTrackingView.getHeight()
- - (mTrackingParams.height-closePos) - contentsBottom;
+ mExpandedParams.y = pos + mTrackingView.getHeight()
+ - (mTrackingParams.height-closePos) - contentsBottom;
+ } else {
+ // If the tracking view is not yet visible, then we can't have
+ // a good value of the close view location. We need to wait for
+ // it to be visible to do a layout.
+ mExpandedParams.y = -mDisplaySize.y;
+ }
int max = h;
if (mExpandedParams.y > max) {
mExpandedParams.y = max;
@@ -1859,14 +1862,24 @@
}
}
- int getExpandedHeight() {
- return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+ int getExpandedHeight(int disph) {
+ return disph - mStatusBarView.getHeight() - mCloseView.getHeight();
}
- void updateExpandedHeight() {
- if (mExpandedView != null) {
- mExpandedParams.height = getExpandedHeight();
- mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ void updateDisplaySize() {
+ mDisplay.getSize(mDisplaySize);
+ updateExpandedSize();
+ }
+
+ void updateExpandedSize() {
+ if (mExpandedDialog != null) {
+ mExpandedParams.width = mDisplaySize.x;
+ mExpandedParams.height = getExpandedHeight(mDisplaySize.y);
+ if (!mExpandedVisible) {
+ updateExpandedInvisiblePosition();
+ } else {
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c2390e8..db6907c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -77,6 +77,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mService.updateDisplaySize();
boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
if (mNightMode != nightMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
index fd32a3d..fc0f332 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrackingView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
+import android.os.Handler;
import android.util.AttributeSet;
import android.view.Display;
import android.view.KeyEvent;
@@ -29,6 +30,7 @@
PhoneStatusBar mService;
boolean mTracking;
int mStartX, mStartY;
+ Handler mHandler = new Handler();
public TrackingView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -39,7 +41,6 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mService.updateExpandedHeight();
}
@Override
@@ -60,4 +61,16 @@
super.onAttachedToWindow();
mService.onTrackingViewAttached();
}
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (visibility == VISIBLE) {
+ mHandler.post(new Runnable() {
+ @Override public void run() {
+ mService.updateExpandedViewPos(PhoneStatusBar.EXPANDED_LEAVE_ALONE);
+ }
+ });
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/IconUtilities.java b/policy/src/com/android/internal/policy/impl/IconUtilities.java
index 99055cf..4564f90 100644
--- a/policy/src/com/android/internal/policy/impl/IconUtilities.java
+++ b/policy/src/com/android/internal/policy/impl/IconUtilities.java
@@ -186,6 +186,7 @@
mask.recycle();
dest.drawBitmap(src, 0, 0, mPaint);
+ dest.setBitmap(null);
return result;
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 174f733..9c19da2 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -35,13 +35,13 @@
import com.android.internal.view.menu.MenuDialogHelper;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.MenuView;
-import com.android.internal.view.menu.SubMenuBuilder;
import com.android.internal.widget.ActionBarContainer;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;
import android.app.KeyguardManager;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -175,6 +175,8 @@
private AudioManager mAudioManager;
private KeyguardManager mKeyguardManager;
+ private int mUiOptions = 0;
+
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
@@ -213,6 +215,11 @@
}
@Override
+ public void setUiOptions(int uiOptions) {
+ mUiOptions = uiOptions;
+ }
+
+ @Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
@@ -2634,8 +2641,14 @@
mActionBar.initIndeterminateProgress();
}
- final boolean splitActionBar = getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowSplitActionBar, false);
+ boolean splitActionBar = false;
+ if ((mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0) {
+ splitActionBar = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.split_action_bar_is_narrow);
+ } else {
+ splitActionBar = getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowSplitActionBar, false);
+ }
if (splitActionBar) {
final ActionBarContainer splitView = (ActionBarContainer) findViewById(
com.android.internal.R.id.split_action_bar);
@@ -2648,7 +2661,7 @@
com.android.internal.R.id.action_context_bar);
cab.setSplitView(splitView);
} else {
- Log.e(TAG, "Window style requested split action bar with " +
+ Log.e(TAG, "Requested split action bar with " +
"incompatible window decor! Ignoring request.");
}
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 541a8cf..1bbe934 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -344,7 +344,7 @@
mPolicyManager.registerListener(mPolicyListener);
} catch (RemoteException e) {
// ouch, no rules updates means some processes may never get network
- Slog.e(TAG, "unable to register INetworkPolicyListener", e);
+ loge("unable to register INetworkPolicyListener" + e.toString());
}
final PowerManager powerManager = (PowerManager) context.getSystemService(
@@ -798,9 +798,11 @@
}
public void expire() {
- log("ConnectivityService FeatureUser expire(" +
- mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
- (System.currentTimeMillis() - mCreateTime) + " mSec ago");
+ if (VDBG) {
+ log("ConnectivityService FeatureUser expire(" +
+ mNetworkType + ", " + mFeature + ", " + mBinder +"), created " +
+ (System.currentTimeMillis() - mCreateTime) + " mSec ago");
+ }
stopUsingNetworkFeature(this, false);
}
@@ -843,7 +845,7 @@
if(networkType == ConnectivityManager.TYPE_MOBILE) {
usedNetworkType = convertFeatureToNetworkType(feature);
if (usedNetworkType < 0) {
- Slog.e(TAG, "Can't match any netTracker!");
+ loge("Can't match any netTracker!");
usedNetworkType = networkType;
}
}
@@ -953,7 +955,7 @@
return stopUsingNetworkFeature(u, true);
} else {
// none found!
- if (DBG) log("ignoring stopUsingNetworkFeature - not a live request");
+ if (VDBG) log("ignoring stopUsingNetworkFeature - not a live request");
return 1;
}
}
@@ -1081,7 +1083,7 @@
if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
tracker.isTeardownRequested()) {
- if (DBG) {
+ if (VDBG) {
log("requestRouteToHostAddress on down network " +
"(" + networkType + ") - dropped");
}
@@ -1152,13 +1154,13 @@
}
}
if (doAdd) {
- if (DBG) log("Adding " + r + " for interface " + ifaceName);
+ if (VDBG) log("Adding " + r + " for interface " + ifaceName);
mAddedRoutes.add(r);
try {
mNetd.addRoute(ifaceName, r);
} catch (Exception e) {
// never crash - catch them all
- loge("Exception trying to add a route: " + e);
+ if (VDBG) loge("Exception trying to add a route: " + e);
return false;
}
} else {
@@ -1166,16 +1168,16 @@
// we can remove it from the table
mAddedRoutes.remove(r);
if (mAddedRoutes.contains(r) == false) {
- if (DBG) log("Removing " + r + " for interface " + ifaceName);
+ if (VDBG) log("Removing " + r + " for interface " + ifaceName);
try {
mNetd.removeRoute(ifaceName, r);
} catch (Exception e) {
// never crash - catch them all
- loge("Exception trying to remove a route: " + e);
+ if (VDBG) loge("Exception trying to remove a route: " + e);
return false;
}
} else {
- if (DBG) log("not removing " + r + " as it's still in use");
+ if (VDBG) log("not removing " + r + " as it's still in use");
}
}
return true;
@@ -1220,7 +1222,7 @@
enforceAccessPermission();
boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.MOBILE_DATA, 1) == 1;
- if (DBG) log("getMobileDataEnabled returning " + retVal);
+ if (VDBG) log("getMobileDataEnabled returning " + retVal);
return retVal;
}
@@ -1247,7 +1249,7 @@
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (LOGD_RULES) {
- Slog.d(TAG, "onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
+ log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")");
}
synchronized (mRulesLock) {
@@ -1268,8 +1270,7 @@
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
if (LOGD_RULES) {
- Slog.d(TAG,
- "onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
+ log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")");
}
synchronized (mRulesLock) {
@@ -1294,8 +1295,8 @@
private void handleSetMobileData(boolean enabled) {
if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
- if (DBG) {
- Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
+ if (VDBG) {
+ log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
}
mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
}
@@ -1587,7 +1588,7 @@
mNetConfigs[type].priority) ||
mNetworkPreference == mActiveDefaultNetwork) {
// don't accept this one
- if (DBG) {
+ if (VDBG) {
log("Not broadcasting CONNECT_ACTION " +
"to torn down network " + info.getTypeName());
}
@@ -1688,9 +1689,11 @@
}
} else {
resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
- log("handleConnectivityChange: interface not not equivalent reset both" +
- " linkProperty[" + netType + "]:" +
- " resetMask=" + resetMask);
+ if (DBG) {
+ log("handleConnectivityChange: interface not not equivalent reset both" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
+ }
}
}
if (mNetConfigs[netType].isDefault()) {
@@ -1798,7 +1801,7 @@
String bufferSizes = SystemProperties.get(key);
if (bufferSizes.length() == 0) {
- loge(key + " not found in system properties. Using defaults");
+ if (VDBG) log(key + " not found in system properties. Using defaults");
// Setting to default values so we won't be stuck to previous values
key = "net.tcp.buffersize.default";
@@ -1807,7 +1810,7 @@
// Set values in kernel
if (bufferSizes.length() != 0) {
- if (DBG) {
+ if (VDBG) {
log("Setting TCP values: [" + bufferSizes
+ "] which comes from [" + key + "]");
}
@@ -1849,7 +1852,7 @@
*/
private void reassessPidDns(int myPid, boolean doBump)
{
- if (DBG) log("reassessPidDns for pid " + myPid);
+ if (VDBG) log("reassessPidDns for pid " + myPid);
for(int i : mPriorityList) {
if (mNetConfigs[i].isDefault()) {
continue;
@@ -1935,7 +1938,7 @@
String value = mDefaultDns.getHostAddress();
if (!value.equals(SystemProperties.get("net.dns1"))) {
if (DBG) {
- log("no dns provided for " + network + " - using " + value);
+ loge("no dns provided for " + network + " - using " + value);
}
changed = true;
SystemProperties.set("net.dns1", value);
@@ -1948,7 +1951,7 @@
if (!changed && value.equals(SystemProperties.get(key))) {
continue;
}
- if (DBG) {
+ if (VDBG) {
log("adding dns " + value + " for " + network);
}
changed = true;
@@ -1957,7 +1960,7 @@
}
for (int i = last + 1; i <= mNumDnsEntries; ++i) {
String key = "net.dns" + i;
- if (DBG) log("erasing " + key);
+ if (VDBG) log("erasing " + key);
changed = true;
SystemProperties.set(key, "");
}
@@ -1968,7 +1971,7 @@
mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses));
mNetd.setDefaultInterfaceForDns(iface);
} catch (Exception e) {
- Slog.e(TAG, "exception setting default dns interface: " + e);
+ loge("exception setting default dns interface: " + e);
}
}
if (!domains.equals(SystemProperties.get("net.dns.search"))) {
@@ -1998,7 +2001,7 @@
mNetd.setDnsServersForInterface(p.getInterfaceName(),
NetworkUtils.makeStrings(dnses));
} catch (Exception e) {
- Slog.e(TAG, "exception setting dns servers: " + e);
+ loge("exception setting dns servers: " + e);
}
// set per-pid dns for attached secondary nets
List pids = mNetRequestersPids[netType];
@@ -2335,7 +2338,7 @@
// 100 percent is full good, 0 is full bad.
public void reportInetCondition(int networkType, int percentage) {
- if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
+ if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR,
"ConnectivityService");
@@ -2372,7 +2375,7 @@
mDefaultInetCondition = condition;
int delay;
if (mInetConditionChangeInFlight == false) {
- if (DBG) log("starting a change hold");
+ if (VDBG) log("starting a change hold");
// setup a new hold to debounce this
if (mDefaultInetCondition > 50) {
delay = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -2387,12 +2390,12 @@
} else {
// we've set the new condition, when this hold ends that will get
// picked up
- if (DBG) log("currently in hold - not setting new end evt");
+ if (VDBG) log("currently in hold - not setting new end evt");
}
}
private void handleInetConditionHoldEnd(int netType, int sequence) {
- if (DBG) {
+ if (VDBG) {
log("Inet hold end, net=" + netType +
", condition =" + mDefaultInetCondition +
", published condition =" + mDefaultInetConditionPublished);
@@ -2490,7 +2493,7 @@
mDefaultProxy = null;
}
}
- if (DBG) log("changing default proxy to " + proxy);
+ if (VDBG) log("changing default proxy to " + proxy);
if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
if (mGlobalProxy != null) return;
sendProxyBroadcast(proxy);
@@ -2517,7 +2520,7 @@
private void sendProxyBroadcast(ProxyProperties proxy) {
if (proxy == null) proxy = new ProxyProperties("", 0, "");
- log("sending Proxy Broadcast for " + proxy);
+ if (DBG) log("sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 9cb772e..ecbad099 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -183,7 +183,9 @@
android.R.dimen.notification_large_icon_height);
icon.setBounds(0, 0, width, height);
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- icon.draw(new Canvas(bitmap));
+ Canvas c = new Canvas(bitmap);
+ icon.draw(c);
+ c.setBitmap(null);
}
// Configure the interface. Abort if any of these steps fails.
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 88e0fa8..3d977d0 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -3326,7 +3326,7 @@
if (pkg.applicationInfo.nativeLibraryDir != null) {
try {
final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- final String dataPathString = dataPath.getCanonicalFile().getPath();
+ final String dataPathString = dataPath.getCanonicalPath();
if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
/*
@@ -3340,7 +3340,7 @@
Log.i(TAG, "removed obsolete native libraries for system package "
+ path);
}
- } else if (nativeLibraryDir.getCanonicalFile().getParent()
+ } else if (nativeLibraryDir.getParentFile().getCanonicalPath()
.equals(dataPathString)) {
/*
* Make sure the native library dir isn't a symlink to
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f8059f5..e0b5e17 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -4919,6 +4919,7 @@
matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
Canvas canvas = new Canvas(bm);
canvas.drawBitmap(rawss, matrix, null);
+ canvas.setBitmap(null);
rawss.recycle();
return bm;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 7bf3e0a..f4be168 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -40,6 +40,7 @@
#include "GLExtensions.h"
#include "HWComposer.h"
+#include "SurfaceFlinger.h"
using namespace android;
@@ -75,7 +76,7 @@
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy),
- mFlags(0), mHwc(0)
+ mFlinger(flinger), mFlags(0), mHwc(0)
{
init(dpy);
}
@@ -310,7 +311,7 @@
// initialize the H/W composer
- mHwc = new HWComposer();
+ mHwc = new HWComposer(mFlinger);
if (mHwc->initCheck() == NO_ERROR) {
mHwc->setFrameBuffer(mDisplay, mSurface);
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index cdf89fd..40a6f1e 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -95,6 +95,7 @@
void init(uint32_t displayIndex) __attribute__((noinline));
void fini() __attribute__((noinline));
+ sp<SurfaceFlinger> mFlinger;
EGLDisplay mDisplay;
EGLSurface mSurface;
EGLContext mContext;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index 30eb258..3ebc7b6 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -37,7 +37,7 @@
~DisplayHardwareBase();
- // console managment
+ // console management
void releaseScreen() const;
void acquireScreen() const;
bool isScreenAcquired() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4a3b20d..7d1bdf0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,12 +30,14 @@
#include <EGL/egl.h>
#include "HWComposer.h"
+#include "SurfaceFlinger.h"
namespace android {
// ---------------------------------------------------------------------------
-HWComposer::HWComposer()
- : mModule(0), mHwc(0), mList(0), mCapacity(0),
+HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger),
+ mModule(0), mHwc(0), mList(0), mCapacity(0),
mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
{
int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
@@ -44,6 +46,13 @@
err = hwc_open(mModule, &mHwc);
LOGE_IF(err, "%s device failed to initialize (%s)",
HWC_HARDWARE_COMPOSER, strerror(-err));
+ if (err == 0) {
+ if (mHwc->registerProcs) {
+ mCBContext.hwc = this;
+ mCBContext.procs.invalidate = &hook_invalidate;
+ mHwc->registerProcs(mHwc, &mCBContext.procs);
+ }
+ }
}
}
@@ -58,6 +67,14 @@
return mHwc ? NO_ERROR : NO_INIT;
}
+void HWComposer::hook_invalidate(struct hwc_procs* procs) {
+ reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
+}
+
+void HWComposer::invalidate() {
+ mFlinger->signalEvent();
+}
+
void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
mDpy = (hwc_display_t)dpy;
mSur = (hwc_surface_t)sur;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5a9e9eb..983898a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -24,16 +24,19 @@
#include <hardware/hwcomposer.h>
+#include <utils/StrongPointer.h>
+
namespace android {
// ---------------------------------------------------------------------------
class String8;
+class SurfaceFlinger;
class HWComposer
{
public:
- HWComposer();
+ HWComposer(const sp<SurfaceFlinger>& flinger);
~HWComposer();
status_t initCheck() const;
@@ -60,12 +63,21 @@
void dump(String8& out, char* scratch, size_t SIZE) const;
private:
+ struct cb_context {
+ hwc_procs_t procs;
+ HWComposer* hwc;
+ };
+ static void hook_invalidate(struct hwc_procs* procs);
+ void invalidate();
+
+ sp<SurfaceFlinger> mFlinger;
hw_module_t const* mModule;
hwc_composer_device_t* mHwc;
hwc_layer_list_t* mList;
size_t mCapacity;
hwc_display_t mDpy;
hwc_surface_t mSur;
+ cb_context mCBContext;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 886bb2a..383c045 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -172,17 +172,14 @@
void Layer::setGeometry(hwc_layer_t* hwcl)
{
- hwcl->compositionType = HWC_FRAMEBUFFER;
- hwcl->hints = 0;
- hwcl->flags = 0;
- hwcl->transform = 0;
- hwcl->blending = HWC_BLENDING_NONE;
+ LayerBaseClient::setGeometry(hwcl);
+
+ hwcl->flags &= ~HWC_SKIP_LAYER;
// we can't do alpha-fade with the hwc HAL
const State& s(drawingState());
if (s.alpha < 0xFF) {
hwcl->flags = HWC_SKIP_LAYER;
- return;
}
/*
@@ -205,26 +202,9 @@
// we can only handle simple transformation
if (finalTransform & Transform::ROT_INVALID) {
hwcl->flags = HWC_SKIP_LAYER;
- return;
+ } else {
+ hwcl->transform = finalTransform;
}
-
- hwcl->transform = finalTransform;
-
- if (!isOpaque()) {
- hwcl->blending = mPremultipliedAlpha ?
- HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
- }
-
- // scaling is already applied in mTransformedBounds
- hwcl->displayFrame.left = mTransformedBounds.left;
- hwcl->displayFrame.top = mTransformedBounds.top;
- hwcl->displayFrame.right = mTransformedBounds.right;
- hwcl->displayFrame.bottom = mTransformedBounds.bottom;
-
- hwcl->visibleRegionScreen.rects =
- reinterpret_cast<hwc_rect_t const *>(
- visibleRegionScreen.getArray(
- &hwcl->visibleRegionScreen.numRects));
}
void Layer::setPerFrameData(hwc_layer_t* hwcl) {
@@ -235,9 +215,9 @@
// HWC handle it.
hwcl->flags |= HWC_SKIP_LAYER;
hwcl->handle = NULL;
- return;
+ } else {
+ hwcl->handle = buffer->handle;
}
- hwcl->handle = buffer->handle;
if (isCropped()) {
hwcl->sourceCrop.left = mCurrentCrop.left;
@@ -247,8 +227,13 @@
} else {
hwcl->sourceCrop.left = 0;
hwcl->sourceCrop.top = 0;
- hwcl->sourceCrop.right = buffer->width;
- hwcl->sourceCrop.bottom = buffer->height;
+ if (buffer != NULL) {
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+ } else {
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
+ }
}
}
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index c86c659..e04c533 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -302,13 +302,47 @@
}
}
-void LayerBase::setGeometry(hwc_layer_t* hwcl) {
- hwcl->flags |= HWC_SKIP_LAYER;
+void LayerBase::setGeometry(hwc_layer_t* hwcl)
+{
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->hints = 0;
+ hwcl->flags = HWC_SKIP_LAYER;
+ hwcl->transform = 0;
+ hwcl->blending = HWC_BLENDING_NONE;
+
+ // this gives us only the "orientation" component of the transform
+ const State& s(drawingState());
+ const uint32_t finalTransform = s.transform.getOrientation();
+ // we can only handle simple transformation
+ if (finalTransform & Transform::ROT_INVALID) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ } else {
+ hwcl->transform = finalTransform;
+ }
+
+ if (!isOpaque()) {
+ hwcl->blending = mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+ }
+
+ // scaling is already applied in mTransformedBounds
+ hwcl->displayFrame.left = mTransformedBounds.left;
+ hwcl->displayFrame.top = mTransformedBounds.top;
+ hwcl->displayFrame.right = mTransformedBounds.right;
+ hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+ hwcl->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ visibleRegionScreen.getArray(
+ &hwcl->visibleRegionScreen.numRects));
}
void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
hwcl->compositionType = HWC_FRAMEBUFFER;
hwcl->handle = NULL;
+ hwcl->sourceCrop.left = 0;
+ hwcl->sourceCrop.top = 0;
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
}
void LayerBase::setFiltering(bool filtering)
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
index 7bf25cf..4037a69 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java
@@ -77,13 +77,23 @@
super.onDraw(canvas);
canvas.drawRGB(255, 255, 255);
+ mMediumPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ mMediumPaint.setStrokeWidth(2.0f);
canvas.drawText("Hello OpenGL renderer!", 100, 20, mMediumPaint);
+
+ mMediumPaint.setStyle(Paint.Style.FILL);
mMediumPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("Hello OpenGL renderer!", 100, 40, mMediumPaint);
+
+ mMediumPaint.setStyle(Paint.Style.STROKE);
+ mMediumPaint.setStrokeWidth(2.0f);
mMediumPaint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText("Hello OpenGL renderer!", 100, 60, mMediumPaint);
+
+ mMediumPaint.setStyle(Paint.Style.FILL);
mMediumPaint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("Hello OpenGL renderer!", 100, 100, mMediumPaint);
+
mMediumPaint.setShadowLayer(2.5f, 0.0f, 0.0f, 0xff000000);
canvas.drawText("Hello OpenGL renderer!", 100, 150, mMediumPaint);
mMediumPaint.clearShadowLayer();
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
index 66972ac..c4fd189 100644
--- a/tests/TileBenchmark/res/values/strings.xml
+++ b/tests/TileBenchmark/res/values/strings.xml
@@ -71,8 +71,16 @@
<string name="frames_per_second">Frames/sec</string>
<!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
<string name="viewport_coverage">Coverage</string>
+ <!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
+ <string name="render_millis">RenderMillis</string>
<!-- Format string for stat value overlay [CHAR LIMIT=15] -->
<string name="format_stat">%4.4f</string>
+
+ <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
+ <string name="format_view_pos">View:(%1$d,%2$d)-(%3$d,%4$d)</string>
+ <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
+ <string name="format_inval_pos">Inval:(%1$d,%2$d)-(%3$d,%4$d)</string>
+
<!-- Format string for displaying aggregate stats+values (nr of valid tiles,
etc.) [CHAR LIMIT=20] -->
<string name="format_stat_name">%1$-20s %2$3d</string>
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
index 36694a7..1eb1c00 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackActivity.java
@@ -83,14 +83,14 @@
}
};
- private class LoadFileTask extends AsyncTask<String, Void, TileData[][]> {
+ private class LoadFileTask extends AsyncTask<String, Void, RunData> {
@Override
- protected TileData[][] doInBackground(String... params) {
- TileData[][] data = null;
+ protected RunData doInBackground(String... params) {
+ RunData data = null;
try {
FileInputStream fis = openFileInput(params[0]);
ObjectInputStream in = new ObjectInputStream(fis);
- data = (TileData[][]) in.readObject();
+ data = (RunData) in.readObject();
in.close();
} catch (IOException ex) {
ex.printStackTrace();
@@ -101,7 +101,7 @@
}
@Override
- protected void onPostExecute(TileData data[][]) {
+ protected void onPostExecute(RunData data) {
if (data == null) {
Toast.makeText(getApplicationContext(),
getResources().getString(R.string.error_no_data),
@@ -110,7 +110,7 @@
}
mPlaybackView.setData(data);
- mFrameMax = data.length - 1;
+ mFrameMax = data.frames.length - 1;
mSeekBar.setMax(mFrameMax);
setFrame(null, 0);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
index 35b1563..aad138c 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
@@ -22,10 +22,12 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
-import android.os.Bundle;
+
+import com.test.tilebenchmark.RunData.TileData;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
public class PlaybackGraphs {
private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3;
@@ -44,7 +46,7 @@
return 0.0f;
}
- private interface MetricGen {
+ protected interface MetricGen {
public double getValue(TileData[] frame);
public double getMax();
@@ -52,7 +54,7 @@
public int getLabelId();
};
- private static MetricGen[] Metrics = new MetricGen[] {
+ protected static MetricGen[] Metrics = new MetricGen[] {
new MetricGen() {
// framerate graph
@Override
@@ -99,7 +101,7 @@
}
};
- private interface StatGen {
+ protected interface StatGen {
public double getValue(double sortedValues[]);
public int getLabelId();
@@ -116,7 +118,7 @@
+ sortedValues[intIndex + 1] * (alpha);
}
- private static StatGen[] Stats = new StatGen[] {
+ protected static StatGen[] Stats = new StatGen[] {
new StatGen() {
@Override
public double getValue(double[] sortedValues) {
@@ -157,21 +159,22 @@
}
private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
- private double[][] mStats = new double[Metrics.length][Stats.length];
+ protected double[][] mStats = new double[Metrics.length][Stats.length];
+ protected HashMap<String, Double> mSingleStats;
- public void setData(TileData[][] tileProfilingData) {
+ public void setData(RunData data) {
mShapes.clear();
- double metricValues[] = new double[tileProfilingData.length];
+ double metricValues[] = new double[data.frames.length];
- if (tileProfilingData.length == 0) {
+ if (data.frames.length == 0) {
return;
}
for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
// create graph out of rectangles, one per frame
int lastBar = 0;
- for (int frameIndex = 0; frameIndex < tileProfilingData.length; frameIndex++) {
- TileData frame[] = tileProfilingData[frameIndex];
+ for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
+ TileData frame[] = data.frames[frameIndex];
int newBar = (frame[0].top + frame[0].bottom) / 2;
MetricGen s = Metrics[metricIndex];
@@ -194,9 +197,11 @@
// store aggregate statistics per metric (median, and similar)
Arrays.sort(metricValues);
for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
- mStats[metricIndex][statIndex] = Stats[statIndex]
- .getValue(metricValues);
+ mStats[metricIndex][statIndex] =
+ Stats[statIndex].getValue(metricValues);
}
+
+ mSingleStats = data.singleStats;
}
}
@@ -215,7 +220,7 @@
}
public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes,
- String[] strings, Resources resources) {
+ ArrayList<String> strings, Resources resources) {
canvas.scale(CANVAS_SCALE, CANVAS_SCALE);
canvas.translate(BAR_WIDTH * Metrics.length, 0);
@@ -238,26 +243,9 @@
canvas.drawText(label, xPos, yPos, whiteLabels);
}
}
- for (int stringIndex = 0; stringIndex < strings.length; stringIndex++) {
+ for (int stringIndex = 0; stringIndex < strings.size(); stringIndex++) {
int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
- canvas.drawText(strings[stringIndex], 0, yPos, whiteLabels);
+ canvas.drawText(strings.get(stringIndex), 0, yPos, whiteLabels);
}
}
-
- public Bundle getStatBundle(Resources resources) {
- Bundle b = new Bundle();
-
- for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
- for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
- String metricLabel = resources.getString(
- Metrics[metricIndex].getLabelId());
- String statLabel = resources.getString(
- Stats[statIndex].getLabelId());
- double value = mStats[metricIndex][statIndex];
- b.putDouble(metricLabel + " " + statLabel, value);
- }
- }
-
- return b;
- }
}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
index edc8643..5459c1f 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackView.java
@@ -30,10 +30,12 @@
import android.view.MotionEvent;
import android.view.View;
+import com.test.tilebenchmark.RunData.TileData;
+
import java.util.ArrayList;
public class PlaybackView extends View {
- public static final int TILE_SCALE = 300;
+ public static final int TILE_SCALE = 256;
private static final int INVAL_FLAG = -2;
private static final int INVAL_CYCLE = 250;
@@ -41,9 +43,9 @@
private PlaybackGraphs mGraphs;
private ArrayList<ShapeDrawable> mTempShapes = new ArrayList<ShapeDrawable>();
- private TileData mProfData[][] = null;
+ private RunData mProfData = null;
private GestureDetector mGestureDetector = null;
- private String mRenderStrings[] = new String[4];
+ private ArrayList<String> mRenderStrings = new ArrayList<String>();
private class TileDrawable extends ShapeDrawable {
TileData tile;
@@ -135,17 +137,30 @@
invalidate(); // may have animations, force redraw
}
+ private String statString(int labelId, int value) {
+ return getResources().getString(R.string.format_stat_name,
+ getResources().getString(labelId), value);
+ }
+ private String tileString(int formatStringId, TileData t) {
+ return getResources().getString(formatStringId,
+ t.left, t.top, t.right, t.bottom);
+ }
+
public int setFrame(int frame) {
- if (mProfData == null || mProfData.length == 0) {
+ if (mProfData == null || mProfData.frames.length == 0) {
return 0;
}
int readyTiles = 0, unreadyTiles = 0, unplacedTiles = 0, numInvals = 0;
mTempShapes.clear();
+ mRenderStrings.clear();
// create tile shapes (as they're drawn on bottom)
- for (TileData t : mProfData[frame]) {
- if (t.level != INVAL_FLAG && t != mProfData[frame][0]) {
+ for (TileData t : mProfData.frames[frame]) {
+ if (t == mProfData.frames[frame][0]){
+ // viewport 'tile', add coords to render strings
+ mRenderStrings.add(tileString(R.string.format_view_pos, t));
+ } else if (t.level != INVAL_FLAG) {
int colorId;
if (t.isReady) {
readyTiles++;
@@ -159,14 +174,16 @@
}
mTempShapes.add(new TileDrawable(t, colorId));
} else {
+ // inval 'tile', count and add coords to render strings
numInvals++;
+ mRenderStrings.add(tileString(R.string.format_inval_pos, t));
}
}
// create invalidate shapes (drawn above tiles)
int invalId = 0;
- for (TileData t : mProfData[frame]) {
- if (t.level == INVAL_FLAG && t != mProfData[frame][0]) {
+ for (TileData t : mProfData.frames[frame]) {
+ if (t.level == INVAL_FLAG && t != mProfData.frames[frame][0]) {
TileDrawable invalShape = new TileDrawable(t,
R.color.inval_region_start);
ValueAnimator tileAnimator = ObjectAnimator.ofInt(invalShape,
@@ -186,26 +203,20 @@
}
}
- mRenderStrings[0] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.ready_tiles), readyTiles);
- mRenderStrings[1] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.unready_tiles), unreadyTiles);
- mRenderStrings[2] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.unplaced_tiles),
- unplacedTiles);
- mRenderStrings[3] = getResources().getString(R.string.format_stat_name,
- getResources().getString(R.string.number_invalidates),
- numInvals);
+ mRenderStrings.add(statString(R.string.ready_tiles, readyTiles));
+ mRenderStrings.add(statString(R.string.unready_tiles, unreadyTiles));
+ mRenderStrings.add(statString(R.string.unplaced_tiles, unplacedTiles));
+ mRenderStrings.add(statString(R.string.number_invalidates, numInvals));
// draw view rect (using first TileData object, on top)
- TileDrawable viewShape = new TileDrawable(mProfData[frame][0],
+ TileDrawable viewShape = new TileDrawable(mProfData.frames[frame][0],
R.color.view);
mTempShapes.add(viewShape);
this.invalidate();
return frame;
}
- public void setData(TileData[][] tileProfilingData) {
+ public void setData(RunData tileProfilingData) {
mProfData = tileProfilingData;
mGraphs.setData(mProfData);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
index 1521807..a63a2f0 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
@@ -51,11 +51,11 @@
public class ProfileActivity extends Activity {
public interface ProfileCallback {
- public void profileCallback(TileData data[][]);
+ public void profileCallback(RunData data);
}
public static final String TEMP_FILENAME = "profile.tiles";
- private static final int LOAD_TEST_DELAY = 2000; // nr of millis after load,
+ private static final int LOAD_TEST_DELAY = 1000; // nr of millis after load,
// before test
Button mInspectButton;
@@ -135,6 +135,7 @@
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.requestFocus();
+
new CountDownTimer(LOAD_TEST_DELAY, LOAD_TEST_DELAY) {
@Override
public void onTick(long millisUntilFinished) {
@@ -155,10 +156,10 @@
}
private class StoreFileTask extends
- AsyncTask<Pair<String, TileData[][]>, Void, Void> {
+ AsyncTask<Pair<String, RunData>, Void, Void> {
@Override
- protected Void doInBackground(Pair<String, TileData[][]>... params) {
+ protected Void doInBackground(Pair<String, RunData>... params) {
try {
FileOutputStream fos = openFileOutput(params[0].first,
Context.MODE_PRIVATE);
@@ -205,10 +206,8 @@
/** auto - automatically scroll. */
private void startViewProfiling(boolean auto) {
- if (!auto) {
- // manual, toggle capture button to indicate capture state to user
- mCaptureButton.setChecked(true);
- }
+ // toggle capture button to indicate capture state to user
+ mCaptureButton.setChecked(true);
mWeb.startScrollTest(mCallback, auto);
setTestingState(TestingState.START_TESTING);
}
@@ -227,8 +226,8 @@
mCallback = new ProfileCallback() {
@SuppressWarnings("unchecked")
@Override
- public void profileCallback(TileData[][] data) {
- new StoreFileTask().execute(new Pair<String, TileData[][]>(
+ public void profileCallback(RunData data) {
+ new StoreFileTask().execute(new Pair<String, RunData>(
TEMP_FILENAME, data));
mCaptureButton.setChecked(false);
setTestingState(TestingState.STOP_TESTING);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index d3941be..3fc4665 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -18,15 +18,19 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
import android.webkit.WebView;
import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
+import com.test.tilebenchmark.RunData.TileData;
public class ProfiledWebView extends WebView {
private int mSpeed;
+ private boolean isTesting = false;
private boolean isScrolling = false;
private ProfileCallback mCallback;
+ private long mContentInvalMillis;
public ProfiledWebView(Context context) {
super(context);
@@ -47,7 +51,7 @@
@Override
protected void onDraw(android.graphics.Canvas canvas) {
- if (isScrolling) {
+ if (isTesting && isScrolling) {
if (canScrollVertically(1)) {
scrollBy(0, mSpeed);
} else {
@@ -60,31 +64,53 @@
/*
* Called once the page is loaded to start scrolling for evaluating tiles.
- * If autoScrolling isn't set, stop must be called manually.
+ * If autoScrolling isn't set, stop must be called manually. Before
+ * scrolling, invalidate all content and redraw it, measuring time taken.
*/
public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
isScrolling = autoScrolling;
mCallback = callback;
- tileProfilingStart();
+ isTesting = false;
+ mContentInvalMillis = System.currentTimeMillis();
+ registerPageSwapCallback();
+ contentInvalidateAll();
invalidate();
}
/*
+ * Called after the manual contentInvalidateAll, after the tiles have all
+ * been redrawn.
+ */
+ @Override
+ protected void pageSwapCallback() {
+ mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
+ super.pageSwapCallback();
+ Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
+ + "millis");
+ isTesting = true;
+ invalidate(); // ensure a redraw so that auto-scrolling can occur
+ tileProfilingStart();
+ }
+
+ /*
* Called once the page has stopped scrolling
*/
public void stopScrollTest() {
- super.tileProfilingStop();
+ tileProfilingStop();
+ isTesting = false;
if (mCallback == null) {
tileProfilingClear();
return;
}
- TileData data[][] = new TileData[super.tileProfilingNumFrames()][];
- for (int frame = 0; frame < data.length; frame++) {
- data[frame] = new TileData[
+ RunData data = new RunData(super.tileProfilingNumFrames());
+ data.singleStats.put(getResources().getString(R.string.render_millis),
+ (double)mContentInvalMillis);
+ for (int frame = 0; frame < data.frames.length; frame++) {
+ data.frames[frame] = new TileData[
tileProfilingNumTilesInFrame(frame)];
- for (int tile = 0; tile < data[frame].length; tile++) {
+ for (int tile = 0; tile < data.frames[frame].length; tile++) {
int left = tileProfilingGetInt(frame, tile, "left");
int top = tileProfilingGetInt(frame, tile, "top");
int right = tileProfilingGetInt(frame, tile, "right");
@@ -96,18 +122,18 @@
float scale = tileProfilingGetFloat(frame, tile, "scale");
- data[frame][tile] = new TileData(left, top, right, bottom,
+ data.frames[frame][tile] = data.new TileData(left, top, right, bottom,
isReady, level, scale);
}
}
- super.tileProfilingClear();
+ tileProfilingClear();
mCallback.profileCallback(data);
}
@Override
public void loadUrl(String url) {
- if (!url.startsWith("http://")) {
+ if (!url.startsWith("http://") && !url.startsWith("file://")) {
url = "http://" + url;
}
super.loadUrl(url);
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
new file mode 100644
index 0000000..2da61cc
--- /dev/null
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/RunData.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 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.test.tilebenchmark;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+public class RunData implements Serializable {
+ public TileData[][] frames;
+ public HashMap<String, Double> singleStats = new HashMap<String, Double>();
+
+ public RunData(int frames) {
+ this.frames = new TileData[frames][];
+ }
+
+ public class TileData implements Serializable {
+ public int left, top, right, bottom;
+ public boolean isReady;
+ public int level;
+ public float scale;
+
+ public TileData(int left, int top, int right, int bottom,
+ boolean isReady, int level, float scale) {
+ this.left = left;
+ this.right = right;
+ this.top = top;
+ this.bottom = bottom;
+ this.isReady = isReady;
+ this.level = level;
+ this.scale = scale;
+ }
+
+ public String toString() {
+ return "Tile (" + left + "," + top + ")->("
+ + right + "," + bottom + ")";
+ }
+ }
+
+}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java b/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
deleted file mode 100644
index 3e729a6..0000000
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/TileData.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2011 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.test.tilebenchmark;
-
-import java.io.Serializable;
-
-public class TileData implements Serializable {
- int left, top, right, bottom;
- public boolean isReady;
- public int level;
- public float scale;
-
- public TileData(int left, int top, int right, int bottom, boolean isReady,
- int level, float scale) {
- this.left = left;
- this.right = right;
- this.top = top;
- this.bottom = bottom;
- this.isReady = isReady;
- this.level = level;
- this.scale = scale;
- }
-
- public String toString() {
- return "Tile (" + left + "," + top + ")->("
- + right + "," + bottom + ")";
- }
-}
diff --git a/tests/TileBenchmark/tests/Android.mk b/tests/TileBenchmark/tests/Android.mk
new file mode 100644
index 0000000..8b235ec
--- /dev/null
+++ b/tests/TileBenchmark/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := TileBenchmarkTests
+
+LOCAL_INSTRUMENTATION_FOR := TileBenchmark
+
+include $(BUILD_PACKAGE)
diff --git a/tests/TileBenchmark/tests/AndroidManifest.xml b/tests/TileBenchmark/tests/AndroidManifest.xml
new file mode 100644
index 0000000..703b152
--- /dev/null
+++ b/tests/TileBenchmark/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.test.tilebenchmark.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.test.tilebenchmark"
+ android:label="Tests for WebView Tiles."/>
+</manifest>
diff --git a/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java
new file mode 100644
index 0000000..0f02239
--- /dev/null
+++ b/tests/TileBenchmark/tests/src/com/test/tilebenchmark/PerformanceTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2011 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.test.tilebenchmark;
+
+import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+public class PerformanceTest extends
+ ActivityInstrumentationTestCase2<ProfileActivity> {
+
+ private class StatAggregator extends PlaybackGraphs {
+ private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
+ private int mCount = 0;
+
+ public void aggregate() {
+ mCount++;
+ Resources resources = mView.getResources();
+ for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
+ for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
+ String metricLabel = resources.getString(
+ Metrics[metricIndex].getLabelId());
+ String statLabel = resources.getString(
+ Stats[statIndex].getLabelId());
+
+ String label = metricLabel + " " + statLabel;
+ double aggVal = mDataMap.containsKey(label) ? mDataMap
+ .get(label) : 0;
+
+ aggVal += mStats[metricIndex][statIndex];
+ mDataMap.put(label, aggVal);
+ }
+ }
+ for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
+ double aggVal = mDataMap.containsKey(e.getKey())
+ ? mDataMap.get(e.getKey()) : 0;
+ mDataMap.put(e.getKey(), aggVal + e.getValue());
+ }
+ }
+
+ public Bundle getBundle() {
+ Bundle b = new Bundle();
+ int count = 0 == mCount ? Integer.MAX_VALUE : mCount;
+ for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
+ b.putDouble(e.getKey(), e.getValue() / count);
+ }
+ return b;
+ }
+ }
+
+ ProfileActivity mActivity;
+ ProfiledWebView mView;
+ StatAggregator mStats = new StatAggregator();
+
+ private static final String LOGTAG = "PerformanceTest";
+ private static final String TEST_LOCATION = "webkit/page_cycler";
+ private static final String URL_PREFIX = "file://";
+ private static final String URL_POSTFIX = "/index.html?skip=true";
+ private static final int MAX_ITERATIONS = 4;
+ private static final String TEST_DIRS[] = {
+ "alexa_us"//, "android", "dom", "intl1", "intl2", "moz", "moz2"
+ };
+
+ public PerformanceTest() {
+ super(ProfileActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mView = (ProfiledWebView) mActivity.findViewById(R.id.web);
+ }
+
+ private boolean loadUrl(final String url) {
+ try {
+ Log.d(LOGTAG, "test starting for url " + url);
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mView.loadUrl(url);
+ }
+ });
+ synchronized (mStats) {
+ mStats.wait();
+ }
+ mStats.aggregate();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ private boolean runIteration() {
+ File sdFile = Environment.getExternalStorageDirectory();
+ for (String testDirName : TEST_DIRS) {
+ File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
+ Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
+ + "', exists=" + testDir.exists());
+ for (File siteDir : testDir.listFiles()) {
+ if (!siteDir.isDirectory())
+ continue;
+
+ if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
+ + URL_POSTFIX)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public void testMetrics() {
+ String state = Environment.getExternalStorageState();
+
+ if (!Environment.MEDIA_MOUNTED.equals(state)
+ && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ Log.d(LOGTAG, "ARG Can't access sd card!");
+ // Can't read the SD card, fail and die!
+ getInstrumentation().sendStatus(1, null);
+ return;
+ }
+
+ // use mGraphs as a condition variable between the UI thread and
+ // this(the testing) thread
+ mActivity.setCallback(new ProfileCallback() {
+ @Override
+ public void profileCallback(RunData data) {
+ Log.d(LOGTAG, "test completion callback");
+ mStats.setData(data);
+ synchronized (mStats) {
+ mStats.notify();
+ }
+ }
+ });
+
+ for (int i = 0; i < MAX_ITERATIONS; i++)
+ if (!runIteration()) {
+ getInstrumentation().sendStatus(1, null);
+ return;
+ }
+ getInstrumentation().sendStatus(0, mStats.getBundle());
+ }
+}