Merge "Move SyncStateContentProviderHelper to frameworks/ex"
diff --git a/api/current.xml b/api/current.xml
index 126da0e..1fe1498 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2114,7 +2114,7 @@
type="int"
transient="false"
volatile="false"
- value="16843567"
+ value="16843566"
static="true"
final="true"
deprecated="not deprecated"
@@ -2136,7 +2136,7 @@
type="int"
transient="false"
volatile="false"
- value="16843576"
+ value="16843575"
static="true"
final="true"
deprecated="not deprecated"
@@ -2147,7 +2147,7 @@
type="int"
transient="false"
volatile="false"
- value="16843575"
+ value="16843574"
static="true"
final="true"
deprecated="not deprecated"
@@ -2158,18 +2158,7 @@
type="int"
transient="false"
volatile="false"
- value="16843577"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="actionButtonPadding"
- type="int"
- transient="false"
- volatile="false"
- value="16843547"
+ value="16843576"
static="true"
final="true"
deprecated="not deprecated"
@@ -2202,7 +2191,7 @@
type="int"
transient="false"
volatile="false"
- value="16843584"
+ value="16843582"
static="true"
final="true"
deprecated="not deprecated"
@@ -2213,7 +2202,7 @@
type="int"
transient="false"
volatile="false"
- value="16843549"
+ value="16843548"
static="true"
final="true"
deprecated="not deprecated"
@@ -2224,7 +2213,7 @@
type="int"
transient="false"
volatile="false"
- value="16843580"
+ value="16843578"
static="true"
final="true"
deprecated="not deprecated"
@@ -2235,7 +2224,7 @@
type="int"
transient="false"
volatile="false"
- value="16843550"
+ value="16843549"
static="true"
final="true"
deprecated="not deprecated"
@@ -2246,7 +2235,7 @@
type="int"
transient="false"
volatile="false"
- value="16843578"
+ value="16843577"
static="true"
final="true"
deprecated="not deprecated"
@@ -2257,7 +2246,7 @@
type="int"
transient="false"
volatile="false"
- value="16843585"
+ value="16843583"
static="true"
final="true"
deprecated="not deprecated"
@@ -2268,7 +2257,7 @@
type="int"
transient="false"
volatile="false"
- value="16843586"
+ value="16843584"
static="true"
final="true"
deprecated="not deprecated"
@@ -2367,7 +2356,7 @@
type="int"
transient="false"
volatile="false"
- value="16843598"
+ value="16843596"
static="true"
final="true"
deprecated="not deprecated"
@@ -2488,7 +2477,7 @@
type="int"
transient="false"
volatile="false"
- value="16843574"
+ value="16843573"
static="true"
final="true"
deprecated="not deprecated"
@@ -2829,7 +2818,7 @@
type="int"
transient="false"
volatile="false"
- value="16843593"
+ value="16843591"
static="true"
final="true"
deprecated="not deprecated"
@@ -2840,7 +2829,7 @@
type="int"
transient="false"
volatile="false"
- value="16843592"
+ value="16843590"
static="true"
final="true"
deprecated="not deprecated"
@@ -2869,6 +2858,17 @@
visibility="public"
>
</field>
+<field name="buttonGroupStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843599"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="buttonStyle"
type="int"
transient="false"
@@ -3643,7 +3643,7 @@
type="int"
transient="false"
volatile="false"
- value="16843597"
+ value="16843595"
static="true"
final="true"
deprecated="not deprecated"
@@ -3760,6 +3760,17 @@
visibility="public"
>
</field>
+<field name="dividerVertical"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843598"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="drawSelectorOnTop"
type="int"
transient="false"
@@ -4501,7 +4512,7 @@
type="int"
transient="false"
volatile="false"
- value="16843557"
+ value="16843556"
static="true"
final="true"
deprecated="not deprecated"
@@ -4512,7 +4523,7 @@
type="int"
transient="false"
volatile="false"
- value="16843561"
+ value="16843560"
static="true"
final="true"
deprecated="not deprecated"
@@ -4523,7 +4534,7 @@
type="int"
transient="false"
volatile="false"
- value="16843562"
+ value="16843561"
static="true"
final="true"
deprecated="not deprecated"
@@ -4534,7 +4545,7 @@
type="int"
transient="false"
volatile="false"
- value="16843563"
+ value="16843562"
static="true"
final="true"
deprecated="not deprecated"
@@ -4545,7 +4556,7 @@
type="int"
transient="false"
volatile="false"
- value="16843564"
+ value="16843563"
static="true"
final="true"
deprecated="not deprecated"
@@ -4556,7 +4567,7 @@
type="int"
transient="false"
volatile="false"
- value="16843559"
+ value="16843558"
static="true"
final="true"
deprecated="not deprecated"
@@ -4567,7 +4578,7 @@
type="int"
transient="false"
volatile="false"
- value="16843560"
+ value="16843559"
static="true"
final="true"
deprecated="not deprecated"
@@ -4578,7 +4589,7 @@
type="int"
transient="false"
volatile="false"
- value="16843565"
+ value="16843564"
static="true"
final="true"
deprecated="not deprecated"
@@ -4589,7 +4600,7 @@
type="int"
transient="false"
volatile="false"
- value="16843566"
+ value="16843565"
static="true"
final="true"
deprecated="not deprecated"
@@ -5073,7 +5084,7 @@
type="int"
transient="false"
volatile="false"
- value="16843583"
+ value="16843581"
static="true"
final="true"
deprecated="not deprecated"
@@ -5194,7 +5205,7 @@
type="int"
transient="false"
volatile="false"
- value="16843570"
+ value="16843569"
static="true"
final="true"
deprecated="not deprecated"
@@ -5205,7 +5216,7 @@
type="int"
transient="false"
volatile="false"
- value="16843568"
+ value="16843567"
static="true"
final="true"
deprecated="not deprecated"
@@ -5216,7 +5227,7 @@
type="int"
transient="false"
volatile="false"
- value="16843569"
+ value="16843568"
static="true"
final="true"
deprecated="not deprecated"
@@ -5575,17 +5586,6 @@
visibility="public"
>
</field>
-<field name="itemPadding"
- type="int"
- transient="false"
- volatile="false"
- value="16843579"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="itemTextAppearance"
type="int"
transient="false"
@@ -6855,7 +6855,7 @@
type="int"
transient="false"
volatile="false"
- value="16843572"
+ value="16843571"
static="true"
final="true"
deprecated="not deprecated"
@@ -6899,7 +6899,7 @@
type="int"
transient="false"
volatile="false"
- value="16843594"
+ value="16843592"
static="true"
final="true"
deprecated="not deprecated"
@@ -6910,7 +6910,7 @@
type="int"
transient="false"
volatile="false"
- value="16843588"
+ value="16843586"
static="true"
final="true"
deprecated="not deprecated"
@@ -6998,7 +6998,7 @@
type="int"
transient="false"
volatile="false"
- value="16843596"
+ value="16843594"
static="true"
final="true"
deprecated="not deprecated"
@@ -7482,7 +7482,7 @@
type="int"
transient="false"
volatile="false"
- value="16843556"
+ value="16843555"
static="true"
final="true"
deprecated="not deprecated"
@@ -7812,7 +7812,7 @@
type="int"
transient="false"
volatile="false"
- value="16843589"
+ value="16843587"
static="true"
final="true"
deprecated="not deprecated"
@@ -7911,7 +7911,7 @@
type="int"
transient="false"
volatile="false"
- value="16843548"
+ value="16843547"
static="true"
final="true"
deprecated="not deprecated"
@@ -8076,7 +8076,7 @@
type="int"
transient="false"
volatile="false"
- value="16843555"
+ value="16843554"
static="true"
final="true"
deprecated="not deprecated"
@@ -9121,7 +9121,7 @@
type="int"
transient="false"
volatile="false"
- value="16843573"
+ value="16843572"
static="true"
final="true"
deprecated="not deprecated"
@@ -9143,7 +9143,7 @@
type="int"
transient="false"
volatile="false"
- value="16843571"
+ value="16843570"
static="true"
final="true"
deprecated="not deprecated"
@@ -9242,7 +9242,7 @@
type="int"
transient="false"
volatile="false"
- value="16843587"
+ value="16843585"
static="true"
final="true"
deprecated="not deprecated"
@@ -9473,7 +9473,7 @@
type="int"
transient="false"
volatile="false"
- value="16843582"
+ value="16843580"
static="true"
final="true"
deprecated="not deprecated"
@@ -9858,7 +9858,7 @@
type="int"
transient="false"
volatile="false"
- value="16843590"
+ value="16843588"
static="true"
final="true"
deprecated="not deprecated"
@@ -9935,7 +9935,7 @@
type="int"
transient="false"
volatile="false"
- value="16843591"
+ value="16843589"
static="true"
final="true"
deprecated="not deprecated"
@@ -9979,7 +9979,7 @@
type="int"
transient="false"
volatile="false"
- value="16843595"
+ value="16843593"
static="true"
final="true"
deprecated="not deprecated"
@@ -10173,6 +10173,17 @@
visibility="public"
>
</field>
+<field name="textLineHeight"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843597"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="textOff"
type="int"
transient="false"
@@ -10397,7 +10408,7 @@
type="int"
transient="false"
volatile="false"
- value="16843581"
+ value="16843579"
static="true"
final="true"
deprecated="not deprecated"
@@ -10672,7 +10683,7 @@
type="int"
transient="false"
volatile="false"
- value="16843552"
+ value="16843551"
static="true"
final="true"
deprecated="not deprecated"
@@ -10683,7 +10694,7 @@
type="int"
transient="false"
volatile="false"
- value="16843553"
+ value="16843552"
static="true"
final="true"
deprecated="not deprecated"
@@ -10694,7 +10705,7 @@
type="int"
transient="false"
volatile="false"
- value="16843554"
+ value="16843553"
static="true"
final="true"
deprecated="not deprecated"
@@ -11024,7 +11035,7 @@
type="int"
transient="false"
volatile="false"
- value="16843558"
+ value="16843557"
static="true"
final="true"
deprecated="not deprecated"
@@ -11035,7 +11046,7 @@
type="int"
transient="false"
volatile="false"
- value="16843551"
+ value="16843550"
static="true"
final="true"
deprecated="not deprecated"
@@ -16937,7 +16948,7 @@
type="int"
transient="false"
volatile="false"
- value="16973984"
+ value="16973987"
static="true"
final="true"
deprecated="not deprecated"
@@ -16948,7 +16959,7 @@
type="int"
transient="false"
volatile="false"
- value="16973985"
+ value="16973988"
static="true"
final="true"
deprecated="not deprecated"
@@ -17087,6 +17098,39 @@
visibility="public"
>
</field>
+<field name="Theme_Holo_Dialog"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973981"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Holo_Light"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973980"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="Theme_Holo_Light_Dialog"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973982"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Theme_Holo_NoActionBar"
type="int"
transient="false"
@@ -17388,7 +17432,7 @@
type="int"
transient="false"
volatile="false"
- value="16973983"
+ value="16973986"
static="true"
final="true"
deprecated="not deprecated"
@@ -17399,7 +17443,7 @@
type="int"
transient="false"
volatile="false"
- value="16973982"
+ value="16973985"
static="true"
final="true"
deprecated="not deprecated"
@@ -17553,7 +17597,7 @@
type="int"
transient="false"
volatile="false"
- value="16973986"
+ value="16973989"
static="true"
final="true"
deprecated="not deprecated"
@@ -17619,7 +17663,7 @@
type="int"
transient="false"
volatile="false"
- value="16973980"
+ value="16973983"
static="true"
final="true"
deprecated="not deprecated"
@@ -17674,7 +17718,7 @@
type="int"
transient="false"
volatile="false"
- value="16973981"
+ value="16973984"
static="true"
final="true"
deprecated="not deprecated"
@@ -28843,7 +28887,7 @@
</parameter>
</method>
<method name="remove"
- return="void"
+ return="int"
abstract="false"
native="false"
synchronized="false"
@@ -28852,7 +28896,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="id" type="long">
+<parameter name="ids" type="long...">
</parameter>
</method>
<field name="ACTION_DOWNLOAD_COMPLETE"
@@ -29256,7 +29300,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="id" type="long">
+<parameter name="ids" type="long...">
</parameter>
</method>
<method name="setFilterByStatus"
@@ -134181,6 +134225,17 @@
visibility="public"
>
</constructor>
+<field name="BATTERY_HEALTH_COLD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="BATTERY_HEALTH_DEAD"
type="int"
transient="false"
@@ -137617,6 +137672,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.io.Closeable">
+</implements>
<implements name="android.os.Parcelable">
</implements>
<constructor name="DropBoxManager.Entry"
@@ -225087,6 +225144,19 @@
<parameter name="filterText" type="java.lang.String">
</parameter>
</method>
+<method name="setFriction"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="friction" type="float">
+</parameter>
+</method>
<method name="setItemChecked"
return="void"
abstract="false"
@@ -228698,6 +228768,51 @@
</parameter>
</constructor>
</class>
+<class name="ButtonGroup"
+ extends="android.widget.LinearLayout"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ButtonGroup"
+ type="android.widget.ButtonGroup"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="ButtonGroup"
+ type="android.widget.ButtonGroup"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="ButtonGroup"
+ type="android.widget.ButtonGroup"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+<parameter name="defStyleRes" type="int">
+</parameter>
+</constructor>
+</class>
<class name="CheckBox"
extends="android.widget.CompoundButton"
abstract="false"
@@ -238603,6 +238718,19 @@
<parameter name="newY" type="int">
</parameter>
</method>
+<method name="setFriction"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="friction" type="float">
+</parameter>
+</method>
<method name="startScroll"
return="void"
abstract="false"
@@ -242956,6 +243084,19 @@
<parameter name="input" type="android.text.method.KeyListener">
</parameter>
</method>
+<method name="setLineHeight"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="lineHeight" type="int">
+</parameter>
+</method>
<method name="setLineSpacing"
return="void"
abstract="false"
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index d2b17f0..a6f061d 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -46,7 +46,7 @@
/*
* The default amount of time in ms between animation frames
*/
- private static final long DEFAULT_FRAME_DELAY = 30;
+ private static final long DEFAULT_FRAME_DELAY = 10;
/**
* Messages sent to timing handler: START is sent when an animation first begins, FRAME is sent
@@ -469,7 +469,8 @@
// If there are still active or delayed animations, call the handler again
// after the frameDelay
if (callAgain && (!sAnimations.isEmpty() || !sDelayedAnims.isEmpty())) {
- sendEmptyMessageDelayed(ANIMATION_FRAME, sFrameDelay);
+ sendEmptyMessageDelayed(ANIMATION_FRAME, Math.max(0, sFrameDelay -
+- (AnimationUtils.currentAnimationTimeMillis() - currentTime)));
}
break;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 092fa2a..1ef529c 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2752,14 +2752,15 @@
private final File mBackupFile;
private final int mMode;
- private Map<String, Object> mMap; // guarded by 'this'
- private long mTimestamp; // guarded by 'this'
+ private Map<String, Object> mMap; // guarded by 'this'
private int mDiskWritesInFlight = 0; // guarded by 'this'
- private boolean mLoaded = false; // guarded by 'this'
+ private boolean mLoaded = false; // guarded by 'this'
+ private long mStatTimestamp; // guarded by 'this'
+ private long mStatSize; // guarded by 'this'
private final Object mWritingToDiskLock = new Object();
private static final Object mContent = new Object();
- private WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
+ private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
SharedPreferencesImpl(
File file, int mode, Map initialContents) {
@@ -2770,7 +2771,7 @@
mMap = initialContents != null ? initialContents : new HashMap<String, Object>();
FileStatus stat = new FileStatus();
if (FileUtils.getFileStatus(file.getPath(), stat)) {
- mTimestamp = stat.mtime;
+ mStatTimestamp = stat.mtime;
}
mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
}
@@ -2797,7 +2798,7 @@
return true;
}
synchronized (this) {
- return mTimestamp != stat.mtime;
+ return mStatTimestamp != stat.mtime || mStatSize != stat.size;
}
}
@@ -3191,7 +3192,8 @@
FileStatus stat = new FileStatus();
if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
synchronized (this) {
- mTimestamp = stat.mtime;
+ mStatTimestamp = stat.mtime;
+ mStatSize = stat.size;
}
}
// Writing was successful, delete the backup file if there is one.
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index f0a8dfd..b9a541d 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -28,6 +28,7 @@
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import android.provider.Downloads;
+import android.util.Log;
import android.util.Pair;
import java.io.File;
@@ -53,6 +54,8 @@
* download in a notification or from the downloads UI.
*/
public class DownloadManager {
+ private static final String TAG = "DownloadManager";
+
/**
* An identifier for a particular download, unique across the system. Clients use this ID to
* make subsequent calls related to the download.
@@ -573,18 +576,18 @@
*/
public static final int ORDER_DESCENDING = 2;
- private Long mId = null;
+ private long[] mIds = null;
private Integer mStatusFlags = null;
private String mOrderByColumn = Downloads.COLUMN_LAST_MODIFICATION;
private int mOrderDirection = ORDER_DESCENDING;
private boolean mOnlyIncludeVisibleInDownloadsUi = false;
/**
- * Include only the download with the given ID.
+ * Include only the downloads with the given IDs.
* @return this object
*/
- public Query setFilterById(long id) {
- mId = id;
+ public Query setFilterById(long... ids) {
+ mIds = ids;
return this;
}
@@ -645,9 +648,11 @@
Cursor runQuery(ContentResolver resolver, String[] projection, Uri baseUri) {
Uri uri = baseUri;
List<String> selectionParts = new ArrayList<String>();
+ String[] selectionArgs = null;
- if (mId != null) {
- uri = ContentUris.withAppendedId(uri, mId);
+ if (mIds != null) {
+ selectionParts.add(getWhereClauseForIds(mIds));
+ selectionArgs = getWhereArgsForIds(mIds);
}
if (mStatusFlags != null) {
@@ -682,7 +687,7 @@
String orderDirection = (mOrderDirection == ORDER_ASCENDING ? "ASC" : "DESC");
String orderBy = mOrderByColumn + " " + orderDirection;
- return resolver.query(uri, projection, selection, null, orderBy);
+ return resolver.query(uri, projection, selection, selectionArgs, orderBy);
}
private String joinStrings(String joiner, Iterable<String> parts) {
@@ -744,17 +749,19 @@
}
/**
- * Cancel a download and remove it from the download manager. The download will be stopped if
+ * Cancel downloads and remove them from the download manager. Each download will be stopped if
* it was running, and it will no longer be accessible through the download manager. If a file
- * was already downloaded, it will not be deleted.
+ * was already downloaded to external storage, it will not be deleted.
*
- * @param id the ID of the download
+ * @param ids the IDs of the downloads to remove
+ * @return the number of downloads actually removed
*/
- public void remove(long id) {
- int numDeleted = mResolver.delete(getDownloadUri(id), null, null);
- if (numDeleted == 0) {
- throw new IllegalArgumentException("Download " + id + " does not exist");
+ public int remove(long... ids) {
+ if (ids == null || ids.length == 0) {
+ // called with nothing to remove!
+ throw new IllegalArgumentException("input param 'ids' can't be null");
}
+ return mResolver.delete(mBaseUri, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
}
/**
@@ -782,20 +789,20 @@
}
/**
- * Restart the given download, which must have already completed (successfully or not). This
+ * Restart the given downloads, which must have already completed (successfully or not). This
* method will only work when called from within the download manager's process.
- * @param id the ID of the download
+ * @param ids the IDs of the downloads
* @hide
*/
- public void restartDownload(long id) {
- Cursor cursor = query(new Query().setFilterById(id));
+ public void restartDownload(long... ids) {
+ Cursor cursor = query(new Query().setFilterById(ids));
try {
- if (!cursor.moveToFirst()) {
- throw new IllegalArgumentException("No download with id " + id);
- }
- int status = cursor.getInt(cursor.getColumnIndex(COLUMN_STATUS));
- if (status != STATUS_SUCCESSFUL && status != STATUS_FAILED) {
- throw new IllegalArgumentException("Cannot restart incomplete download: " + id);
+ for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+ int status = cursor.getInt(cursor.getColumnIndex(COLUMN_STATUS));
+ if (status != STATUS_SUCCESSFUL && status != STATUS_FAILED) {
+ throw new IllegalArgumentException("Cannot restart incomplete download: "
+ + cursor.getLong(cursor.getColumnIndex(COLUMN_ID)));
+ }
}
} finally {
cursor.close();
@@ -806,7 +813,7 @@
values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, -1);
values.putNull(Downloads.Impl._DATA);
values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
- mResolver.update(getDownloadUri(id), values, null, null);
+ mResolver.update(mBaseUri, values, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
}
/**
@@ -817,6 +824,34 @@
}
/**
+ * Get a parameterized SQL WHERE clause to select a bunch of IDs.
+ */
+ static String getWhereClauseForIds(long[] ids) {
+ StringBuilder whereClause = new StringBuilder();
+ whereClause.append("(");
+ for (int i = 0; i < ids.length; i++) {
+ if (i > 0) {
+ whereClause.append("OR ");
+ }
+ whereClause.append(Downloads.Impl._ID);
+ whereClause.append(" = ? ");
+ }
+ whereClause.append(")");
+ return whereClause.toString();
+ }
+
+ /**
+ * Get the selection args for a clause returned by {@link #getWhereClauseForIds(long[])}.
+ */
+ static String[] getWhereArgsForIds(long[] ids) {
+ String[] whereArgs = new String[ids.length];
+ for (int i = 0; i < ids.length; i++) {
+ whereArgs[i] = Long.toString(ids[i]);
+ }
+ return whereArgs;
+ }
+
+ /**
* This class wraps a cursor returned by DownloadProvider -- the "underlying cursor" -- and
* presents a different set of columns, those defined in the DownloadManager.COLUMN_* constants.
* Some columns correspond directly to underlying values while others are computed from
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index c0788f5..4d9ee54 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -198,9 +198,21 @@
* {@link #commit} will block until all async commits are
* completed as well as the commit itself.
*
- * <p>If you call this from an {@link android.app.Activity},
- * the base class will wait for any async commits to finish in
- * its {@link android.app.Activity#onPause}.</p>
+ * <p>As {@link SharedPreferences} instances are singletons within
+ * a process, it's safe to replace any instance of {@link #commit} with
+ * {@link #apply} if you were already ignoring the return value.
+ *
+ * <p>You don't need to worry about Android component
+ * lifecycles and their interaction with <code>apply()</code>
+ * writing to disk. The framework makes sure in-flight disk
+ * writes from <code>apply()</code> complete before switching
+ * states.
+ *
+ * <p class='note'>The SharedPreferences.Editor interface
+ * isn't expected to be implemented directly. However, if you
+ * previously did implement it and are now getting errors
+ * about missing <code>apply()</code>, you can simply call
+ * {@link #commit} from <code>apply()</code>.
*/
void apply();
}
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 22968b0..3447e76c 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -98,7 +98,8 @@
}
@Override public boolean onTextContextMenuItem(int id) {
- if (mIME != null) {
+ // Horrible hack: select word option has to be handled by original view to work.
+ if (mIME != null && id != android.R.id.startSelectingText) {
if (mIME.onExtractTextContextMenuItem(id)) {
return true;
}
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index 830ff06..23a3ea8 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -299,15 +299,15 @@
final URI uri = URI.create(url);
final String host = uri.getHost();
if (host != null) {
- if (host.equalsIgnoreCase("localhost")) {
- return true;
- }
- if (InetAddress.getByName(host).isLoopbackAddress()) {
+ // TODO: InetAddress.isLoopbackAddress should be used to check
+ // for localhost. However no public factory methods exist which
+ // can be used without triggering DNS lookup if host is not localhost.
+ if (host.equalsIgnoreCase("localhost") ||
+ host.equals("127.0.0.1") ||
+ host.equals("[::1]")) {
return true;
}
}
- } catch (UnknownHostException uex) {
- // Ignore (INetworkSystem.ipStringToByteArray)
} catch (IllegalArgumentException iex) {
// Ignore (URI.create)
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 5fd2246..247b281 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -107,6 +107,7 @@
public static final int BATTERY_HEALTH_DEAD = 4;
public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;
public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
+ public static final int BATTERY_HEALTH_COLD = 7;
// values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.
// These must be powers of 2.
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index d49c8be..d67e6f5 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -449,6 +449,10 @@
public static final int STATE_WAKE_LOCK_FLAG = 1<<17;
public static final int STATE_SENSOR_ON_FLAG = 1<<16;
+ public static final int MOST_INTERESTING_STATES =
+ STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG
+ | STATE_GPS_ON_FLAG | STATE_PHONE_IN_CALL_FLAG;
+
public int states;
public HistoryItem() {
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index fa23458..a47c66a 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -21,6 +21,7 @@
import com.android.internal.os.IDropBoxManagerService;
import java.io.ByteArrayInputStream;
+import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -61,7 +62,7 @@
* This may include a reference to a stream, so you must call
* {@link #close()} when you are done using it.
*/
- public static class Entry implements Parcelable {
+ public static class Entry implements Parcelable, Closeable {
private final String mTag;
private final long mTimeMillis;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 17b2e82..12b9f0c 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1242,7 +1242,14 @@
private void tryCommit(SharedPreferences.Editor editor) {
if (mPreferenceManager.shouldCommit()) {
- editor.apply();
+ try {
+ editor.apply();
+ } catch (AbstractMethodError unused) {
+ // The app injected its own pre-Gingerbread
+ // SharedPreferences.Editor implementation without
+ // an apply method.
+ editor.commit();
+ }
}
}
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 42150ed..6562de90 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -461,7 +461,16 @@
pm.setSharedPreferencesMode(sharedPreferencesMode);
pm.inflateFromResource(context, resId, null);
- defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true).apply();
+ SharedPreferences.Editor editor =
+ defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true);
+ try {
+ editor.apply();
+ } catch (AbstractMethodError unused) {
+ // The app injected its own pre-Gingerbread
+ // SharedPreferences.Editor implementation without
+ // an apply method.
+ editor.commit();
+ }
}
}
@@ -496,15 +505,21 @@
boolean shouldCommit() {
return !mNoCommit;
}
-
+
private void setNoCommit(boolean noCommit) {
if (!noCommit && mEditor != null) {
- mEditor.apply();
+ try {
+ mEditor.apply();
+ } catch (AbstractMethodError unused) {
+ // The app injected its own pre-Gingerbread
+ // SharedPreferences.Editor implementation without
+ // an apply method.
+ mEditor.commit();
+ }
}
-
mNoCommit = noCommit;
}
-
+
/**
* Returns the activity that shows the preferences. This is useful for doing
* managed queries, but in most cases the use of {@link #getContext()} is
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 9e7eedf..0e5ece1 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -46,10 +46,12 @@
* with the special action {@link #ACTION_MULTIPLE} that either specifies
* that single repeated key code or a sequence of characters to insert.
* </p><p>
- * In general, the framework makes no guarantees that the key events delivered
- * to a view constitute a complete key press. In particular, there is no
- * guarantee that a view will always receive a key event with {@link #ACTION_UP}
- * for each {@link #ACTION_DOWN} that was delivered.
+ * In general, the framework cannot guarantee that the key events it delivers
+ * to a view always constitute complete key sequences since some events may be dropped
+ * or modified by containing views before they are delivered. The view implementation
+ * should be prepared to handle {@link #FLAG_CANCELED} and should tolerate anomalous
+ * situations such as receiving a new {@link #ACTION_DOWN} without first having
+ * received an {@link #ACTION_UP} for the prior key press.
* </p><p>
* Refer to {@link InputDevice} for more information about how different kinds of
* input devices and sources represent keys and buttons.
@@ -195,7 +197,8 @@
public static final int KEYCODE_TAB = 61;
/** Key code constant: Space key. */
public static final int KEYCODE_SPACE = 62;
- /** Key code constant: Symbol modifier key. */
+ /** Key code constant: Symbol modifier key.
+ * Used to enter alternate symbols. */
public static final int KEYCODE_SYM = 63;
/** Key code constant: Explorer special function key.
* Used to launch a browser application. */
@@ -205,7 +208,8 @@
public static final int KEYCODE_ENVELOPE = 65;
/** Key code constant: Enter key. */
public static final int KEYCODE_ENTER = 66;
- /** Key code constant: Delete key. */
+ /** Key code constant: Backspace key.
+ * Deletes characters before the insertion point. */
public static final int KEYCODE_DEL = 67;
/** Key code constant: '`' (backtick) key. */
public static final int KEYCODE_GRAVE = 68;
@@ -227,7 +231,10 @@
public static final int KEYCODE_SLASH = 76;
/** Key code constant: '@' key. */
public static final int KEYCODE_AT = 77;
- /** Key code constant: Number Lock modifier key. */
+ /** Key code constant: Number modifier key.
+ * Used to enter numeric symbols.
+ * This key is not Num Lock; it is more like {@link #KEYCODE_ALT_LEFT} and is
+ * interpreted as an ALT key by {@link android.text.method.MetaKeyKeyListener}. */
public static final int KEYCODE_NUM = 78;
/** Key code constant: Headset Hook key.
* Used to hang up calls and stop media. */
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index dfbe65c..9411474 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -82,10 +82,12 @@
* }
* }
* </code></pre></p><p>
- * In general, the framework makes no guarantees that the motion events delivered
- * to a view constitute a complete gesture. In particular, there is no
- * guarantee that a view will always receive a motion event with {@link #ACTION_UP}
- * for each {@link #ACTION_DOWN} that was delivered.
+ * In general, the framework cannot guarantee that the motion events it delivers
+ * to a view always constitute a complete motion sequences since some events may be dropped
+ * or modified by containing views before they are delivered. The view implementation
+ * should be prepared to handle {@link #ACTION_CANCEL} and should tolerate anomalous
+ * situations such as receiving a new {@link #ACTION_DOWN} without first having
+ * received an {@link #ACTION_UP} for the prior gesture.
* </p><p>
* Refer to {@link InputDevice} for more information about how different kinds of
* input devices and sources represent pointer coordinates.
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index acdfc28..f413475 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -25,6 +25,20 @@
*/
public class ViewConfiguration {
/**
+ * Expected bit depth of the display panel.
+ *
+ * @hide
+ */
+ public static final float PANEL_BIT_DEPTH = 24;
+
+ /**
+ * Minimum alpha required for a view to draw.
+ *
+ * @hide
+ */
+ public static final float ALPHA_THRESHOLD = 0.5f / PANEL_BIT_DEPTH;
+
+ /**
* Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
* pixels
*/
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5b3a091..be6aa43b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -69,7 +69,7 @@
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
private static final boolean DBG = false;
-
+
/**
* Views which have been hidden or removed which need to be animated on
* their way out.
@@ -2185,6 +2185,10 @@
(child.mPrivateFlags & DRAW_ANIMATION) == 0) {
return more;
}
+
+ float alpha = child.getAlpha();
+ // Bail out early if the view does not need to be drawn
+ if (alpha <= ViewConfiguration.ALPHA_THRESHOLD) return more;
child.computeScroll();
@@ -2217,8 +2221,6 @@
}
}
- float alpha = child.getAlpha();
-
if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
int transX = 0;
int transY = 0;
@@ -2253,7 +2255,7 @@
if (alpha < 1.0f) {
mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-
+
if (hasNoCache) {
final int multipliedAlpha = (int) (255 * alpha);
if (!child.onSetAlpha(multipliedAlpha)) {
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 79f1f5b..7907ad2 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1280,7 +1280,9 @@
}
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
- if (!dirty.isEmpty()) {
+ if (!dirty.isEmpty() || mIsAnimating) {
+ mIsAnimating = false;
+ dirty.setEmpty();
mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, yoff);
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 954b3e7..1fd31a3 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -65,6 +65,7 @@
* @hide
*/
public interface WindowManagerPolicy {
+ // Policy flags. These flags are also defined in frameworks/base/include/ui/Input.h.
public final static int FLAG_WAKE = 0x00000001;
public final static int FLAG_WAKE_DROPPED = 0x00000002;
public final static int FLAG_SHIFT = 0x00000004;
@@ -76,9 +77,11 @@
public final static int FLAG_VIRTUAL = 0x00000100;
public final static int FLAG_INJECTED = 0x01000000;
+ public final static int FLAG_TRUSTED = 0x02000000;
public final static int FLAG_WOKE_HERE = 0x10000000;
public final static int FLAG_BRIGHT_HERE = 0x20000000;
+ public final static int FLAG_PASS_TO_USER = 0x40000000;
public final static boolean WATCH_POINTER = false;
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index efe4b9d..bef5388 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -73,7 +73,7 @@
// that if the UI thread posts any messages after the message
// queue has been cleared,they are ignored.
private boolean mBlockMessages = false;
-
+ private int mOrientation = -1;
private static String sDatabaseDirectory;
private static String sCacheDirectory;
@@ -497,7 +497,10 @@
}
case ORIENTATION_CHANGED: {
- nativeOrientationChanged(msg.arg1);
+ if (mOrientation != msg.arg1) {
+ mOrientation = msg.arg1;
+ nativeOrientationChanged(msg.arg1);
+ }
break;
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index fedb873..5d68613 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1972,6 +1972,7 @@
* bounds of the view.
*/
public Picture capturePicture() {
+ if (mNativeClass == 0) return null;
Picture result = new Picture();
nativeCopyBaseContentToPicture(result);
return result;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index c694ff1..2af59f9 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2965,7 +2965,7 @@
final int firstPos = mFirstPosition;
final int lastPos = firstPos + getChildCount() - 1;
- int viewTravelCount = 0;
+ int viewTravelCount;
if (position <= firstPos) {
viewTravelCount = firstPos - position + 1;
mMode = MOVE_UP_POS;
@@ -2998,7 +2998,7 @@
final int firstPos = mFirstPosition;
final int lastPos = firstPos + getChildCount() - 1;
- int viewTravelCount = 0;
+ int viewTravelCount;
if (position <= firstPos) {
final int boundPosFromLast = lastPos - boundPosition;
if (boundPosFromLast < 1) {
@@ -3059,7 +3059,7 @@
final int childCount = getChildCount();
final int lastPos = firstPos + childCount - 1;
- int viewTravelCount = 0;
+ int viewTravelCount;
if (position < firstPos) {
viewTravelCount = firstPos - position;
} else if (position > lastPos) {
@@ -3249,6 +3249,20 @@
}
/**
+ * The amount of friction applied to flings. The default value
+ * is {@link ViewConfiguration#getScrollFriction}.
+ *
+ * @return A scalar dimensionless value representing the coefficient of
+ * friction.
+ */
+ public void setFriction(float friction) {
+ if (mFlingRunnable == null) {
+ mFlingRunnable = new FlingRunnable();
+ }
+ mFlingRunnable.mScroller.setFriction(friction);
+ }
+
+ /**
* Smoothly scroll to the specified adapter position. The view will
* scroll such that the indicated position is displayed.
* @param position Scroll to this adapter position.
@@ -3581,22 +3595,6 @@
* @return The position of the first (or only) item in the row containing y
*/
abstract int findMotionRow(int y);
-
- /**
- * Find the row closest to y. This row will be used as the motion row when scrolling.
- *
- * @param y Where the user touched
- * @return The position of the first (or only) item in the row closest to y
- */
- int findClosestMotionRow(int y) {
- final int childCount = getChildCount();
- if (childCount == 0) {
- return INVALID_POSITION;
- }
-
- final int motionRow = findMotionRow(y);
- return motionRow != INVALID_POSITION ? motionRow : mFirstPosition + childCount - 1;
- }
/**
* Causes all the views to be rebuilt and redrawn.
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index aa14c81..d3aa42f 100755
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -17,14 +17,14 @@
package android.widget;
import com.android.internal.R;
+
import android.content.Context;
-import android.content.res.Resources;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageParser;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
@@ -329,11 +329,6 @@
TextView permGrpView = (TextView) permView.findViewById(R.id.permission_group);
TextView permDescView = (TextView) permView.findViewById(R.id.permission_list);
- if (dangerous) {
- final Resources resources = context.getResources();
- permGrpView.setTextColor(resources.getColor(R.color.perms_dangerous_grp_color));
- permDescView.setTextColor(resources.getColor(R.color.perms_dangerous_perm_color));
- }
ImageView imgView = (ImageView)permView.findViewById(R.id.perm_icon);
imgView.setImageDrawable(icon);
diff --git a/core/java/android/widget/ButtonGroup.java b/core/java/android/widget/ButtonGroup.java
new file mode 100644
index 0000000..a23ea07
--- /dev/null
+++ b/core/java/android/widget/ButtonGroup.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class ButtonGroup extends LinearLayout {
+ private Drawable mDivider;
+ private Drawable mButtonBackground;
+
+ public ButtonGroup(Context context) {
+ this(context, null);
+ }
+
+ public ButtonGroup(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.buttonGroupStyle);
+ }
+
+ public ButtonGroup(Context context, AttributeSet attrs, int defStyleRes) {
+ super(context, attrs, defStyleRes);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.ButtonGroup);
+
+ mDivider = a.getDrawable(com.android.internal.R.styleable.ButtonGroup_divider);
+ mButtonBackground = a.getDrawable(
+ com.android.internal.R.styleable.ButtonGroup_buttonBackground);
+ a.recycle();
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (getChildCount() > 0) {
+ super.addView(makeDividerView(), index, makeDividerLayoutParams());
+ if (index >= 0) {
+ index++;
+ }
+ }
+ child.setBackgroundDrawable(mButtonBackground);
+ super.addView(child, index, params);
+ }
+
+ private ImageView makeDividerView() {
+ ImageView result = new ImageView(mContext);
+ result.setImageDrawable(mDivider);
+ result.setScaleType(ImageView.ScaleType.FIT_XY);
+ return result;
+ }
+
+ private LayoutParams makeDividerLayoutParams() {
+ return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+ }
+}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 7c4897a..b5e103f 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -26,7 +26,6 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
@@ -2980,7 +2979,6 @@
if (!mStackFromBottom) {
int bottom;
- final int scrollY = mScrollY;
for (int i = 0; i < count; i++) {
if ((headerDividers || first + i >= headerCount) &&
(footerDividers || first + i < footerLimit)) {
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 4cb0839..d2e6688 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -63,7 +63,8 @@
private static final int SCROLL_MODE = 0;
private static final int FLING_MODE = 1;
- private final float mDeceleration;
+ private float mDeceleration;
+ private final float mPpi;
/**
* Create a Scroller with the default duration and interpolator.
@@ -79,13 +80,28 @@
public Scroller(Context context, Interpolator interpolator) {
mFinished = true;
mInterpolator = interpolator;
- float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
- mDeceleration = SensorManager.GRAVITY_EARTH // g (m/s^2)
- * 39.37f // inch/meter
- * ppi // pixels per inch
- * ViewConfiguration.getScrollFriction();
+ mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
+ mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
+ }
+
+ /**
+ * The amount of friction applied to flings. The default value
+ * is {@link ViewConfiguration#getScrollFriction}.
+ *
+ * @return A scalar dimensionless value representing the coefficient of
+ * friction.
+ */
+ public final void setFriction(float friction) {
+ computeDeceleration(friction);
}
+ private float computeDeceleration(float friction) {
+ return SensorManager.GRAVITY_EARTH // g (m/s^2)
+ * 39.37f // inch/meter
+ * mPpi // pixels per inch
+ * friction;
+ }
+
/**
*
* Returns whether the scroller has finished scrolling.
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index c0cbb19..b51d21a 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -589,7 +589,7 @@
setAnchorView(Spinner.this);
setModal(true);
- setPromptPosition(POSITION_PROMPT_BELOW);
+ setPromptPosition(POSITION_PROMPT_ABOVE);
setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
Spinner.this.setSelection(position);
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index f720cee..ff31dec 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -144,6 +144,11 @@
}
}
+ @Override
+ public void sendAccessibilityEvent(int eventType) {
+ /* avoid super class behavior - TabWidget sends the right events */
+ }
+
/**
* If you are using {@link TabSpec#setContent(android.content.Intent)}, this
* must be called since the activityGroup is needed to launch the local activity.
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index afae7ef..594b1e6 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -28,6 +28,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnFocusChangeListener;
+import android.view.accessibility.AccessibilityEvent;
/**
*
@@ -335,7 +336,7 @@
* @see #focusCurrentTab
*/
public void setCurrentTab(int index) {
- if (index < 0 || index >= getTabCount()) {
+ if (index < 0 || index >= getTabCount() || index == mSelectedTab) {
return;
}
@@ -343,6 +344,18 @@
mSelectedTab = index;
getChildTabViewAt(mSelectedTab).setSelected(true);
mStripMoved = true;
+
+ if (isShown()) {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+ }
+ }
+
+ @Override
+ public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+ event.setItemCount(getTabCount());
+ event.setCurrentItemIndex(mSelectedTab);
+ getChildTabViewAt(mSelectedTab).dispatchPopulateAccessibilityEvent(event);
+ return true;
}
/**
@@ -416,6 +429,15 @@
child.setOnFocusChangeListener(this);
}
+ @Override
+ public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
+ // this class fires events only when tabs are focused or selected
+ if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED && isFocused()) {
+ return;
+ }
+ super.sendAccessibilityEventUnchecked(event);
+ }
+
/**
* Provides a way for {@link TabHost} to be notified that the user clicked on a tab indicator.
*/
@@ -436,6 +458,10 @@
if (getChildTabViewAt(i) == v) {
setCurrentTab(i);
mSelectionChangedListener.onTabSelectionChanged(i, false);
+ if (isShown()) {
+ // a tab is focused so send an event to announce the tab widget state
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ }
break;
}
i++;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3ff235b..bacbb24 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -734,6 +734,12 @@
case com.android.internal.R.styleable.TextView_textSelectHandle:
mTextSelectHandleRes = a.getResourceId(attr, 0);
break;
+
+ case com.android.internal.R.styleable.TextView_textLineHeight:
+ int lineHeight = a.getDimensionPixelSize(attr, 0);
+ if (lineHeight != 0) {
+ setLineHeight(lineHeight);
+ }
}
}
a.recycle();
@@ -1063,6 +1069,9 @@
* or last-line padding.
*/
public int getLineHeight() {
+ if (mLineHeight != 0) {
+ return mLineHeight;
+ }
return FastMath.round(mTextPaint.getFontMetricsInt(null) * mSpacingMult
+ mSpacingAdd);
}
@@ -1655,10 +1664,27 @@
TextAppearance_textStyle, -1);
setTypefaceByIndex(typefaceIndex, styleIndex);
+
+ int lineHeight = appearance.getDimensionPixelSize(
+ com.android.internal.R.styleable.TextAppearance_textLineHeight, 0);
+ if (lineHeight != 0) {
+ setLineHeight(lineHeight);
+ }
+
appearance.recycle();
}
/**
+ * Set the height of a line of text in pixels. This value will override line height
+ * values stored in the font modified by lineSpacingExtra and lineSpacingMultiplier.
+ *
+ * @param lineHeight Desired height of a single line of text in pixels
+ */
+ public void setLineHeight(int lineHeight) {
+ mLineHeight = lineHeight;
+ }
+
+ /**
* @return the size (in pixels) of the default text size in this TextView.
*/
public float getTextSize() {
@@ -6610,11 +6636,11 @@
int selEnd = getSelectionEnd();
if (!mFrozenWithFocus || (selStart < 0 || selEnd < 0)) {
+ // If a tap was used to give focus to that view, move cursor at tap position.
// Has to be done before onTakeFocus, which can be overloaded.
- if (mLastTouchOffset >= 0) {
- // Can happen when a TextView is displayed after its content has been deleted.
- mLastTouchOffset = Math.min(mLastTouchOffset, mText.length());
- Selection.setSelection((Spannable) mText, mLastTouchOffset);
+ final int lastTapPosition = getLastTapPosition();
+ if (lastTapPosition >= 0) {
+ Selection.setSelection((Spannable) mText, lastTapPosition);
}
if (mMovement != null) {
@@ -6678,7 +6704,9 @@
terminateSelectionActionMode();
}
- mLastTouchOffset = -1;
+ if (mSelectionModifierCursorController != null) {
+ ((SelectionModifierCursorController) mSelectionModifierCursorController).resetTouchOffsets();
+ }
}
startStopMarquee(focused);
@@ -6690,6 +6718,24 @@
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
+ private int getLastTapPosition() {
+ if (mSelectionModifierCursorController != null) {
+ int lastTapPosition = ((SelectionModifierCursorController)
+ mSelectionModifierCursorController).getMinTouchOffset();
+ if (lastTapPosition >= 0) {
+ // Safety check, should not be possible.
+ if (lastTapPosition > mText.length()) {
+ Log.e(LOG_TAG, "Invalid tap focus position (" + lastTapPosition + " vs "
+ + mText.length() + ")");
+ lastTapPosition = mText.length();
+ }
+ return lastTapPosition;
+ }
+ }
+
+ return -1;
+ }
+
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
@@ -6712,10 +6758,7 @@
if (mInputContentType != null) {
mInputContentType.enterDown = false;
}
- hideInsertionPointCursorController();
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.hide();
- }
+ hideControllers();
}
startStopMarquee(hasWindowFocus);
@@ -6725,10 +6768,7 @@
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility != VISIBLE) {
- hideInsertionPointCursorController();
- if (mSelectionModifierCursorController != null) {
- mSelectionModifierCursorController.hide();
- }
+ hideControllers();
}
}
@@ -6781,7 +6821,7 @@
// Tapping outside stops selection mode, if any
stopSelectionActionMode();
- if (mInsertionPointCursorController != null) {
+ if (mInsertionPointCursorController != null && mText.length() > 0) {
mInsertionPointCursorController.show();
}
}
@@ -7321,7 +7361,7 @@
int minOffset, maxOffset;
- if (mDPadCenterIsDown || mEnterKeyIsDown) {
+ if (mContextMenuTriggeredByKey) {
minOffset = getSelectionStart();
maxOffset = getSelectionEnd();
} else {
@@ -7391,6 +7431,14 @@
protected void onCreateContextMenu(ContextMenu menu) {
super.onCreateContextMenu(menu);
boolean added = false;
+ mContextMenuTriggeredByKey = mDPadCenterIsDown || mEnterKeyIsDown;
+ // Problem with context menu on long press: the menu appears while the key in down and when
+ // the key is released, the view does not receive the key_up event. This ensures that the
+ // state is reset whenever the context menu action is displayed.
+ // mContextMenuTriggeredByKey saved that state so that it is available in
+ // onTextContextMenuItem. We cannot simply clear these flags in onTextContextMenuItem since
+ // it may not be called (if the user/ discards the context menu with the back key).
+ mDPadCenterIsDown = mEnterKeyIsDown = false;
MenuHandler handler = new MenuHandler();
@@ -8023,8 +8071,7 @@
final float newPosX = rawX - mTouchToWindowOffsetX + mHotspotX;
final float newPosY = rawY - mTouchToWindowOffsetY + mHotspotY + mTouchOffsetY;
- mController.updatePosition(this, (int) Math.round(newPosX),
- (int) Math.round(newPosY));
+ mController.updatePosition(this, Math.round(newPosX), Math.round(newPosY));
break;
}
@@ -8149,6 +8196,7 @@
SelectionModifierCursorController() {
mStartHandle = new HandleView(this, HandleView.LEFT);
mEndHandle = new HandleView(this, HandleView.RIGHT);
+ resetTouchOffsets();
}
public void show() {
@@ -8231,14 +8279,16 @@
}
public boolean onTouchEvent(MotionEvent event) {
- if (isFocused() && isTextEditable()) {
+ // This is done even when the View does not have focus, so that long presses can start
+ // selection and tap can move cursor from this tap position.
+ if (isTextEditable()) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
final int x = (int) event.getX();
final int y = (int) event.getY();
// Remember finger down position, to be able to start selection from there
- mMinTouchOffset = mMaxTouchOffset = mLastTouchOffset = getOffset(x, y);
+ mMinTouchOffset = mMaxTouchOffset = getOffset(x, y);
break;
@@ -8278,6 +8328,10 @@
return mMaxTouchOffset;
}
+ public void resetTouchOffsets() {
+ mMinTouchOffset = mMaxTouchOffset = -1;
+ }
+
/**
* @return true iff this controller is currently used to move the selection start.
*/
@@ -8298,9 +8352,15 @@
}
}
+ private void hideSelectionModifierCursorController() {
+ if (mSelectionModifierCursorController != null) {
+ mSelectionModifierCursorController.hide();
+ }
+ }
+
private void hideControllers() {
hideInsertionPointCursorController();
- stopSelectionActionMode();
+ hideSelectionModifierCursorController();
}
private int getOffsetForHorizontal(int line, int x) {
@@ -8396,11 +8456,11 @@
private CursorController mInsertionPointCursorController;
private CursorController mSelectionModifierCursorController;
private ActionMode mSelectionActionMode;
- private int mLastTouchOffset = -1;
// These are needed to desambiguate a long click. If the long click comes from ones of these, we
// select from the current cursor position. Otherwise, select from long pressed position.
private boolean mDPadCenterIsDown = false;
private boolean mEnterKeyIsDown = false;
+ private boolean mContextMenuTriggeredByKey = false;
// Created once and shared by different CursorController helper methods.
// Only one cursor controller is active at any time which prevent race conditions.
private static Rect sCursorControllerTempRect = new Rect();
@@ -8415,6 +8475,7 @@
private float mSpacingMult = 1;
private float mSpacingAdd = 0;
+ private int mLineHeight = 0;
private static final int LINES = 1;
private static final int EMS = LINES;
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index df957ac..29ca49a 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -30,6 +30,8 @@
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
/**
* A toast is a view containing a quick little message for the user. The toast class
@@ -281,6 +283,21 @@
tv.setText(s);
}
+ private void trySendAccessibilityEvent() {
+ AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
+ if (!accessibilityManager.isEnabled()) {
+ return;
+ }
+ // treat toasts as notifications since they are used to
+ // announce a transient piece of information to the user
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
+ event.setClassName(getClass().getName());
+ event.setPackageName(mContext.getPackageName());
+ mView.dispatchPopulateAccessibilityEvent(event);
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
+
// =======================================================================================
// All the gunk below is the interaction with the Notification Service, which handles
// the proper ordering of these system-wide.
@@ -371,6 +388,7 @@
}
if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
mWM.addView(mView, mParams);
+ trySendAccessibilityEvent();
}
}
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index 8104ece..d6f5db1 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -69,7 +69,8 @@
private boolean mActionDone;
private Context mContext;
private PowerManager mPowerManager;
- private PowerManager.WakeLock mWakeLock;
+ private PowerManager.WakeLock mCpuWakeLock;
+ private PowerManager.WakeLock mScreenWakeLock;
private Handler mHandler;
private ShutdownThread() {
@@ -187,20 +188,36 @@
pd.show();
- // start the thread that initiates shutdown
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- sInstance.mWakeLock = null;
+
+ // make sure we never fall asleep again
+ sInstance.mCpuWakeLock = null;
+ try {
+ sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
+ sInstance.mCpuWakeLock.setReferenceCounted(false);
+ sInstance.mCpuWakeLock.acquire();
+ } catch (SecurityException e) {
+ Log.w(TAG, "No permission to acquire wake lock", e);
+ sInstance.mCpuWakeLock = null;
+ }
+
+ // also make sure the screen stays on for better user experience
+ sInstance.mScreenWakeLock = null;
if (sInstance.mPowerManager.isScreenOn()) {
try {
- sInstance.mWakeLock = sInstance.mPowerManager.newWakeLock(
- PowerManager.FULL_WAKE_LOCK, "Shutdown");
- sInstance.mWakeLock.acquire();
+ sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
+ PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
+ sInstance.mScreenWakeLock.setReferenceCounted(false);
+ sInstance.mScreenWakeLock.acquire();
} catch (SecurityException e) {
Log.w(TAG, "No permission to acquire wake lock", e);
- sInstance.mWakeLock = null;
+ sInstance.mScreenWakeLock = null;
}
}
+
+ // start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
sInstance.start();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8ea02aa..fd8b454 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -74,6 +74,9 @@
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
+ // No, really, THIS is the maximum number of items we will record in the history.
+ private static final int MAX_MAX_HISTORY_ITEMS = 3000;
+
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
// in to one common name.
@@ -1177,15 +1180,20 @@
mBtHeadset = headset;
}
+ int mChangedStates = 0;
+
void addHistoryRecordLocked(long curTime) {
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
// If the current time is basically the same as the last time,
- // just collapse into one record.
+ // and no states have since the last recorded entry changed and
+ // are now resetting back to their original value, then just collapse
+ // into one record.
if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
- && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+500)) {
+ && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+2000)
+ && ((mHistoryEnd.states^mHistoryCur.states)&mChangedStates) == 0) {
// If the current is the same as the one before, then we no
// longer need the entry.
if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
@@ -1196,20 +1204,29 @@
mHistoryEnd = mHistoryLastEnd;
mHistoryLastEnd = null;
} else {
+ mChangedStates |= mHistoryEnd.states^mHistoryCur.states;
mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, mHistoryCur);
}
return;
}
- if (mNumHistoryItems == MAX_HISTORY_ITEMS) {
+ mChangedStates = 0;
+
+ if (mNumHistoryItems == MAX_HISTORY_ITEMS
+ || mNumHistoryItems == MAX_MAX_HISTORY_ITEMS) {
addHistoryRecordLocked(curTime, HistoryItem.CMD_OVERFLOW);
}
if (mNumHistoryItems >= MAX_HISTORY_ITEMS) {
// Once we've reached the maximum number of items, we only
+ // record changes to the battery level and the most interesting states.
+ // Once we've reached the maximum maximum number of items, we only
// record changes to the battery level.
if (mHistoryEnd != null && mHistoryEnd.batteryLevel
- == mHistoryCur.batteryLevel) {
+ == mHistoryCur.batteryLevel &&
+ (mNumHistoryItems >= MAX_MAX_HISTORY_ITEMS
+ || ((mHistoryEnd.states^mHistoryCur.states)
+ & HistoryItem.MOST_INTERESTING_STATES) == 0)) {
return;
}
}
@@ -4458,10 +4475,13 @@
}
public void commitPendingDataToDisk() {
- Parcel next;
+ final Parcel next;
synchronized (this) {
next = mPendingWrite;
mPendingWrite = null;
+ if (next == null) {
+ return;
+ }
mWriteLock.lock();
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index af0438c6..f97bfb4 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -43,7 +43,7 @@
}
public ActionMenuItemView(Context context, AttributeSet attrs) {
- this(context, attrs, com.android.internal.R.attr.actionButtonStyle);
+ super(context, attrs);
}
public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) {
@@ -113,6 +113,10 @@
mImageButton.setVisibility(GONE);
}
}
+
+ public boolean hasText() {
+ return mTextButton.getVisibility() != GONE;
+ }
public void setShortcut(boolean showShortcut, char shortcutKey) {
// Action buttons don't show text for shortcut keys.
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 20939ab..3b34b7e 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -19,12 +19,15 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
+import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
import java.util.ArrayList;
@@ -33,15 +36,22 @@
*/
public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView {
private static final String TAG = "ActionMenuView";
+
+ // TODO Theme/style this.
+ private static final int DIVIDER_PADDING = 12; // dips
private MenuBuilder mMenu;
- private int mItemPadding;
- private int mItemMargin;
private int mMaxItems;
private boolean mReserveOverflow;
private OverflowMenuButton mOverflowButton;
private MenuPopupHelper mOverflowPopup;
+
+ private float mButtonPaddingLeft;
+ private float mButtonPaddingRight;
+ private float mDividerPadding;
+
+ private Drawable mDivider;
private Runnable mShowOverflow = new Runnable() {
public void run() {
@@ -56,20 +66,34 @@
public ActionMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
- TypedArray a = context.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.Theme);
- mItemPadding = a.getDimensionPixelOffset(
- com.android.internal.R.styleable.Theme_actionButtonPadding, 0);
- mItemMargin = mItemPadding / 2;
- a.recycle();
+ final Resources res = getResources();
// Measure for initial configuration
- mMaxItems = measureMaxActionButtons();
+ mMaxItems = getMaxActionButtons();
// TODO There has to be a better way to indicate that we don't have a hard menu key.
- final int screen = getResources().getConfiguration().screenLayout;
+ final int screen = res.getConfiguration().screenLayout;
mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_XLARGE;
+
+ TypedArray a = context.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
+ final int buttonStyle = a.getResourceId(
+ com.android.internal.R.styleable.Theme_actionButtonStyle, 0);
+ final int groupStyle = a.getResourceId(
+ com.android.internal.R.styleable.Theme_buttonGroupStyle, 0);
+ a.recycle();
+
+ a = context.obtainStyledAttributes(buttonStyle, com.android.internal.R.styleable.View);
+ mButtonPaddingLeft = a.getDimension(com.android.internal.R.styleable.View_paddingLeft, 0);
+ mButtonPaddingRight = a.getDimension(com.android.internal.R.styleable.View_paddingRight, 0);
+ a.recycle();
+
+ a = context.obtainStyledAttributes(groupStyle,
+ com.android.internal.R.styleable.ButtonGroup);
+ mDivider = a.getDrawable(com.android.internal.R.styleable.ButtonGroup_divider);
+ a.recycle();
+
+ mDividerPadding = DIVIDER_PADDING * res.getDisplayMetrics().density;
}
@Override
@@ -77,7 +101,7 @@
final int screen = newConfig.screenLayout;
mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_XLARGE;
- mMaxItems = measureMaxActionButtons();
+ mMaxItems = getMaxActionButtons();
if (mMenu != null) {
mMenu.setMaxActionItems(mMaxItems);
updateChildren(false);
@@ -89,13 +113,8 @@
}
}
- private int measureMaxActionButtons() {
- final Resources res = getResources();
- final int size = res.getDimensionPixelSize(com.android.internal.R.dimen.action_icon_size);
- final int spaceAvailable = res.getDisplayMetrics().widthPixels / 2;
- final int itemSpace = size + mItemPadding;
-
- return spaceAvailable / (itemSpace > 0 ? itemSpace : 1);
+ private int getMaxActionButtons() {
+ return getResources().getInteger(com.android.internal.R.integer.max_action_buttons);
}
public boolean isOverflowReserved() {
@@ -105,24 +124,11 @@
public void setOverflowReserved(boolean reserveOverflow) {
mReserveOverflow = reserveOverflow;
}
-
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
- if (p instanceof LayoutParams) {
- LayoutParams lp = (LayoutParams) p;
- return lp.leftMargin == mItemMargin && lp.rightMargin == mItemMargin &&
- lp.gravity == Gravity.CENTER_VERTICAL &&
- lp.width == LayoutParams.WRAP_CONTENT && lp.height == LayoutParams.WRAP_CONTENT;
- }
- return false;
- }
@Override
protected LayoutParams generateDefaultLayoutParams() {
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
- params.leftMargin = mItemMargin;
- params.rightMargin = mItemMargin;
params.gravity = Gravity.CENTER_VERTICAL;
return params;
}
@@ -131,10 +137,6 @@
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return generateDefaultLayoutParams();
}
-
- public int getItemMargin() {
- return mItemMargin;
- }
public boolean invokeItem(MenuItemImpl item) {
return mMenu.performItemAction(item, 0);
@@ -157,14 +159,19 @@
final ArrayList<MenuItemImpl> itemsToShow = mMenu.getActionItems(reserveOverflow);
final int itemCount = itemsToShow.size();
+ boolean needsDivider = false;
for (int i = 0; i < itemCount; i++) {
+ if (needsDivider) {
+ addView(makeDividerView(), makeDividerLayoutParams());
+ }
final MenuItemImpl itemData = itemsToShow.get(i);
final View actionView = itemData.getActionView();
if (actionView != null) {
- addView(actionView);
+ addView(actionView, makeActionViewLayoutParams());
} else {
- addItemView((ActionMenuItemView) itemData.getItemView(
- MenuBuilder.TYPE_ACTION_BUTTON, this));
+ needsDivider = addItemView(i == 0 || !needsDivider,
+ (ActionMenuItemView) itemData.getItemView(
+ MenuBuilder.TYPE_ACTION_BUTTON, this));
}
}
@@ -212,16 +219,43 @@
return false;
}
- private void addItemView(ActionMenuItemView view) {
+ private boolean addItemView(boolean needsDivider, ActionMenuItemView view) {
view.setItemInvoker(this);
+ boolean hasText = view.hasText();
+
+ if (hasText && needsDivider) {
+ addView(makeDividerView(), makeDividerLayoutParams());
+ }
addView(view);
+ return hasText;
+ }
+
+ private ImageView makeDividerView() {
+ ImageView result = new ImageView(mContext);
+ result.setImageDrawable(mDivider);
+ result.setScaleType(ImageView.ScaleType.FIT_XY);
+ return result;
+ }
+
+ private LayoutParams makeDividerLayoutParams() {
+ LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT);
+ params.topMargin = (int) mDividerPadding;
+ params.bottomMargin = (int) mDividerPadding;
+ return params;
+ }
+
+ private LayoutParams makeActionViewLayoutParams() {
+ LayoutParams params = generateDefaultLayoutParams();
+ params.leftMargin = (int) mButtonPaddingLeft;
+ params.rightMargin = (int) mButtonPaddingRight;
+ return params;
}
private class OverflowMenuButton extends ImageButton {
public OverflowMenuButton(Context context) {
super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
- final Resources res = context.getResources();
setClickable(true);
setFocusable(true);
setVisibility(VISIBLE);
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index eaeb67f..d0faea6 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -236,14 +236,14 @@
int themeResForType = THEME_RES_FOR_TYPE[mMenuType];
switch (themeResForType) {
case THEME_APPLICATION:
- wrappedContext = new ContextThemeWrapper(mContext, themeResForType);
+ wrappedContext = mContext;
break;
case THEME_ALERT_DIALOG:
wrappedContext = new ContextThemeWrapper(mContext,
getAlertDialogTheme(mContext));
break;
default:
- wrappedContext = mContext;
+ wrappedContext = new ContextThemeWrapper(mContext, themeResForType);
break;
}
mInflater = (LayoutInflater) wrappedContext
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index b5e57c2..a824e92 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -36,8 +36,6 @@
* @hide
*/
public class ActionBarContextView extends ViewGroup {
- private int mItemPadding;
- private int mActionSpacing;
private int mContentHeight;
private CharSequence mTitle;
@@ -64,8 +62,6 @@
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionMode, defStyle, 0);
- mItemPadding = a.getDimensionPixelOffset(
- com.android.internal.R.styleable.ActionMode_itemPadding, 0);
setBackgroundDrawable(a.getDrawable(
com.android.internal.R.styleable.ActionMode_background));
mTitleStyleRes = a.getResourceId(
@@ -219,7 +215,6 @@
}
final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
- final int itemMargin = mItemPadding;
int maxHeight = mContentHeight > 0 ?
mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
@@ -230,13 +225,11 @@
final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
if (mCloseButton != null) {
- availableWidth = measureChildView(mCloseButton, availableWidth,
- childSpecHeight, itemMargin);
+ availableWidth = measureChildView(mCloseButton, availableWidth, childSpecHeight, 0);
}
if (mTitleLayout != null && mCustomView == null) {
- availableWidth = measureChildView(mTitleLayout, availableWidth,
- childSpecHeight, itemMargin);
+ availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
}
final int childCount = getChildCount();
@@ -246,7 +239,7 @@
continue;
}
- availableWidth = measureChildView(child, availableWidth, childSpecHeight, itemMargin);
+ availableWidth = measureChildView(child, availableWidth, childSpecHeight, 0);
}
if (mCustomView != null) {
@@ -284,25 +277,23 @@
int x = getPaddingLeft();
final int y = getPaddingTop();
final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
- final int itemMargin = mItemPadding;
if (mCloseButton != null && mCloseButton.getVisibility() != GONE) {
x += positionChild(mCloseButton, x, y, contentHeight);
}
if (mTitleLayout != null && mCustomView == null) {
- x += positionChild(mTitleLayout, x, y, contentHeight) + itemMargin;
+ x += positionChild(mTitleLayout, x, y, contentHeight);
}
if (mCustomView != null) {
- x += positionChild(mCustomView, x, y, contentHeight) + itemMargin;
+ x += positionChild(mCustomView, x, y, contentHeight);
}
x = r - l - getPaddingRight();
if (mMenuView != null) {
- x -= positionChildInverse(mMenuView, x + mActionSpacing, y, contentHeight)
- - mActionSpacing;
+ x -= positionChildInverse(mMenuView, x, y, contentHeight);
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 308a709..054423c 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -53,12 +53,7 @@
*/
public class ActionBarView extends ViewGroup {
private static final String TAG = "ActionBarView";
-
- // TODO: This must be defined in the default theme
- private static final int CONTENT_PADDING_DIP = 3;
- private static final int CONTENT_SPACING_DIP = 6;
- private static final int CONTENT_ACTION_SPACING_DIP = 12;
-
+
/**
* Display options applied by default
*/
@@ -75,12 +70,11 @@
private int mNavigationMode;
private int mDisplayOptions;
- private int mSpacing;
- private int mActionSpacing;
private CharSequence mTitle;
private CharSequence mSubtitle;
private Drawable mIcon;
private Drawable mLogo;
+ private Drawable mDivider;
private ImageView mIconView;
private ImageView mLogoView;
@@ -126,8 +120,6 @@
public ActionBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
-
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar);
final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0);
@@ -171,12 +163,10 @@
}
mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
+
+ mDivider = a.getDrawable(R.styleable.ActionBar_divider);
a.recycle();
-
- // TODO: Set this in the theme
- mSpacing = (int) (CONTENT_SPACING_DIP * metrics.density + 0.5f);
- mActionSpacing = (int) (CONTENT_ACTION_SPACING_DIP * metrics.density + 0.5f);
if (mLogo != null || mIcon != null || mTitle != null) {
mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
@@ -210,7 +200,6 @@
}
final ActionMenuView menuView = (ActionMenuView) builder.getMenuView(
MenuBuilder.TYPE_ACTION_BUTTON, null);
- mActionSpacing = menuView.getItemMargin();
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
menuView.setLayoutParams(layoutParams);
@@ -452,7 +441,8 @@
if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) {
if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
- mLogoView = new ImageView(getContext());
+ mLogoView = new ImageView(getContext(), null,
+ com.android.internal.R.attr.actionButtonStyle);
mLogoView.setAdjustViewBounds(true);
mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT));
@@ -462,7 +452,8 @@
mLogoView.setOnClickListener(mHomeClickListener);
addView(mLogoView);
} else if (mIcon != null) {
- mIconView = new ImageView(getContext());
+ mIconView = new ImageView(getContext(), null,
+ com.android.internal.R.attr.actionButtonStyle);
mIconView.setAdjustViewBounds(true);
mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT));
@@ -558,10 +549,10 @@
final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
if (mLogoView != null && mLogoView.getVisibility() != GONE) {
- availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, mSpacing);
+ availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, 0);
}
if (mIconView != null && mIconView.getVisibility() != GONE) {
- availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, mSpacing);
+ availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, 0);
}
if (mMenuView != null) {
@@ -572,7 +563,7 @@
switch (mNavigationMode) {
case ActionBar.NAVIGATION_MODE_STANDARD:
if (mTitleLayout != null) {
- measureChildView(mTitleLayout, availableWidth, childSpecHeight, mSpacing);
+ measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
}
break;
case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
@@ -652,39 +643,38 @@
final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
if (mLogoView != null && mLogoView.getVisibility() != GONE) {
- x += positionChild(mLogoView, x, y, contentHeight) + mSpacing;
+ x += positionChild(mLogoView, x, y, contentHeight);
}
if (mIconView != null && mIconView.getVisibility() != GONE) {
- x += positionChild(mIconView, x, y, contentHeight) + mSpacing;
+ x += positionChild(mIconView, x, y, contentHeight);
}
switch (mNavigationMode) {
case ActionBar.NAVIGATION_MODE_STANDARD:
if (mTitleLayout != null) {
- x += positionChild(mTitleLayout, x, y, contentHeight) + mSpacing;
+ x += positionChild(mTitleLayout, x, y, contentHeight);
}
break;
case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
if (mSpinner != null) {
- x += positionChild(mSpinner, x, y, contentHeight) + mSpacing;
+ x += positionChild(mSpinner, x, y, contentHeight);
}
break;
case ActionBar.NAVIGATION_MODE_CUSTOM:
if (mCustomNavView != null) {
- x += positionChild(mCustomNavView, x, y, contentHeight) + mSpacing;
+ x += positionChild(mCustomNavView, x, y, contentHeight);
}
break;
case ActionBar.NAVIGATION_MODE_TABS:
if (mTabScrollView != null) {
- x += positionChild(mTabScrollView, x, y, contentHeight) + mSpacing;
+ x += positionChild(mTabScrollView, x, y, contentHeight);
}
}
x = r - l - getPaddingRight();
if (mMenuView != null) {
- x -= positionChildInverse(mMenuView, x + mActionSpacing, y, contentHeight)
- - mActionSpacing;
+ x -= positionChildInverse(mMenuView, x, y, contentHeight);
}
}
diff --git a/core/res/res/drawable-hdpi/ic_bullet_key_permission.png b/core/res/res/drawable-hdpi/ic_bullet_key_permission.png
index 98d95dc..b6b840a 100644
--- a/core/res/res/drawable-hdpi/ic_bullet_key_permission.png
+++ b/core/res/res/drawable-hdpi/ic_bullet_key_permission.png
Binary files differ
diff --git a/core/res/res/drawable/list_selector_holo_dark.xml b/core/res/res/drawable/list_selector_holo_dark.xml
index ee59904..a046831 100644
--- a/core/res/res/drawable/list_selector_holo_dark.xml
+++ b/core/res/res/drawable/list_selector_holo_dark.xml
@@ -24,6 +24,6 @@
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
<item android:state_focused="true" android:drawable="@drawable/list_selector_focused_holo_dark" />
- <item android:drawable="@drawable/list_selector_focused_holo_dark" />
+ <item android:drawable="@color/transparent" />
</selector>
diff --git a/core/res/res/drawable/list_selector_holo_light.xml b/core/res/res/drawable/list_selector_holo_light.xml
index 2dc39f6..e0a3bec 100644
--- a/core/res/res/drawable/list_selector_holo_light.xml
+++ b/core/res/res/drawable/list_selector_holo_light.xml
@@ -24,6 +24,6 @@
<item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
<item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/list_selector_background_transition" />
<item android:state_focused="true" android:drawable="@drawable/list_selector_focused_holo_light" />
- <item android:drawable="@drawable/list_selector_focused_holo_light" />
+ <item android:drawable="@color/transparent" />
</selector>
diff --git a/core/res/res/layout-xlarge/alert_dialog_holo.xml b/core/res/res/layout-xlarge/alert_dialog_holo.xml
new file mode 100644
index 0000000..a01e03a
--- /dev/null
+++ b/core/res/res/layout-xlarge/alert_dialog_holo.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<com.android.internal.widget.WeightedLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingTop="9dip"
+ android:paddingBottom="3dip"
+ android:paddingLeft="3dip"
+ android:paddingRight="1dip"
+ android:majorWeightMin="0.45"
+ android:minorWeightMin="0.72"
+ android:majorWeightMax="0.45"
+ android:minorWeightMax="0.72">
+
+ <LinearLayout android:id="@+id/topPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="48dip"
+ android:orientation="vertical">
+ <LinearLayout android:id="@+id/title_template"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:layout_marginTop="8dip"
+ android:layout_marginBottom="8dip"
+ android:layout_marginLeft="32dip"
+ android:layout_marginRight="32dip">
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="16dip"
+ android:src="@null" />
+ <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+ style="?android:attr/textAppearanceMedium"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+ <ImageView android:id="@+id/titleDivider"
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:visibility="gone"
+ android:scaleType="fitXY"
+ android:gravity="fill_horizontal"
+ android:src="@android:drawable/divider_horizontal_dark" />
+ <!-- If the client uses a customTitle, it will be added here. -->
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/contentPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <ScrollView android:id="@+id/scrollView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="32dip"
+ android:paddingBottom="32dip"
+ android:paddingLeft="32dip"
+ android:paddingRight="32dip">
+ <TextView android:id="@+id/message"
+ style="?android:attr/textAppearanceMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </ScrollView>
+ </LinearLayout>
+
+ <FrameLayout android:id="@+id/customPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+ <FrameLayout android:id="@+android:id/custom"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dip"
+ android:paddingBottom="8dip" />
+ </FrameLayout>
+
+ <LinearLayout android:id="@+id/buttonPanel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="54dip"
+ android:orientation="vertical" >
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingTop="4dip"
+ android:paddingLeft="2dip"
+ android:paddingRight="2dip"
+ android:measureWithLargestChild="true">
+ <LinearLayout android:id="@+id/leftSpacer"
+ android:layout_weight="0.25"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone" />
+ <Button android:id="@+id/button1"
+ android:layout_width="0dip"
+ android:layout_gravity="left"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button3"
+ android:layout_width="0dip"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:layout_height="wrap_content" />
+ <Button android:id="@+id/button2"
+ android:layout_width="0dip"
+ android:layout_gravity="right"
+ android:layout_weight="1"
+ android:maxLines="2"
+ android:layout_height="wrap_content" />
+ <LinearLayout android:id="@+id/rightSpacer"
+ android:layout_width="0dip"
+ android:layout_weight="0.25"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone" />
+ </LinearLayout>
+ </LinearLayout>
+</com.android.internal.widget.WeightedLinearLayout>
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
index 0d3cce5..e7b8a25 100644
--- a/core/res/res/layout/action_menu_item_layout.xml
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -20,10 +20,13 @@
<ImageButton android:id="@+id/imageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="center"
android:visibility="gone"
style="?attr/actionButtonStyle" />
<Button android:id="@+id/textButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:visibility="gone" />
+ android:layout_gravity="center"
+ android:visibility="gone"
+ android:background="?attr/listChoiceBackgroundIndicator" />
</com.android.internal.view.menu.ActionMenuItemView>
diff --git a/core/res/res/layout/app_perms_summary.xml b/core/res/res/layout/app_perms_summary.xml
index 7160743..bdbbfcb 100755
--- a/core/res/res/layout/app_perms_summary.xml
+++ b/core/res/res/layout/app_perms_summary.xml
@@ -65,21 +65,23 @@
android:layout_marginLeft="16dip"
android:duplicateParentState="true">
- <ImageView
- android:id="@+id/show_more_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
<TextView
android:id="@+id/show_more_text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:duplicateParentState="true"
- android:layout_alignTop="@id/show_more_icon"
+ android:layout_alignTop="@+id/show_more_icon"
android:layout_gravity="center_vertical"
- android:paddingLeft="6dip"
- android:layout_width="match_parent"
+ android:paddingLeft="36dip"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content" />
+ <ImageView
+ android:id="@id/show_more_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="12dip" />
+
</LinearLayout>
<View
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d9f0039..461fb5f 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -483,8 +483,6 @@
<!-- Action bar styles -->
<!-- =================== -->
<eat-comment />
- <!-- Default amount of padding to use between action buttons. -->
- <attr name="actionButtonPadding" format="dimension" />
<!-- Default style for tabs within an action bar -->
<attr name="actionBarTabStyle" format="reference" />
<attr name="actionBarTabBarStyle" format="reference" />
@@ -555,6 +553,12 @@
<attr name="dialogTheme" format="reference" />
<!-- Theme to use for alert dialogs spawned from this theme. -->
<attr name="alertDialogTheme" format="reference" />
+
+ <!-- Drawable to use for vertical dividers. -->
+ <attr name="dividerVertical" format="reference" />
+
+ <!-- Style for button groups -->
+ <attr name="buttonGroupStyle" format="reference" />
</declare-styleable>
<!-- **************************************************************** -->
@@ -600,6 +604,9 @@
<!-- Color of link text (URLs). -->
<attr name="textColorLink" format="reference|color" />
+ <!-- Height of a line of text. -->
+ <attr name="textLineHeight" format="dimension" />
+
<!-- Where to ellipsize text. -->
<attr name="ellipsize">
<enum name="none" value="0" />
@@ -2076,6 +2083,8 @@
<attr name="textColorHint" />
<!-- Color of the links. -->
<attr name="textColorLink" />
+ <!-- Height of a single line of text. -->
+ <attr name="textLineHeight" />
</declare-styleable>
<declare-styleable name="TextSwitcher">
</declare-styleable>
@@ -2312,6 +2321,9 @@
<!-- Reference to a drawable that will be used to display a text selection
anchor for positioning the cursor within text. -->
<attr name="textSelectHandle" />
+
+ <!-- Height of a line of text. -->
+ <attr name="textLineHeight" />
</declare-styleable>
<!-- An <code>input-extras</code> is a container for extra data to supply to
an input method. Contains
@@ -4177,8 +4189,6 @@
<attr name="background" />
<!-- Specifies a fixed height for the action mode bar. -->
<attr name="height" />
- <!-- Specifies a padding to use between elements on the bar. -->
- <attr name="itemPadding" format="dimension" />
</declare-styleable>
<declare-styleable name="SearchView">
@@ -4186,4 +4196,11 @@
use and expanded when clicked. -->
<attr name="iconifiedByDefault" format="boolean"/>
</declare-styleable>
+
+ <declare-styleable name="ButtonGroup">
+ <!-- Drawable to use as a vertical divider between buttons. -->
+ <attr name="divider" />
+ <!-- Drawable to use as a background for buttons added to this group. -->
+ <attr name="buttonBackground" format="reference" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 171bb45..6ec8017 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -25,9 +25,10 @@
<!-- The standard size (both width and height) of an application icon that
will be displayed in the app launcher and elsewhere. -->
<dimen name="app_icon_size">48dip</dimen>
- <!-- The standard size (both width and height) of an action icon that will
- be displayed in application action bars. -->
- <dimen name="action_icon_size">48dip</dimen>
+ <!-- The maximum number of action buttons that should be permitted within
+ an action bar/action mode. This will be used to determine how many
+ showAsAction="ifRoom" items can fit. "always" items can override this. -->
+ <integer name="max_action_buttons">5</integer>
<dimen name="toast_y_offset">64dip</dimen>
<!-- Height of the status bar -->
<dimen name="status_bar_height">25dip</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ae25715..1080187 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1316,7 +1316,6 @@
<public type="attr" name="actionDropDownStyle" />
<public type="attr" name="actionButtonStyle" />
<public type="attr" name="showAsAction" />
- <public type="attr" name="actionButtonPadding" />
<public type="attr" name="previewImage" />
<public type="attr" name="actionModeBackground" />
<public type="attr" name="actionModeCloseDrawable" />
@@ -1348,7 +1347,6 @@
<public type="attr" name="actionBarTabBarStyle" />
<public type="attr" name="actionBarTabTextStyle" />
<public type="attr" name="actionOverflowButtonStyle" />
- <public type="attr" name="itemPadding" />
<public type="attr" name="actionModeCloseButtonStyle" />
<public type="attr" name="titleTextStyle" />
<public type="attr" name="subtitleTextStyle" />
@@ -1368,6 +1366,9 @@
<public type="attr" name="loopViews" />
<public type="attr" name="dialogTheme" />
<public type="attr" name="alertDialogTheme" />
+ <public type="attr" name="textLineHeight" />
+ <public type="attr" name="dividerVertical" />
+ <public type="attr" name="buttonGroupStyle" />
<public type="anim" name="animator_fade_in" />
<public type="anim" name="animator_fade_out" />
@@ -1409,6 +1410,9 @@
<public type="style" name="Theme.Holo.NoActionBar.Fullscreen" />
<public type="style" name="Theme.Light.Holo.NoActionBar" />
<public type="style" name="Theme.Light.Holo.NoActionBar.Fullscreen" />
+ <public type="style" name="Theme.Holo.Light" />
+ <public type="style" name="Theme.Holo.Dialog" />
+ <public type="style" name="Theme.Holo.Light.Dialog" />
<public type="style" name="Widget.ListPopupWindow" />
<public type="style" name="Widget.PopupMenu" />
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 8f7ace9..fdc8c47 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -905,9 +905,9 @@
<item name="android:displayOptions">useLogo</item>
<item name="android:divider">@android:drawable/action_bar_divider</item>
<item name="android:height">?android:attr/actionBarSize</item>
- <item name="android:paddingLeft">3dip</item>
+ <item name="android:paddingLeft">0dip</item>
<item name="android:paddingTop">0dip</item>
- <item name="android:paddingRight">3dip</item>
+ <item name="android:paddingRight">0dip</item>
<item name="android:paddingBottom">0dip</item>
<item name="android:titleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Title</item>
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Widget.ActionBar.Subtitle</item>
@@ -916,7 +916,6 @@
<style name="Widget.ActionMode">
<item name="android:background">?android:attr/actionModeBackground</item>
<item name="android:height">?android:attr/actionBarSize</item>
- <item name="android:itemPadding">?android:attr/actionButtonPadding</item>
<item name="android:titleTextStyle">@android:style/TextAppearance.Widget.ActionMode.Title</item>
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Widget.ActionMode.Subtitle</item>
</style>
@@ -939,6 +938,8 @@
<style name="Widget.ActionButton">
<item name="android:background">@null</item>
+ <item name="android:paddingLeft">16dip</item>
+ <item name="android:paddingRight">16dip</item>
</style>
<style name="Widget.ActionButton.Overflow">
@@ -992,6 +993,11 @@
<item name="android:textColor">@android:color/secondary_text_light</item>
</style>
+ <style name="Widget.ButtonGroup">
+ <item name="divider">?android:attr/dividerVertical</item>
+ <item name="buttonBackground">?android:attr/listChoiceBackgroundIndicator</item>
+ </style>
+
<!-- Begin Holo theme styles -->
<!-- Text Styles -->
@@ -1009,6 +1015,7 @@
</style>
<style name="TextAppearance.Holo.Medium" parent="TextAppearance.Medium">
+ <item name="android:textLineHeight">24dip</item>
</style>
<style name="TextAppearance.Holo.Small" parent="TextAppearance.Small">
@@ -1073,16 +1080,16 @@
</style>
<style name="TextAppearance.Holo.Widget.DropDownHint">
- <item name="android:textColor">?textColorPrimaryInverse</item>
+ <item name="android:textColor">?textColorPrimary</item>
<item name="android:textSize">14sp</item>
</style>
<style name="TextAppearance.Holo.Widget.DropDownItem">
- <item name="android:textColor">@android:color/primary_text_light_disable_only</item>
+ <item name="android:textColor">?textColorPrimaryDisableOnly</item>
</style>
<style name="TextAppearance.Holo.Widget.TextView.SpinnerItem">
- <item name="android:textColor">@android:color/primary_text_light_disable_only</item>
+ <item name="android:textColor">?textColorPrimaryDisableOnly</item>
</style>
<style name="TextAppearance.Holo.Widget.EditText">
@@ -1142,13 +1149,13 @@
<item name="android:textColorLink">?textColorLinkInverse</item>
</style>
- <style name="TextAppearance.Holo.Light.Large" parent="TextAppearance.Large">
+ <style name="TextAppearance.Holo.Light.Large" parent="TextAppearance.Holo.Large">
</style>
- <style name="TextAppearance.Holo.Light.Medium" parent="TextAppearance.Medium">
+ <style name="TextAppearance.Holo.Light.Medium" parent="TextAppearance.Holo.Medium">
</style>
- <style name="TextAppearance.Holo.Light.Small" parent="TextAppearance.Small">
+ <style name="TextAppearance.Holo.Light.Small" parent="TextAppearance.Holo.Small">
</style>
<style name="TextAppearance.Holo.Light.Large.Inverse">
@@ -1260,6 +1267,9 @@
<item name="android:paddingRight">24dip</item>
</style>
+ <style name="Widget.Holo.ButtonGroup" parent="Widget.ButtonGroup">
+ </style>
+
<style name="Widget.Holo.TextView" parent="Widget.TextView">
</style>
@@ -1393,12 +1403,14 @@
</style>
<style name="Widget.Holo.DropDownItem" parent="Widget.DropDownItem">
+ <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.DropDownItem</item>
</style>
<style name="Widget.Holo.DropDownItem.Spinner">
</style>
<style name="Widget.Holo.TextView.SpinnerItem" parent="Widget.TextView.SpinnerItem">
+ <item name="android:textAppearance">@style/TextAppearance.Holo.Widget.TextView.SpinnerItem</item>
</style>
<style name="Widget.Holo.KeyboardView" parent="Widget.KeyboardView">
@@ -1433,13 +1445,27 @@
<style name="Widget.Holo.PopupMenu" parent="Widget.Holo.ListPopupWindow">
</style>
- <style name="Widget.Holo.ActionButton" parent="Widget.ActionButton">
+ <style name="Widget.Holo.ButtonBar">
+ <item name="android:divider">?android:attr/dividerVertical</item>
</style>
- <style name="Widget.Holo.ActionButton.Overflow" parent="Widget.ActionButton.Overflow">
+ <style name="Widget.Holo.ButtonBar.Button">
+ </style>
+
+ <style name="Widget.Holo.ActionButton" parent="Widget.ActionButton">
+ <item name="android:paddingLeft">16dip</item>
+ <item name="android:paddingRight">16dip</item>
+ <item name="android:minWidth">64dip</item>
+ <item name="android:minHeight">56dip</item>
+ </style>
+
+ <style name="Widget.Holo.ActionButton.Overflow">
<item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_dark</item>
</style>
+ <style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button">
+ </style>
+
<style name="Widget.Holo.ActionBarView_TabView" parent="Widget.ActionBarView_TabView">
</style>
@@ -1458,7 +1484,7 @@
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionMode.Subtitle</item>
</style>
- <style name="Widget.Holo.ActionButton.CloseMode" parent="Widget.ActionButton.CloseMode">
+ <style name="Widget.Holo.ActionButton.CloseMode">
<item name="android:src">@drawable/cab_ic_close_holo</item>
</style>
@@ -1466,6 +1492,7 @@
<item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Title</item>
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
<item name="android:background">@null</item>
+ <item name="android:divider">?android:attr/dividerVertical</item>
</style>
<!-- Light widget styles -->
@@ -1493,6 +1520,9 @@
<item name="android:paddingRight">24dip</item>
</style>
+ <style name="Widget.Holo.Light.ButtonGroup" parent="Widget.Holo.ButtonGroup">
+ </style>
+
<style name="Widget.Holo.Light.TextView" parent="Widget.TextView">
</style>
@@ -1619,13 +1649,13 @@
<style name="Widget.Holo.Light.WebView" parent="Widget.WebView">
</style>
- <style name="Widget.Holo.Light.DropDownItem" parent="Widget.DropDownItem">
+ <style name="Widget.Holo.Light.DropDownItem" parent="Widget.Holo.DropDownItem">
</style>
<style name="Widget.Holo.Light.DropDownItem.Spinner">
</style>
- <style name="Widget.Holo.Light.TextView.SpinnerItem" parent="Widget.TextView.SpinnerItem">
+ <style name="Widget.Holo.Light.TextView.SpinnerItem" parent="Widget.Holo.TextView.SpinnerItem">
</style>
<style name="Widget.Holo.Light.KeyboardView" parent="Widget.KeyboardView">
@@ -1660,10 +1690,10 @@
<style name="Widget.Holo.Light.PopupMenu" parent="Widget.Holo.Light.ListPopupWindow">
</style>
- <style name="Widget.Holo.Light.ActionButton" parent="Widget.ActionButton">
+ <style name="Widget.Holo.Light.ActionButton" parent="Widget.Holo.ActionButton">
</style>
- <style name="Widget.Holo.Light.ActionButton.Overflow" parent="Widget.ActionButton.Overflow">
+ <style name="Widget.Holo.Light.ActionButton.Overflow">
<item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
</style>
@@ -1676,16 +1706,16 @@
<style name="Widget.Holo.Light.ActionBarView_TabText" parent="Widget.ActionBarView_TabText">
</style>
- <style name="Widget.Holo.Light.ActionMode" parent="Widget.ActionMode">
+ <style name="Widget.Holo.Light.ActionMode" parent="Widget.Holo.ActionMode">
<item name="android:background">@android:drawable/cab_holo_light</item>
<item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionMode.Title</item>
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionMode.Subtitle</item>
</style>
- <style name="Widget.Holo.Light.ActionButton.CloseMode" parent="Widget.ActionButton.CloseMode">
+ <style name="Widget.Holo.Light.ActionButton.CloseMode">
</style>
- <style name="Widget.Holo.Light.ActionBar" parent="Widget.ActionBar">
+ <style name="Widget.Holo.Light.ActionBar" parent="Widget.Holo.ActionBar">
<item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Title</item>
<item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
<item name="android:background">@null</item>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 8daa802..5948a5b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -234,7 +234,6 @@
<item name="actionDropDownStyle">@android:style/Widget.Spinner.DropDown</item>
<item name="actionButtonStyle">@android:style/Widget.ActionButton</item>
<item name="actionOverflowButtonStyle">@android:style/Widget.ActionButton.Overflow</item>
- <item name="actionButtonPadding">12dip</item>
<item name="actionModeBackground">@android:drawable/action_bar_context_background</item>
<item name="actionModeCloseDrawable">@android:drawable/ic_menu_close_clear_cancel</item>
<item name="actionBarTabStyle">@style/Widget.ActionBarView_TabView</item>
@@ -243,7 +242,10 @@
<item name="actionModeStyle">@style/Widget.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.ActionButton.CloseMode</item>
<item name="actionBarStyle">@android:style/Widget.ActionBar</item>
- <item name="actionBarSize">50dip</item>
+ <item name="actionBarSize">56dip</item>
+
+ <item name="dividerVertical">@drawable/divider_vertical_dark</item>
+ <item name="buttonGroupStyle">@android:style/Widget.ButtonGroup</item>
</style>
<!-- Variant of the default (dark) theme with no title bar -->
@@ -826,7 +828,6 @@
<item name="actionDropDownStyle">@android:style/Widget.Holo.Spinner.DropDown</item>
<item name="actionButtonStyle">@android:style/Widget.Holo.ActionButton</item>
<item name="actionOverflowButtonStyle">@android:style/Widget.Holo.ActionButton.Overflow</item>
- <item name="actionButtonPadding">12dip</item>
<item name="actionModeBackground">@android:drawable/cab_holo_dark</item>
<item name="actionModeCloseDrawable">@android:drawable/cab_ic_close_holo</item>
<item name="actionBarTabStyle">@style/Widget.Holo.ActionBarView_TabView</item>
@@ -835,8 +836,10 @@
<item name="actionModeStyle">@style/Widget.Holo.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Holo.ActionButton.CloseMode</item>
<item name="actionBarStyle">@android:style/Widget.Holo.ActionBar</item>
- <item name="actionBarSize">50dip</item>
+ <item name="actionBarSize">56dip</item>
+ <item name="dividerVertical">@drawable/divider_vertical_holo_dark</item>
+ <item name="buttonGroupStyle">@android:style/Widget.Holo.ButtonGroup</item>
</style>
<!-- New Honeycomb holographic theme. Light version. The widgets in the
@@ -1052,7 +1055,6 @@
<item name="actionDropDownStyle">@android:style/Widget.Holo.Spinner.DropDown</item>
<item name="actionButtonStyle">@android:style/Widget.Holo.ActionButton</item>
<item name="actionOverflowButtonStyle">@android:style/Widget.Holo.ActionButton.Overflow</item>
- <item name="actionButtonPadding">12dip</item>
<item name="actionModeBackground">@android:drawable/cab_holo_light</item>
<item name="actionModeCloseDrawable">@android:drawable/cab_ic_close_holo</item>
<item name="actionBarTabStyle">@style/Widget.Holo.ActionBarView_TabView</item>
@@ -1061,8 +1063,10 @@
<item name="actionModeStyle">@style/Widget.Holo.Light.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Holo.ActionButton.CloseMode</item>
<item name="actionBarStyle">@android:style/Widget.Holo.ActionBar</item>
- <item name="actionBarSize">50dip</item>
+ <item name="actionBarSize">56dip</item>
+ <item name="dividerVertical">@drawable/divider_vertical_holo_light</item>
+ <item name="buttonGroupStyle">@android:style/Widget.Holo.Light.ButtonGroup</item>
</style>
<!-- Development legacy name; if you're using this, switch. -->
diff --git a/docs/html/guide/developing/debug-tasks.jd b/docs/html/guide/developing/debug-tasks.jd
index 500ef58..f0bf84c 100644
--- a/docs/html/guide/developing/debug-tasks.jd
+++ b/docs/html/guide/developing/debug-tasks.jd
@@ -40,10 +40,13 @@
your application, which can help you profile the performance of your application.</dd>
<dt><strong><a href="{@docRoot}guide/developing/tools/ddms.html#logcat">logcat</a></strong></dt>
<dd>Dumps a log of system
- messages. The messages include a stack trace when the emulator throws an error,
+ messages. The messages include a stack trace when the device throws an error,
as well as {@link android.util.Log} messages you've written from your application. To run
- logcat, execute <code>adb logcat</code> or, from DDMS, select <strong>Device > Run
- logcat</strong>.
+ logcat, execute <code>adb logcat</code> from your Android SDK {@code tools/} directory or,
+from DDMS, select <strong>Device > Run
+ logcat</strong>. When using the <a href="{@docRoot}sdk/eclipse-adt.html">ADT plugin for
+Eclipse</a>, you can also view logcat messages by opening the Logcat view, available from
+<strong>Window > Show View > Other > Android > Logcat</strong>.
<p>{@link android.util.Log} is a logging
class you can use to print out messages to the logcat. You can read messages
in real time if you run logcat on DDMS (covered next). Common logging methods include:
@@ -148,72 +151,7 @@
<h2 id="DebuggingWebPages">Debugging Web Pages</h2>
-<p>If you're developing a web application for Android devices, you can debug your JavaScript in the
-Android Browser using the Console APIs, which will output messages to logcat. If you're familiar
-debugging web pages with Firefox's FireBug or WebKit's Web Inspector, then you're probably familiar
-with the Console APIs. The Android Browser (and the {@link android.webkit.WebChromeClient}) supports
-most of the same APIs.</p>
-
-<p>When you call a function from the Console APIs (in the DOM's {@code window.console} object),
-you will see the output in logcat as a warning. For example, if your web page
-executes the following JavaScript:</p>
-<pre class="no-pretty-print">
-console.log("Hello World");
-</pre>
-<p>Then the logcat output from the Android Browser will look like this:</p>
-<pre class="no-pretty-print">
-W/browser ( 202): Console: Hello World http://www.example.com/hello.html :82
-</pre>
-
-<p>All Console messages from the Android Browser are tagged with the name "browser" on Android
-platforms running API Level 7 or higher. On platforms running API Level 6 or lower, Browser
-messages are tagged with the name "WebCore". The Android Browser also formats console messages
-with the log message
-preceded by "Console:" and then followed by the address and line number where the
-message occurred. (The format for the address and line number will appear different from the example
-above on platforms running API Level 6 or lower.)</p>
-
-<p>The Android Browser (and {@link android.webkit.WebChromeClient}) does not implement all of the
-Console APIs provided by Firefox or other WebKit-based browsers. Primarily, you need to depend
-on the basic text logging functions:</p>
-<ul>
- <li>{@code console.log(String)}</li>
- <li>{@code console.info(String)}</li>
- <li>{@code console.warn(String)}</li>
- <li>{@code console.error(String)}</li>
-</ul>
-<p>Although the Android Browser may not fully implement other Console functions, they will not raise
-run-time errors, but may not behave the same as they do on other desktop browsers.</p>
-
-<p>If you've implemented a custom {@link android.webkit.WebView} in your application, then in order
-to receive messages that are sent through the Console APIs, you must provide a {@link
-android.webkit.WebChromeClient} that implements the {@link
-android.webkit.WebChromeClient#onConsoleMessage(String,int,String) onConsoleMessage()} callback
-method. For example, assuming that the {@code myWebView} field references the {@link
-android.webkit.WebView} in your application, you can log debug messages like this:</p>
-<pre>
-myWebView.setWebChromeClient(new WebChromeClient() {
- public void onConsoleMessage(String message, int lineNumber, String sourceID) {
- Log.d("MyApplication", message + " -- From line " + lineNumber + " of " + sourceID);
- }
-});
-</pre>
-<p>The {@link android.webkit.WebChromeClient#onConsoleMessage(String,int,String)
-onConsoleMessage()} method will be called each time one of the Console methods is called from
-within your {@link android.webkit.WebView}.</p>
-<p>When the "Hello World" log is executed through your {@link android.webkit.WebView}, it will
-now look like this:</p>
-<pre class="no-pretty-print">
-D/MyApplication ( 430): Hello World -- From line 82 of http://www.example.com/hello.html
-</pre>
-
-<p class="note"><strong>Note:</strong> The {@link
-android.webkit.WebChromeClient#onConsoleMessage(String,int,String) onConsoleMessage()} callback
-method was added with API Level 7. If you are using a custom {@link
-android.webkit.WebView} on a platform running API Level 6 or lower, then your Console messages will
-automatically be sent to logcat with the "WebCore" logging tag.</p>
-
-
+<p>See the <a href="{@docRoot}guide/webapps/debugging.html">Debugging Web Apps</a> document.</p>
<h2 id="toptips">Top Debugging Tips</h2>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index da8c927..76d5f4f 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -110,7 +110,7 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/topics/resources/index.html">
<span class="en">Application Resources</span>
- </a> <span class="new">new!</span></div>
+ </a></div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/resources/providing-resources.html">
<span class="en">Providing Resources</span>
@@ -120,14 +120,14 @@
</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/resources/runtime-changes.html">
<span class="en">Handling Runtime Changes</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/topics/resources/localization.html">
<span class="en">Localization</span>
</a></li>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/topics/resources/available-resources.html">
<span class="en">Resource Types</span>
- </a> <span class="new">new!</span></div>
+ </a></div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/resources/animation-resource.html">Animation</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/resources/color-list-resource.html">Color State List</a></li>
@@ -147,11 +147,11 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html">
<span class="en">Data Storage</span>
- </a> <span class="new">new!</span></div>
+ </a></div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
<span class="en">Data Backup</span>
- </a> <span class="new">new!</span>
+ </a>
</li>
</ul>
</li>
@@ -227,7 +227,7 @@
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/location/obtaining-user-location.html">
<span class="en">Obtaining User Location</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
</ul>
</li>
<!--<li class="toggle-list">
@@ -246,7 +246,7 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot?>guide/topics/search/index.html">
<span class="en">Search</span>
- </a> <span class="new">new!</span></div>
+ </a></div>
<ul>
<li><a href="<?cs var:toroot?>guide/topics/search/search-dialog.html">Using the Android Search Dialog</a></li>
<li><a href="<?cs var:toroot?>guide/topics/search/adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
@@ -282,6 +282,10 @@
<span class="en">Device Administration</span></a>
<span class="new">new!</span>
</li>
+ <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
+ <span class="en">Device Administration</span>
+ </a> <span class="new">new!</span><!-- 10/8/10 -->
+ </li>
</ul>
</li>
@@ -328,18 +332,18 @@
<div>
<a href="<?cs var:toroot ?>guide/developing/testing/index.html">
<span class="en">Testing</span>
- </a> <span class="new">new!</span>
+ </a>
</div>
<ul>
<li>
<a href="<?cs var:toroot ?>guide/developing/testing/testing_eclipse.html">
<span class="en">Testing in Eclipse, with ADT</span>
- </a> <span class="new">new!</span>
+ </a>
</li>
<li>
<a href="<?cs var:toroot ?>guide/developing/testing/testing_otheride.html">
<span class="en">Testing in Other IDEs</span>
- </a> <span class="new">new!</span>
+ </a>
</li>
</ul>
</li>
@@ -354,8 +358,7 @@
<!--<li><a href="<?cs var:toroot ?>guide/developing/tools/adt.html">ADT Plugin</a></li>-->
<li><a href="<?cs var:toroot ?>guide/developing/tools/aidl.html">aidl</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/avd.html">AVDs</a></li>
- <li><a href="<?cs var:toroot ?>guide/developing/tools/bmgr.html">bmgr</a>
- <span class="new">new!</span></li>
+ <li><a href="<?cs var:toroot ?>guide/developing/tools/bmgr.html">bmgr</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/ddms.html">ddms</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/othertools.html#dx">dx</a></li>
<li><a href="<?cs var:toroot ?>guide/developing/tools/draw9patch.html">Draw 9-Patch</a></li>
@@ -435,7 +438,7 @@
<ul>
<li><a href="<?cs var:toroot ?>guide/practices/compatibility.html">
<span class="en">Compatibility</span>
- </a><span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/practices/screens_support.html">
<span class="en">Supporting Multiple Screens</span>
</a></li>
@@ -473,6 +476,25 @@
</li>
<li>
+ <h2><span class="en">Web Applications</span>
+ </h2>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/webapps/targetting.html">
+ <span class="en">Targetting Android Devices</span>
+ </a> <span class="new">new!</span><!-- 10/8/10 --></li>
+ <li><a href="<?cs var:toroot ?>guide/webapps/webview.html">
+ <span class="en">Building Web Apps in WebView</span>
+ </a> <span class="new">new!</span><!-- 10/8/10 --></li>
+ <li><a href="<?cs var:toroot ?>guide/webapps/debugging.html">
+ <span class="en">Debugging Web Apps</span>
+ </a> <span class="new">new!</span><!-- 10/8/10 --></li>
+ <li><a href="<?cs var:toroot ?>guide/webapps/best-practices.html">
+ <span class="en">Best Practices for Web Apps</span>
+ </a> <span class="new">new!</span><!-- 10/8/10 --></li>
+ </ul>
+ </li>
+
+ <li>
<h2><span class="en">Appendix</span>
<span class="de" style="display:none">Anhang</span>
<span class="es" style="display:none">Apéndice</span>
@@ -488,10 +510,10 @@
</a></li>
<li><a href="<?cs var:toroot ?>guide/appendix/market-filters.html">
<span class="en">Market Filters</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/appendix/install-location.html">
<span class="en">App Install Location</span>
- </a> <span class="new">new!</span></li>
+ </a></li>
<li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
<span class="en">Supported Media Formats</span>
</a></li>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index 4d9a14f..fda716a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -1,24 +1,33 @@
-page.title=Android Device Administration API
+page.title=Device Administration
@jd:body
+
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#overview">Device Administration API Overview</a>
<ol>
+ <li><a href="#how">How does it work?</a></li>
<li><a href="#policies">Policies</a></li>
</ol>
</li>
- <li><a href="#how">How Does It Work?</a></li>
<li><a href="#sample">Sample Application</a></li>
<li><a href="#developing">Developing a Device Administration Application</a>
<ol>
- <li><a href="#manifest">Creating the Manifest</a></li>
- <li><a href="#code">Implementing the Code</a>
- </li>
+ <li><a href="#manifest">Creating the manifest</a></li>
+ <li><a href="#code">Implementing the code</a></li>
</ol>
+ </li>
+
+ </ol>
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.app.admin.DeviceAdminReceiver}</li>
+ <li>{@link android.app.admin.DevicePolicyManager}</li>
+ <li>{@link android.app.admin.DeviceAdminInfo}</li>
</ol>
- </div>
+</div>
</div>
<p>Android 2.2 introduces support for enterprise applications by offering the
@@ -37,7 +46,10 @@
solutions for Android-powered devices. It discusses the various features
provided by the Device Administration API to provide stronger security for
employee devices that are powered by Android.</p>
+
+
<h2 id="overview">Device Administration API Overview</h2>
+
<p>Here are examples of the types of applications that might use the Device Administration API:</p>
<ul>
<li>Email clients.</li>
@@ -45,14 +57,14 @@
<li>Device management services and applications.</li>
</ul>
-<h3 id="how">How Does it Work?</h3>
+<h3 id="how">How does it work?</h3>
<p>You use the Device Administration API to write device admin applications that users
install on their devices. The device admin application enforces the desired
policies. Here's how it works:</p> <ul>
<li>A system administrator writes a device admin application that enforces
remote/local device security policies. These policies could be hard-coded into
the app, or the application could dynamically fetch policies from a third-party
-server. </li>
+server. </li>
<li>The application is installed on users' devices. Android does
not currently have an automated provisioning solution. Some of the ways a sysadmin might
distribute the application to users are as follows:
@@ -68,7 +80,7 @@
<li>The system prompts the user to enable the device admin application. How
and when this happens depends on how the application is implemented.</li>
<li>Once users enable the device admin application, they are subject to
-its policies. Complying with those policies typically confers benefits, such as
+its policies. Complying with those policies typically confers benefits, such as
access to sensitive systems and data.</li>
</ul>
<p>If users do not enable the device admin app, it remains on the device, but in an inactive state. Users will not be subject to its policies, and they will conversely not get any of the application's benefits—for example, they may not be able to sync data.</p>
@@ -88,12 +100,14 @@
<p>To uninstall an existing device admin application, users need to
first unregister the application as an administrator. </p>
-<h3 id ="policies">Policies</h3>
+
+<h3 id="policies">Policies</h3>
+
<p>In an enterprise setting, it's often the case that employee devices must
adhere to a strict set of policies that govern the use of the device. The
Device Administration API supports the policies listed in Table 1.
Note that the Device Administration API currently only supports passwords for screen
-lock:</p>
+lock:</p>
<p class="table-caption"><strong>Table 1.</strong> Policies supported by the Device Administration API.</p>
<table border="1">
<tr>
@@ -109,7 +123,7 @@
<td>Set the required number of characters for the password. For example, you
can require PIN or passwords to have at least six characters. </td> </tr>
<tr>
- <td>Alphanumeric password required</td>
+ <td>Alphanumeric password required</td>
<td>Requires that passwords have a
combination of letters and numbers. They may include symbolic characters.
</td>
@@ -128,7 +142,9 @@
need to enter their PIN or passwords again before they can use their devices and
access data. The value can be between 1 and 60 minutes.</td> </tr>
</table>
-<h4>Other Features</h4>
+
+<h4>Other features</h4>
+
<p>In addition to supporting the policies listed in the above table, the Device
Administration API lets you do the following:</p> <ul>
<li>Prompt user to set a new password.</li>
@@ -138,6 +154,7 @@
<h2 id="sample">Sample Application</h2>
+
<p>The examples used in this document are based on the <a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/
android/apis/app/DeviceAdminSample.html">Device Administration API
@@ -147,7 +164,7 @@
Getting the Samples</a>. Here is the <a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/
android/apis/app/DeviceAdminSample.html">complete code</a> for
-the sample. </p>
+the sample. </p>
<p>The
sample application offers a demo of device admin features. It presents users
with a user interface that lets them enable the device admin application. Once
@@ -169,13 +186,17 @@
<img src="{@docRoot}images/admin/device-admin-app.png"/>
<p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Sample Application</p>
+
+
<h2 id="developing">Developing a Device Administration Application</h2>
<p>System administrators can use the Device Administration API to write an application
that enforces remote/local device security policy enforcement. This section
summarizes the steps involved in creating a device administration
application.</p>
-<h3 id="manifest">Creating the Manifest</h3>
+
+<h3 id="manifest">Creating the manifest</h3>
+
<p>To use the Device Administration API, the application's
manifest must include the following:</p>
<ul>
@@ -207,7 +228,7 @@
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver></pre>
-
+
<p>Note that:</p>
<ul>
<li>The activity in the sample application is an {@link android.app.Activity}
@@ -218,7 +239,7 @@
an inner class; it just is in this example.</li>
<li>The following attributes refer to string resources that for the sample application reside in
-<code>ApiDemos/res/values/strings.xml</code>. For more information about resources, see
+<code>ApiDemos/res/values/strings.xml</code>. For more information about resources, see
<a
href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.
<ul>
@@ -234,8 +255,8 @@
a label.</li>
</ul>
-
-<li><code>android:permission="android.permission.BIND_DEVICE_ADMIN"
+
+<li><code>android:permission="android.permission.BIND_DEVICE_ADMIN"
</code> is a permission that a {@link android.app.admin.DeviceAdminReceiver} subclass must
have, to ensure that only the system can interact with the receiver (no application can be granted this permission). This
prevents other applications from abusing your device admin app.</li>
@@ -273,11 +294,15 @@
include all of the policies, just the ones that are relevant for your app.
</p>
For more discussion of the manifest file, see the <a
-href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android Developers Guide</a>.
-<h2 id="code">Implementing the Code</h2>
+href="{@docRoot}guide/topics/manifest/manifest-intro.html">Android Developers Guide</a>.
+
+
+
+<h3 id="code">Implementing the code</h3>
+
<p>The Device Administration API includes the following classes:</p>
<dl>
- <dt>{@link android.app.admin.DeviceAdminReceiver}</dt>
+ <dt>{@link android.app.admin.DeviceAdminReceiver}</dt>
<dd>Base class for implementing a device administration component. This class provides
a convenience for interpreting the raw intent actions that are sent by the
system. Your Device Administration application must include a
@@ -287,7 +312,7 @@
this class must have published a {@link android.app.admin.DeviceAdminReceiver} that the user
has currently enabled. The {@link android.app.admin.DevicePolicyManager} manages policies for
one or more {@link android.app.admin.DeviceAdminReceiver} instances</dd>
- <dt>{@link android.app.admin.DeviceAdminInfo}</dt>
+ <dt>{@link android.app.admin.DeviceAdminInfo}</dt>
<dd>This class is used to specify metadata
for a device administrator component.</dd>
</dl>
@@ -295,6 +320,7 @@
The rest of this section describes how you use the {@link
android.app.admin.DeviceAdminReceiver} and
{@link android.app.admin.DevicePolicyManager} APIs to write a device admin application.</p>
+
<h4 id="receiver">Subclassing DeviceAdminReceiver</h4>
<p>To create a device admin application, you must subclass
{@link android.app.admin.DeviceAdminReceiver}. The {@link android.app.admin.DeviceAdminReceiver} class
@@ -305,7 +331,7 @@
events. For example:</p>
<pre>public class DeviceAdminSample extends DeviceAdminReceiver {
-...
+...
@Override
public void onEnabled(Context context, Intent intent) {
showToast(context, "Sample Device Admin: enabled");
@@ -331,30 +357,32 @@
}
...
}</pre>
-<h4 id="enabling">Enabling the Application</h4>
+
+<h4 id="enabling">Enabling the application</h4>
<p>One of the major events a device admin application has to handle is the user
enabling the application. The user must explicitly enable the application for
the policies to be enforced. If the user chooses not to enable the application
it will still be present on the device, but its policies will not be enforced, and the user will not
get any of the application's benefits.</p>
<p>The process of enabling the application begins when the user performs an
-action that triggers the {@link android.app.admin.DevicePolicyManager#ACTION_ADD_DEVICE_ADMIN}
+action that triggers the {@link android.app.admin.DevicePolicyManager#ACTION_ADD_DEVICE_ADMIN}
intent. In the
sample application, this happens when the user clicks the <strong>Enable
Admin</strong> button. </p>
<p>When the user clicks the <strong>Enable Admin</strong> button, the display
-changes to prompt the user to enable the device admin application, as shown in <strong>Figure 2</strong>.</p>
+changes to prompt the user to enable the device admin application, as shown in figure
+2.</p>
<img src="{@docRoot}images/admin/device-admin-activate-prompt.png"/>
<p class="img-caption"><strong>Figure 2.</strong> Sample Application: Activating the Application</p>
<p>Below is the code that gets executed when the user clicks the <strong>Enable
-Admin</strong> button shown in <strong>Figure 1</strong>. </p>
+Admin</strong> button shown in figure 1. </p>
<pre> private OnClickListener mEnableListener = new OnClickListener() {
public void onClick(View v) {
// Launch the activity to have the user enable our admin.
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
- intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+ intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
mDeviceAdminSample);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"Additional text explaining why this needs to be added.");
@@ -379,10 +407,10 @@
}</pre>
<p>The line
-<code>intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+<code>intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
mDeviceAdminSample)</code> states that <code>mDeviceAdminSample</code> (which is
a {@link android.app.admin.DeviceAdminReceiver} component) is the target policy.
-This line invokes the user interface shown in <strong>Figure 2</strong>, which guides users through
+This line invokes the user interface shown in figure 2, which guides users through
adding the device administrator to the system (or allows them to reject it).</p>
<p>When the application needs to perform an operation that is contingent on the
@@ -402,14 +430,16 @@
// do something else
}
</pre>
-<h3 id="admin_ops">Managing Policies</h3>
+
+<h3 id="admin_ops">Managing policies</h3>
<p>{@link android.app.admin.DevicePolicyManager} is a public class for managing policies
enforced on a device. {@link android.app.admin.DevicePolicyManager} manages policies for one
or more {@link android.app.admin.DeviceAdminReceiver} instances. </p>
<p>You get a handle to the {@link android.app.admin.DevicePolicyManager} as follows: </p>
-<pre>DevicePolicyManager mDPM =
-(DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);<br
-/></pre>
+<pre>
+DevicePolicyManager mDPM =
+ (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
+</pre>
<p>This section describes how to use {@link android.app.admin.DevicePolicyManager} to perform
administrative tasks:</p>
<ul>
@@ -417,26 +447,29 @@
<li><a href="#lock">Set device lock</a></li>
<li><a href="#wipe">Perform data wipe</a></li>
</ul>
+
<h4 id="pwd">Set password policies</h4>
<p>{@link android.app.admin.DevicePolicyManager} includes APIs for setting and enforcing the
device password policy. In the Device Administration API, the password only applies to
screen lock. This section describes common password-related tasks.</p>
+
<h5>Set a password for the device</h5>
<p>This code displays a user interface prompting the user to set a password:</p>
<pre>Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
startActivity(intent);
</pre>
+
<h5>Set the password quality</h5>
<p>The password quality can be one of the following {@link android.app.admin.DevicePolicyManager} constants: </p>
<dl>
- <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHABETIC}</dt><dd>The user must enter a
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHABETIC}</dt><dd>The user must enter a
password containing at least alphabetic (or other symbol) characters.</dd>
- <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHANUMERIC}</dt><dd>The user must enter a
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_ALPHANUMERIC}</dt><dd>The user must enter a
password containing at least <em>both</em> numeric <em>and</em> alphabetic (or
other symbol) characters.</dd>
<dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_NUMERIC}</dt><dd>The user must enter a password
containing at least numeric characters.</dd>
- <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
+ <dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_SOMETHING}</dt><dd>The policy requires some kind
of password, but doesn't care what it is.</dd>
<dt>{@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}</dt><dd>
The policy has no requirements for the password. </dd>
@@ -448,6 +481,7 @@
...
mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
</pre>
+
<h5>Set the minimum password length</h5>
<p>You can specify that a password must be at least the specified minimum
length. For example:</p>
@@ -457,19 +491,21 @@
...
mDPM.setPasswordMinimumLength(mDeviceAdminSample, pwLength);
</pre>
+
<h5>Set maximum failed password attempts</h5>
<p>You can set the maximum number of allowed failed password attempts before the
device is wiped (that is, reset to factory settings). For example:</p>
-<pre>DevicePolicyManager mDPM;
-ComponentName mDeviceAdminSample;
+<pre>DevicePolicyManager mDPM;
+ComponentName mDeviceAdminSample;
int maxFailedPw;
...
mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);</pre>
+
<h4 id="lock">Set device lock</h4>
<p>You can set the maximum period of user inactivity that can occur before the
device locks. For example:</p>
<pre>
-DevicePolicyManager mDPM;
+DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
...
long timeMs = 1000L*Long.parseLong(mTimeout.getText().toString());
@@ -477,9 +513,11 @@
</pre>
<p>You can also programmatically tell the device to lock immediately:</p>
<pre>
-DevicePolicyManager mDPM;
+DevicePolicyManager mDPM;
mDPM.lockNow();</pre>
+
<h4 id="wipe">Perform data wipe</h4>
+
<p>You can use the {@link android.app.admin.DevicePolicyManager} method
{@link android.app.admin.DevicePolicyManager#wipeData wipeData()} to reset the device to factory settings. This is useful
if the device is lost or stolen. Often the decision to wipe the device is the
@@ -488,7 +526,7 @@
wiped after a specific number of failed password attempts.</p>
<p>You wipe data as follows:</p>
<pre>
-DevicePolicyManager mDPM;
+DevicePolicyManager mDPM;
mDPM.wipeData(0);</pre>
<p>The {@link android.app.admin.DevicePolicyManager#wipeData wipeData()} method takes as its parameter a bit mask of
additional options. Currently the value must be 0. </p>
diff --git a/docs/html/guide/webapps/best-practices.jd b/docs/html/guide/webapps/best-practices.jd
new file mode 100644
index 0000000..1bde5bf
--- /dev/null
+++ b/docs/html/guide/webapps/best-practices.jd
@@ -0,0 +1,90 @@
+page.title=Best Practices for Web Apps
+@jd:body
+
+<style>
+.bold li {
+ font-weight:bold;
+}
+.bold li * {
+ font-weight:normal;
+}
+</style>
+
+<p>Developing web pages and web applications for mobile devices presents a different set of
+challenges compared to developing a web page for the typical
+desktop web browser. To help you get started, the following is a list of practices you should
+follow in order to provide the most effective web application for Android and other mobile
+devices.</p>
+
+<ol class="bold">
+
+<li>Redirect mobile devices to a dedicated mobile version of your web site
+ <p>There are several ways you can redirect requests to the mobile version of your web site, using
+server-side redirects. Most often, this is done by "sniffing" the User Agent
+string provided by the web browser. To determine whether to serve a mobile version of your site, you
+should simply look for the "mobile" string in the User Agent, which matches a wide variety of mobile
+devices. If necessary, you can also identify the specific operating system in the User Agent string
+(such as "Android 2.1").</p>
+</li>
+
+
+<li>Use a valid markup DOCTYPE that's appropriate for mobile devices
+ <p>The most common markup language used for mobile web sites is <a
+href="http://www.w3.org/TR/2008/REC-xhtml-basic-20080729/">XHTML Basic</a>. This standard
+ensures specific markup for your web site that works best on mobile devices. For instance, it does
+not allow HTML frames or nested tables, which perform poorly on mobile devices. Along with the
+DOCTYPE, be sure to declare the appropriate character encoding for the document (such as
+UTF-8).</p>
+ <p>For example:</p>
+<pre>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
+ "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
+</pre>
+
+ <p>Also be sure that your web page markup is valid against the declared DOCTYPE. Use a
+validator, such as the one available at
+<a href="http://validator.w3.org/">http://validator.w3.org</a>.</p>
+</li>
+
+
+<li>Use viewport meta data to properly resize your web page
+ <p>In your document {@code <head>}, you should provide meta data that specifies how you
+want the browser's viewport to render your web page. For example, your viewport meta data can
+specify the height and width for the browser's viewport, the initial web page scale and even the
+target screen density.</p>
+ <p>For example:</p>
+<pre>
+<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+</pre>
+ <p>For more information about how to use viewport meta data for Android-powered devices, read <a
+href="{@docRoot}guide/webapps/targetting.html">Targetting Android Devices</a>.</p>
+</li>
+
+
+<li>Avoid multiple file requests
+ <p>Because mobile devices typically have a connection speed far slower than a desktop
+computer, you should make your web pages load as fast as possible. One way to speed it up is to
+avoid loading extra files such as stylesheets and script files in the {@code
+<head>}. Instead, provide your CSS and JavaScript directly in the <head> (or
+at the end of the <body>, for scripts that you don't need until the page is loaded).
+Alternatively, you should optimize the size and speed of your files by compressing them with tools
+like <a href="http://code.google.com/p/minify/">Minify</a>.</p>
+</li>
+
+
+<li>Use a vertical linear layout
+ <p>Avoid the need for the user to scroll left and right while navigating your web
+page. Scrolling up and down is easier for the user and makes your web page simpler.</p>
+</li>
+
+</ol>
+
+<p>For a more thorough guide to creating great mobile web applications, see the W3C's <a
+href="http://www.w3.org/TR/mobile-bp/">Mobile Web Best Practices</a>. For other guidance on
+improving the speed of your web site (for mobile and desktop), see Yahoo!'s guide to <a
+href="http://developer.yahoo.com/performance/index.html#rules">Exceptional Performance</a> and
+Google's speed tutorials in <a href="http://code.google.com/speed/articles/">Let's make the web
+faster</a>.</p>
+
+
diff --git a/docs/html/guide/webapps/debugging.jd b/docs/html/guide/webapps/debugging.jd
new file mode 100644
index 0000000..098e17c
--- /dev/null
+++ b/docs/html/guide/webapps/debugging.jd
@@ -0,0 +1,158 @@
+page.title=Debugging Web Apps
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Quickview</h2>
+<ul>
+ <li>You can debug your web app using console methods in JavaScript</li>
+ <li>If debugging in a custom WebView, you need to implement a callback method to handle debug
+messages</li>
+</ul>
+
+<h2>In this document</h2>
+<ol>
+ <li><a href="#Browser">Using Console APIs in the Android Browser</a></li>
+ <li><a href="#WebView">Using Console APIs in WebView</a></li>
+</ol>
+
+<h2>See also</h2>
+<ol>
+ <li><a href="{@docRoot}guide/developing/debug-tasks.html">Debugging Tasks</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>If you're developing a web application for Android, you can debug your JavaScript
+using the {@code console} JavaScript APIs, which output messages to logcat. If you're familiar with
+debugging web pages with Firebug or Web Inspector, then you're probably familiar
+with using {@code console} (such as {@code console.log()}). Android's WebKit framework supports most
+of the same APIs, so you can receive logs from your web page when debugging in Android's Browser
+or in your own {@link android.webkit.WebView}.</p>
+
+
+
+<h2 id="Browser">Using Console APIs in the Android Browser</h2>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h2>Logcat</h2>
+ <p>Logcat is a tool that dumps a log of system messages. The messages include a stack trace when
+the device throws an error, as well as log messages written from your application and
+those written using JavaScript {@code console} APIs.</p>
+ <p>To run logcat and view messages, execute
+{@code adb logcat} from your Android SDK {@code tools/} directory, or, from DDMS, select
+<strong>Device > Run logcat</strong>. When using the <a href="{@docRoot}sdk/eclipse-adt.html">ADT
+plugin for Eclipse</a>, you can also view logcat messages by opening the Logcat view, available from
+<strong>Window > Show View > Other > Android > Logcat</strong>.</p>
+ <p>See <a href="{@docRoot}guide/developing/debug-tasks.html">Debugging
+Tasks</a> for more information about logcat.</p>
+</div>
+</div>
+
+<p>When you call a {@code console} function (in the DOM's {@code window.console} object),
+the output appears in logcat. For example, if your web page executes the following
+JavaScript:</p>
+<pre>
+console.log("Hello World");
+</pre>
+<p>Then the logcat message looks something like this:</p>
+<pre class="no-pretty-print">
+Console: Hello World http://www.example.com/hello.html :82
+</pre>
+
+<p>The format of the message might appear different depending on which version of Android you're
+using. On Android 2.1 and higher, console messages from the Android Browser
+are tagged with the name "browser". On Android 1.6 and lower, Android Browser
+messages are tagged with the name "WebCore".</p>
+
+<p>Android's WebKit does not implement all of the console APIs available in other desktop browsers.
+You can, however, use the basic text logging functions:</p>
+<ul>
+ <li>{@code console.log(String)}</li>
+ <li>{@code console.info(String)}</li>
+ <li>{@code console.warn(String)}</li>
+ <li>{@code console.error(String)}</li>
+</ul>
+
+<p>Other console functions don't raise errors, but might not behave the same as what you
+expect from other web browsers.</p>
+
+
+
+<h2 id="WebView">Using Console APIs in WebView</h2>
+
+<p>If you've implemented a custom {@link android.webkit.WebView} in your application, all the
+same console APIs are supported when debugging your web page in WebView. On Android
+1.6 and lower, console messages are automatically sent to logcat with the
+"WebCore" logging tag. If you're targetting Android 2.1 (API Level 7) or higher, then you must
+provide a {@link android.webkit.WebChromeClient}
+that implements the {@link android.webkit.WebChromeClient#onConsoleMessage(String,int,String)
+onConsoleMessage()} callback method, in order for console messages to appear in logcat.</p>
+
+<p>Additionally, the {@link
+android.webkit.WebChromeClient#onConsoleMessage(String,int,String)} method introduced in API
+Level 7 has been deprecated in favor of {@link
+android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)} in API Level 8.</p>
+
+<p>Whether you're developing for Android 2.1 (API Level 7) or Android 2.2 (API Level 8 or
+greater), you must implement {@link android.webkit.WebChromeClient} and override the appropriate
+{@link
+android.webkit.WebChromeClient#onConsoleMessage(String,int,String) onConsoleMessage()} callback
+method. Then, apply the {@link android.webkit.WebChromeClient} to your {@link
+android.webkit.WebView} with {@link android.webkit.WebView#setWebChromeClient(WebChromeClient)
+setWebChromeClient()}.
+
+<p>Using API Level 7, this is how your code for {@link
+android.webkit.WebChromeClient#onConsoleMessage(String,int,String)} might look:</p>
+
+<pre>
+WebView myWebView = (WebView) findViewById(R.id.webview);
+myWebView.setWebChromeClient(new WebChromeClient() {
+ public void onConsoleMessage(String message, int lineNumber, String sourceID) {
+ Log.d("MyApplication", message + " -- From line "
+ + lineNumber + " of "
+ + sourceID);
+ }
+});
+</pre>
+
+<p>With API Level 8 or greater, your code for {@link
+android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)} might look like this:</p>
+
+<pre>
+WebView myWebView = (WebView) findViewById(R.id.webview);
+myWebView.setWebChromeClient(new WebChromeClient() {
+ public boolean onConsoleMessage(ConsoleMessage cm) {
+ Log.d("MyApplication", cm.{@link android.webkit.ConsoleMessage#message()} + " -- From line "
+ + cm.{@link android.webkit.ConsoleMessage#lineNumber()} + " of "
+ + cm.{@link android.webkit.ConsoleMessage#sourceId()} );
+ return true;
+ }
+});
+</pre>
+
+<p>The {@link android.webkit.ConsoleMessage} also includes a {@link
+android.webkit.ConsoleMessage.MessageLevel MessageLevel} to indicate the type of console message
+being delivered. You can query the message level with {@link
+android.webkit.ConsoleMessage#messageLevel()} to determine the severity of the message, then
+use the appropriate {@link android.util.Log} method or take other appropriate actions.</p>
+
+<p>Whether you're using {@link
+android.webkit.WebChromeClient#onConsoleMessage(String,int,String)} or {@link
+android.webkit.WebChromeClient#onConsoleMessage(ConsoleMessage)}, when you execute a console method
+in your web page, Android calls the appropriate {@link
+android.webkit.WebChromeClient#onConsoleMessage(String,int,String)
+onConsoleMessage()} method so you can report the error. For example, with the example code above,
+a logcat message is printed that looks like this:</p>
+
+<pre class="no-pretty-print">
+Hello World -- From line 82 of http://www.example.com/hello.html
+</pre>
+
+
+
+
+
+
diff --git a/docs/html/guide/webapps/targetting.jd b/docs/html/guide/webapps/targetting.jd
new file mode 100644
index 0000000..844b9ca
--- /dev/null
+++ b/docs/html/guide/webapps/targetting.jd
@@ -0,0 +1,419 @@
+page.title=Targetting Android Devices
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Quickview</h2>
+<ul>
+ <li>You can target your web page for different screens using viewport metadata, CSS, and
+JavaScript</li>
+ <li>Techniques in this document work for Android 2.0 and greater</li>
+</ul>
+
+<h2>In this document</h2>
+<ol>
+<li><a href="#Metadata">Using Viewport Metadata</a>
+ <ol>
+ <li><a href="#ViewportSize">Defining the viewport size</a></li>
+ <li><a href="#ViewportScale">Defining the viewport scale</a></li>
+ <li><a href="#ViewportDensity">Defining the viewport target density</a></li>
+ </ol>
+</li>
+<li><a href="#DensityCSS">Targetting Device Density with CSS</a></li>
+<li><a href="#DensityJS">Targetting Device Density with JavaScript</a></li>
+</ol>
+
+</div>
+</div>
+
+
+<p>If you're developing a web application for Android or redesigning one for mobile devices, you
+should account for some factors that affect the way the Android Browser renders your web page by
+default. There are two fundamental factors that you should account for:</p>
+
+<dl>
+ <dt>The size of the viewport and scale of the web page</dt>
+ <dd>When the Android Browser loads a web page, the default behavior is to load the
+page in "overview mode," which provides a zoomed-out perspective of the web page. You can override
+this behavior for your web page by defining the default dimensions of the viewport or the initial
+scale of the viewport. You can also control how much the user can zoom in and out of your web
+page, if at all.
+ <p>However, the user can also disable overview mode in the
+Browser settings, so you should not assume that your page will load in overview mode. You
+should instead customize the viewport size and/or scale as appropriate for your page.</p></dd>
+
+ <dt>The device's screen density</dt>
+ <dd>The screen density (the number of pixels per inch) on an Android-powered device affects
+the resolution and size at which a web page is displayed. (There are three screen density
+categories: low, medium, and high.) The Android Browser compensates for variations in the screen
+density by scaling a web page so that all devices display the web page at the same perceivable size
+as a medium-density screen. If graphics are an important element of your web design, you
+should pay close attention to the scaling that occurs on different densities, because image scaling
+can produce artifacts (blurring and pixelation).
+ <p>To provide the best visual representation on all
+screen densities, you should control how scaling occurs by providing viewport metadata about
+your web page's target screen density and providing alternative graphics for different screen
+densities, which you can apply to different screens using CSS or JavaScript.</p></dd>
+</dl>
+
+<p>The rest of this document describes how you can account for these effects, and how to target
+your web page for specific screen configurations.</p>
+
+<p class="note"><strong>Note:</strong> The features described in this document are supported
+by the Android Browser application on Android 2.0 and greater. Third-party web browsers running on
+Android might not support these techniques for controlling the viewport size and targetting
+screen densities.</p>
+
+
+
+<h2 id="Metadata">Using Viewport Metadata</h2>
+
+<p>The viewport is the area in which the Android Browser
+draws a web page. Although the viewport's visible area matches the size of the screen,
+the viewport has its own dimensions that determine the number of pixels available to a web page.
+That is, the number of pixels available to a web page before it exceeds the screen area is
+defined by the dimensions of the viewport,
+not the dimensions of the device screen. For example, although a device screen might have a width of
+480 pixels, the viewport can have a width of 800 pixels, so that a web page designed to be 800
+pixels wide is completely visible on the screen.</p>
+
+<p>You can define properties of the viewport for your web page using the {@code "viewport"}
+property in an HTML {@code <meta>} tag (which must
+be placed in your document {@code <head>}). You can define multiple viewport properties in the
+{@code <meta>} tag's {@code content} attribute. For example, you can define the height and
+width of the viewport, the initial scale of the page, and the target screen density.
+Each viewport property in the {@code content} attribute must be separated by a comma.</p>
+
+<p>For example, the following snippet from an HTML document specifies that the viewport width
+should exactly match the device screen width and that the ability to zoom should be disabled:</p>
+
+<pre>
+<head>
+ <title>Example</title>
+ <meta name="viewport" content="width=device-width, user-scalable=no" />
+</head>
+</pre>
+
+<p>That's an example of just two viewport properties. The following syntax shows all of the
+supported viewport properties and the general types of values accepted by each one:</p>
+
+<pre>
+<meta name="viewport"
+ content="
+ <b>height</b> = [<em>pixel_value</em> | device-height] ,
+ <b>width</b> = [<em>pixel_value</em> | device-width ] ,
+ <b>initial-scale</b> = <em>float_value</em> ,
+ <b>minimum-scale</b> = <em>float_value</em> ,
+ <b>maximum-scale</b> = <em>float_value</em> ,
+ <b>user-scalable</b> = [yes | no] ,
+ <b>target-densitydpi</b> = [<em>dpi_value</em> | device-dpi |
+ high-dpi | medium-dpi | low-dpi]
+ " />
+</pre>
+
+<p>The following sections discuss how to use each of these viewport properties and exactly what the
+accepted values are.</p>
+
+<div class="figure" style="width:300px">
+ <img src="{@docRoot}images/webapps/compare-default.png" alt="" height="300" />
+ <p class="img-caption"><strong>Figure 1.</strong> A web page with no viewport metadata and an
+image that's 320 pixels wide (the viewport is 800 pixels wide, by default).</p>
+</div>
+
+
+<div class="figure" style="width:300px">
+ <img src="{@docRoot}images/webapps/compare-width400.png" alt="" height="300" />
+ <p class="img-caption"><strong>Figure 2.</strong> A web page with viewport {@code width=400}
+(the image in the web page is 320 pixels wide).</p>
+</div>
+
+
+<h3 id="ViewportSize">Defining the viewport size</h3>
+
+<p>Viewport's {@code height} and {@code width} properties allow you to specify the size of the
+viewport (the number of pixels available to the web page before it goes off screen). By default, the
+Android Browser's minimum viewport width is 800 pixels, so if your web
+page specifies its size to be 320 pixels wide, then your page renders smaller than the visible
+screen (even if the physical screen is 320 pixels wide, because the viewport simulates a
+drawable area that's 800 pixels wide), as shown in figure 1. So, you should explicitly define the
+viewport {@code width} to match the width for which you have designed your web page.</p>
+
+<p class="note"><strong>Note:</strong> Width values that are greater than 10,000 are ignored and
+values less than (or equal to) 320 result in a value equal to the device-width. Height values that
+are greater then 10,000 or less than 200 are also ignored.</p>
+
+<p>For example, if your web page is designed to be exactly 320 pixels wide, then you might
+want to specify that for the viewport width:</p>
+
+<pre>
+<meta name="viewport" content="width=320" />
+</pre>
+
+<p>In this case, your web page exactly fits the screen width, because the web page width and
+viewport width are the same.</p>
+
+<p>To demonstrate how this property affects the size of
+your web page, figure 2 shows a web page that contains an image that's 320 pixels wide, but with the
+viewport width set to 400.</p>
+
+
+<p class="note"><strong>Note:</strong> If you set the viewport width to match your web page width
+and the device screen width does <em>not</em> match those dimensions, then the web page
+still fits the screen even if the device has a high or low-density screen, because the
+Android Browser scales web pages to match the perceived size on a medium-density
+screen, by default (as you can see in figure 2, when comparing the hdpi device to the mdpi device).
+Screen densities are discussed more in <a href="#ViewportDensity">Defining the viewport target
+density</a>.</p>
+
+
+<h4>Automatic sizing</h4>
+
+<p>As an alternative to specifying the viewport dimensions with exact pixels, you can set the
+viewport size to always match the dimensions of the device screen, by defining the
+viewport properties {@code height}
+and {@code width} with the values {@code device-height} and {@code device-width}, respectively. This
+is appropriate when you're developing a web application that has a fluid width (not fixed width),
+but you want it to appear as if it's fixed (to perfectly fit every screen as
+if the web page width is set to match each screen). For example:</p>
+
+<pre>
+<meta name="viewport" content="width=device-width" />
+</pre>
+
+<p>This results in the viewport width matching whatever the current screen width is, as shown in
+figure 3. It's important to notice that, this results in images being scaled to fit the screen
+when the current device does not match the <a href="#ViewportDensity">target
+density</a>, which is medium-density if you don't specify otherwise. As a result, the image
+displayed on the high-density device in figure 3 is scaled up in order to match the width
+of a screen with a medium-density screen.</p>
+
+<div class="figure" style="width:300px">
+ <img src="{@docRoot}images/webapps/compare-initialscale.png" alt="" height="300" />
+ <p class="img-caption"><strong>Figure 3.</strong> A web page with viewport {@code
+width=device-width} <em>or</em> {@code initial-scale=1.0}.</p>
+</div>
+
+<p class="note"><strong>Note:</strong> If you instead want {@code
+device-width} and {@code device-height} to match the physical screen pixels for every device,
+instead of scaling your web page to match the target density, then you must also include
+the {@code target-densitydpi} property with a value of {@code device-dpi}. This is discussed more in
+the section about <a href="#ViewportDensity">Defining the viewport density</a>. Otherwise, simply
+using {@code device-height} and {@code device-width} to define the viewport size makes your web page
+fit every device screen, but scaling occurs on your images in order to adjust for different screen
+densities.</p>
+
+
+
+<h3 id="ViewportScale">Defining the viewport scale</h3>
+
+<p>The scale of the viewport defines the level of zoom applied to the web page. Viewport
+properties allow you to specify the scale of your web page in the following ways:</p>
+<dl>
+ <dt>{@code initial-scale}</dt>
+ <dd>The initial scale of the page. The value is a float that indicates a multiplier for your web
+page size, relative to the screen size. For example, if you set the initial scale to "1.0" then the
+web page is displayed to match the resolution of the <a href="#ViewportDensity">target
+density</a> 1-to-1. If set to "2.0", then the page is enlarged (zoomed in) by a factor of 2.
+ <p>The default initial scale is calculated to fit the web page in the viewport size.
+Because the default viewport width is 800 pixels, if the device screen resolution is less than
+800 pixels wide, the initial scale is something less than 1.0, by default, in order to fit the
+800-pixel-wide page on the screen.</p></dd>
+
+ <dt>{@code minimum-scale}</dt>
+ <dd>The minimum scale to allow. The value is a float that indicates the minimum multiplier for
+your web page size, relative to the screen size. For example, if you set this to "1.0", then the
+page can't zoom out because the minimum size is 1-to-1 with the <a href="#ViewportDensity">target
+density</a>.</dd>
+
+ <dt>{@code maximum-scale}</dt>
+ <dd>The maximum scale to allow for the page. The value is a float that indicates the
+maximum multiplier for your web page size,
+relative to the screen size. For example, if you set this to "2.0", then the page can't
+zoom in more than 2 times the target size.</dd>
+
+ <dt>{@code user-scalable}</dt>
+ <dd>Whether the user can change the scale of the page at all (zoom in and out). Set to {@code yes}
+to allow scaling and {@code no} to disallow scaling. The default is {@code yes}. If you set
+this to {@code no}, then the {@code minimum-scale} and {@code maximum-scale} are ignored,
+because scaling is not possible.</dd>
+</dl>
+
+<p>All scale values must be within the range 0.01–10.</p>
+
+<p>For example:</p>
+
+<pre>
+<meta name="viewport" content="initial-scale=1.0" />
+</pre>
+
+<p>This metadata sets the initial scale to be full sized, relative to the viewport's target
+density.</p>
+
+
+
+
+<h3 id="ViewportDensity">Defining the viewport target density</h3>
+
+<p>The density of a device's screen is based on the screen resolution. There are three screen
+density categories supported by Android: low (ldpi), medium (mdpi), and high (mdpi). A screen
+with low density has fewer available pixels per inch, whereas a screen with high density has more
+pixels per inch (compared to a medium density screen). The Android Browser targets a medium density
+screen by default.</p>
+
+
+<div class="figure" style="width:300px">
+ <img src="{@docRoot}images/webapps/compare-initialscale-devicedpi.png" alt="" height="300" />
+ <p class="img-caption"><strong>Figure 4.</strong> A web page with viewport {@code
+width=device-width} and {@code target-densitydpi=device-dpi}.</p>
+</div>
+
+
+<p>Because the default target density is medium, when users have a device with a low or high density
+screen, the Android Browser scales web pages (effectively zooms the pages) so they display at a
+size that matches the perceived appearance on a medium density screen. Specifically, the Android
+Browser applies approximately 1.5x scaling to web pages on a high density screen
+(because its screen pixels are smaller) and approximately 0.75x scaling to pages on a low density
+screen (because its screen pixels are bigger).</p>
+
+<p>Due to this default scaling, figures 1, 2, and 3 show the example web page at the same physical
+size on both the high and medium density device (the high-density device shows the
+web page with a default scale factor that is 1.5 times larger than the actual pixel resolution, to
+match the target density). This can introduce some undesirable artifacts in your images.
+For example, although an image appears the same size on a medium and high-density device, the image
+on the high-density device appears more blurry, because the image is designed to be 320 pixels
+wide, but is drawn with 480 pixels.</p>
+
+<p>You can change the target screen density for your web page using the {@code target-densitydpi}
+viewport property. It accepts the following values:</p>
+
+<ul>
+<li><code>device-dpi</code> - Use the device's native dpi as the target dpi. Default scaling never
+occurs.</li>
+<li><code>high-dpi</code> - Use hdpi as the target dpi. Medium and low density screens scale down
+as appropriate.</li>
+<li><code>medium-dpi</code> - Use mdpi as the target dpi. High density screens scale up and low
+density screens scale down. This is the default target density.</li>
+<li><code>low-dpi</code> - Use ldpi as the target dpi. Medium and high density screens scale up
+as appropriate.</li>
+<li><em><code><value></code></em> - Specify a dpi value to use as the target dpi. Values must
+be within the range 70–400.</li>
+</ul></p>
+
+<p>For example, to prevent the Android Browser from scaling of your web page for different screen
+densities, set
+the {@code target-densitydpi} viewport property to {@code device-dpi}. When you do, the Android
+Browser does not scale the page and, instead, displays your web page to match the current screen
+density. In this case, you should also define the viewport width to match the device width, so your
+web page naturally fits the screen size. For example:</p>
+
+<pre>
+<meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" />
+</pre>
+
+<p>Figure 4 shows a web page using these viewport settings—the high-density device
+now displays the page smaller because its physical pixels are smaller than those on the
+medium-density device, so no scaling occurs and the 320-pixel-wide image is drawn using exactly 320
+pixels on both screens. (This is how you should define your viewport if
+you want to customize your web page based on screen density and provide different image assets for
+different densities, <a href="#DensityCSS">with CSS</a> or
+<a href="#DensityJS">with JavaScript</a>.)</p>
+
+
+<h2 id="DensityCSS">Targetting Device Density with CSS</h2>
+
+<p>The Android Browser supports a CSS media feature that allows you to create styles for specific
+screen densities—the <code>-webkit-device-pixel-ratio</code> CSS media feature. The
+value you apply to this feature should be either
+"0.75", "1", or "1.5", to indicate that the styles are for devices with low density, medium density,
+or high density screens, respectively.</p>
+
+<p>For example, you can create separate stylesheets for each density:</p>
+
+<pre>
+<link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.5)" href="hdpi.css" />
+<link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 1.0)" href="mdpi.css" />
+<link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio: 0.75)" href="ldpi.css" />
+</pre>
+
+
+<div class="figure" style="width:300px">
+ <img src="{@docRoot}images/webapps/compare-width-devicedpi-css.png" alt="" height="300" />
+ <p class="img-caption"><strong>Figure 5.</strong> A web page with CSS that's targetted to
+specific screen densities using the {@code -webkit-device-pixel-ratio} media feature. Notice
+that the hdpi device shows a different image that's applied in CSS.</p>
+</div>
+
+<p>Or, specify the different styles in one stylesheet:</p>
+
+<pre class="no-pretty-print">
+#header {
+ background:url(medium-density-image.png);
+}
+
+@media screen and (-webkit-device-pixel-ratio: 1.5) {
+ // CSS for high-density screens
+ #header {
+ background:url(high-density-image.png);
+ }
+}
+
+@media screen and (-webkit-device-pixel-ratio: 0.75) {
+ // CSS for low-density screens
+ #header {
+ background:url(low-density-image.png);
+ }
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> The default style for {@code #header} applies the image
+designed for medium-density devices in order to support devices running a version of Android less
+than 2.0, which do not support the {@code -webkit-device-pixel-ratio} media feature.</p>
+
+<p>The types of styles you might want to adjust based on the screen density depend on how you've
+defined your viewport properties. To provide fully-customized styles that tailor your web page for
+each of the supported densities, you should set your viewport properties so the viewport width and
+density match the device. That is:</p>
+
+<pre>
+<meta name="viewport" content="target-densitydpi=device-dpi, width=device-width" />
+</pre>
+
+<p>This way, the Android Browser does not perform scaling on your web page and the viewport width
+matches the screen width exactly. On its own, these viewport properties create results shown in
+figure 4. However, by adding some custom CSS using the {@code -webkit-device-pixel-ratio} media
+feature, you can apply different styles. For example, figure 5 shows a web page with these viewport
+properties and also some CSS added that applies a high-resolution image for high-density
+screens.</p>
+
+
+
+<h2 id="DensityJS">Targetting Device Density with JavaScript</h2>
+
+<p>The Android Browser supports a DOM property that allows you to query the density of the current
+device—the <code>window.devicePixelRatio</code> DOM property. The value of this property
+specifies the scaling factor used for the current device. For example, if the value
+of <code>window.devicePixelRatio</code> is "1.0", then the device is considered a medium density
+device and no scaling is applied by default; if the value is "1.5", then the device is
+considered a high density device and the page is scaled 1.5x by default; if the value
+is "0.75", then the device is considered a low density device and the page is scaled
+0.75x by default. Of course, the scaling that the Android Browser applies is based on the web page's
+target density—as described in the section about <a href="#ViewportDensity">Defining the
+viewport target density</a>, the default target is medium-density, but you can change the
+target to affect how your web page is scaled for different screen densities.</p>
+
+<p>For example, here's how you can query the device density with JavaScript:</p>
+
+<pre>
+if (window.devicePixelRatio == 1.5) {
+ alert("This is a high-density screen");
+} else if (window.devicePixelRation == 0.75) {
+ alert("This is a low-density screen");
+}
+</pre>
+
+
+
+
+
+
+
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
new file mode 100644
index 0000000..ed28f21
--- /dev/null
+++ b/docs/html/guide/webapps/webview.jd
@@ -0,0 +1,328 @@
+page.title=Building Web Apps in WebView
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+<h2>Quickview</h2>
+<ul>
+ <li>Use {@link android.webkit.WebView} to display web pages in your Android application
+layout</li>
+ <li>You can create interfaces from your JavaScript to your client-side Android code</li>
+</ul>
+
+<h2>In this document</h2>
+<ol>
+ <li><a href="#AddingWebView">Adding a WebView to Your Application</a></li>
+ <li><a href="#UsingJavaScript">Using JavaScript in WebView</a>
+ <ol>
+ <li><a href="#EnablingJavaScript">Enabling JavaScript</a></li>
+ <li><a href="#BindingJavaScript">Binding JavaScript code to Android code</a></li>
+ </ol>
+ </li>
+ <li><a href="#HandlingNavigation">Handling Page Navigation</a>
+ <ol>
+ <li><a href="#NavigatingHistory">Navigating web page history</a></li>
+ </ol>
+ </li>
+</ol>
+
+<h2>Key classes</h2>
+<ol>
+ <li>{@link android.webkit.WebView}</li>
+ <li>{@link android.webkit.WebSettings}</li>
+ <li>{@link android.webkit.WebViewClient}</li>
+</ol>
+
+<h2>Related tutorials</h2>
+<ol>
+ <li><a href="{@docRoot}resources/tutorials/views/hello-webview.html">Web View</a></li>
+</ol>
+
+</div>
+</div>
+
+<p>If you want to deliver a web application (or just a web page) as a part of a client application,
+you can do it using {@link android.webkit.WebView}. The {@link android.webkit.WebView} class is an
+extension of Android's {@link android.view.View} class that allows you to display web pages as a
+part of your activity layout. It does <em>not</em> include any features of a fully developed web
+browser, such as navigation controls or an address bar. All that {@link android.webkit.WebView}
+does, by default, is show a web page.</p>
+
+<p>A common scenario in which using {@link android.webkit.WebView} is helpful is when you want to
+provide information in your application that you might need to update, such as an end-user agreement
+or a user guide. Within your Android application, you can create an {@link android.app.Activity}
+that contains a {@link android.webkit.WebView}, then use that to display your document that's
+hosted online.</p>
+
+<p>Another scenario in which {@link android.webkit.WebView} can help is if your application provides
+data to the user that
+always requires an Internet connection to retrieve data, such as email. In this case, you might
+find that it's easier to build a {@link android.webkit.WebView} in your Android application that
+shows a web page with all
+the user data, rather than performing a network request, then parsing the data and rendering it in
+an Android layout. Instead, you can design a web page that's tailored for Android devices
+and then implement a {@link android.webkit.WebView} in your Android application that loads the web
+page.</p>
+
+<p>This document shows you how to get started with {@link android.webkit.WebView} and how to do some
+additional things, such as handle page navigation and bind JavaScript from your web page to
+client-side code in your Android application.</p>
+
+
+
+<h2 id="AddingWebView">Adding a WebView to Your Application</h2>
+
+<p>To add a {@link android.webkit.WebView} to your Application, simply include the {@code
+<WebView>} element in your activity layout. For example, here's a layout file in which the
+{@link android.webkit.WebView} fills the screen:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<WebView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/webview"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+/>
+</pre>
+
+<p>To load a web page in the {@link android.webkit.WebView}, use {@link
+android.webkit.WebView#loadUrl(String) loadUrl()}. For example:</p>
+
+<pre>
+WebView myWebView = (WebView) findViewById(R.id.webview);
+myWebView.loadUrl("http://www.example.com");
+</pre>
+
+<p>Before this will work, however, your application must have access to the Internet. To get
+Internet access, request the {@link android.Manifest.permission#INTERNET} permission in your
+manifest file. For example:</p>
+
+<pre>
+<manifest ... >
+ <uses-permission android:name="android.permission.INTERNET" />
+ ...
+</manifest>
+</pre>
+
+<p>That's all you need for a basic {@link android.webkit.WebView} that displays a web page.</p>
+
+
+
+
+<h2 id="UsingJavaScript">Using JavaScript in WebView</h2>
+
+<p>If the web page you plan to load in your {@link android.webkit.WebView} use JavaScript, you
+must enable JavaScript for your {@link android.webkit.WebView}. Once JavaScript is enabled, you can
+also create interfaces between your application code and your JavaScript code.</p>
+
+
+<h3 id="EnablingJavaScript">Enabling JavaScript</h3>
+
+<p>JavaScript is disabled in a {@link android.webkit.WebView} by default. You can enable it
+through the {@link
+android.webkit.WebSettings} attached to your {@link android.webkit.WebView}. You can retrieve {@link
+android.webkit.WebSettings} with {@link android.webkit.WebView#getSettings()}, then enable
+JavaScript with {@link android.webkit.WebSettings#setJavaScriptEnabled(boolean)
+setJavaScriptEnabled()}.</p>
+
+<p>For example:</p>
+
+<pre>
+WebView myWebView = (WebView) findViewById(R.id.webview);
+WebSettings webSettings = myWebView.getSettings();
+webSettings.setJavaScriptEnabled(true);
+</pre>
+
+<p>{@link android.webkit.WebSettings} provides access to a variety of other settings that you might
+find useful. For example, if you're developing a web application
+that's designed specifically for the {@link android.webkit.WebView} in your Android application,
+then you can define a
+custom user agent string with {@link android.webkit.WebSettings#setUserAgentString(String)
+setUserAgentString()}, then query the custom user agent in your web page to verify that the
+client requesting your web page is actually your Android application.</p>
+
+from your Android SDK {@code tools/} directory
+<h3 id="BindingJavaScript">Binding JavaScript code to Android code</h3>
+
+<p>When developing a web application that's designed specifically for the {@link
+android.webkit.WebView} in your Android
+application, you can create interfaces between your JavaScript code and client-side Android code.
+For example, your JavaScript code can call a method in your Android code to display a {@link
+android.app.Dialog}, instead of using JavaScript's {@code alert()} function.</p>
+
+<p>To bind a new interface between your JavaScript and Android code, call {@link
+android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()}, passing it
+a class instance to bind to your JavaScript and an interface name that your JavaScript can call to
+access the class.</p>
+
+<p>For example, you can include the following class in your Android application:</p>
+
+<pre>
+public class JavaScriptInterface {
+ Context mContext;
+
+ /** Instantiate the interface and set the context */
+ JavaScriptInterface(Context c) {
+ mContext = c;
+ }
+
+ /** Show a toast from the web page */
+ public void showToast(String toast) {
+ Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
+ }
+}
+</pre>
+
+<p>In this example, the {@code JavaScriptInterface} class allows the web page to create a {@link
+android.widget.Toast} message, using the {@code showToast()} method.</p>
+
+<p>You can bind this class to the JavaScript that runs in your {@link android.webkit.WebView} with
+{@link android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()} and
+name the interface {@code Android}. For example:</p>
+
+<pre>
+WebView webView = (WebView) findViewById(R.id.webview);
+webView.addJavascriptInterface(new JavaScriptInterface(this), "Android");
+</pre>
+
+<p>This creates an interface called {@code Android} for JavaScript running in the {@link
+android.webkit.WebView}. At this point, your web application has access to the {@code
+JavaScriptInterface} class. For example, here's some HTML and JavaScript that creates a toast
+message using the new interface when the user clicks a button:</p>
+
+<pre>
+<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
+
+<script type="text/javascript">
+ function showAndroidToast(toast) {
+ Android.showToast(toast);
+ }
+</script>
+</pre>
+
+<p>There's no need to initialize the {@code Android} interface from JavaScript. The {@link
+android.webkit.WebView} automatically makes it
+available to your web page. So, at the click of the button, the {@code showAndroidToast()}
+function uses the {@code Android} interface to call the {@code JavaScriptInterface.showToast()}
+method.</p>
+
+<p class="note"><strong>Note:</strong> The object that is bound to your JavaScript runs in
+another thread and not in the thread in which it was constructed.</p>
+
+<p class="caution"><strong>Caution:</strong> Using {@link
+android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()} allows
+JavaScript to control your Android application. This can be a very useful feature or a dangerous
+security issue. When the HTML in the {@link android.webkit.WebView} is untrustworthy (for example,
+part or all of the HTML
+is provided by an unknown person or process), then an attacker can include HTML that executes
+your client-side code and possibly any code of the attacker's choosing. As such, you should not use
+{@link android.webkit.WebView#addJavascriptInterface(Object,String) addJavascriptInterface()} unless
+you wrote all of the HTML and JavaScript that appears in your {@link android.webkit.WebView}. You
+should also not allow the user to
+navigate to other web pages that are not your own, within your {@link android.webkit.WebView}
+(instead, allow the user's
+default browser application to open foreign links—by default, the user's web browser
+opens all URL links, so be careful only if you handle page navigation as described in the
+following section).</p>
+
+
+
+
+<h2 id="HandlingNavigation">Handling Page Navigation</h2>
+
+<p>When the user clicks a link from a web page in your {@link android.webkit.WebView}, the default
+behavior is
+for Android to launch an application that handles URLs. Usually, the default web browser opens and
+loads the destination URL. However, you can override this behavior for your {@link
+android.webkit.WebView},
+so links open within your {@link android.webkit.WebView}. You can then allow the user to navigate
+backward and forward through their web page history that's maintained by your {@link
+android.webkit.WebView}.</p>
+
+<p>To open links clicked by the user, simply provide a {@link
+android.webkit.WebViewClient} for your {@link android.webkit.WebView}, using {@link
+android.webkit.WebView#setWebViewClient(WebViewClient) setWebViewClient()}. For example:</p>
+
+<pre>
+WebView myWebView = (WebView) findViewById(R.id.webview);
+myWebView.{@link android.webkit.WebView#setWebViewClient(WebViewClient) setWebViewClient}(new WebViewClient());
+</pre>
+
+<p>That's it. Now all links the user clicks load in your {@link android.webkit.WebView}.</p>
+
+<p>If you want more control over where a clicked link load, create your own {@link
+android.webkit.WebViewClient} that overrides the {@link
+android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String)
+shouldOverrideUrlLoading()} method. For example:</p>
+
+<pre>
+private class MyWebViewClient extends WebViewClient {
+ @Override
+ public boolean {@link android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String) shouldOverrideUrlLoading}(WebView view, String url) {
+ if (Uri.parse(url).getHost().equals("www.example.com")) {
+ // This is my web site, so do not override; let my WebView load the page
+ return false;
+ }
+ // Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ startActivity(intent);
+ return true;
+ }
+}
+</pre>
+
+<p>Then create an instance of this new {@link android.webkit.WebViewClient} for the {@link
+android.webkit.WebView}:</p>
+
+<pre>
+WebView myWebView = (WebView) findViewById(R.id.webview);
+myWebView.{@link android.webkit.WebView#setWebViewClient(WebViewClient) setWebViewClient}(new MyWebViewClient());
+</pre>
+
+<p>Now when the user clicks a link, the system calls
+{@link android.webkit.WebViewClient#shouldOverrideUrlLoading(WebView,String)
+shouldOverrideUrlLoading()}, which checks whether the URL host matches a specific domain (as defined
+above). If it does match, then the method returns false in order to <em>not</em> override the URL
+loading (it allows the {@link android.webkit.WebView} to load the URL as usual). If the URL host
+does not match, then an {@link android.content.Intent} is created to
+launch the default Activity for handling URLs (which resolves to the user's default web
+browser).</p>
+
+
+
+
+<h3 id="NavigatingHistory">Navigating web page history</h3>
+
+<p>When your {@link android.webkit.WebView} overrides URL loading, it automatically accumulates a
+history of visited web
+pages. You can navigate backward and forward through the history with {@link
+android.webkit.WebView#goBack()} and {@link android.webkit.WebView#goForward()}.</p>
+
+<p>For example, here's how your {@link android.app.Activity} can use the device BACK key to navigate
+backward:</p>
+
+<pre>
+@Override
+public boolean {@link android.app.Activity#onKeyDown(int,KeyEvent) onKeyDown}(int keyCode, KeyEvent event) {
+ // Check if the key event was the BACK key and if there's history
+ if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.{@link android.webkit.WebView#canGoBack() canGoBack}() {
+ myWebView.{@link android.webkit.WebView#goBack() goBack}();
+ return true;
+ }
+ // If it wasn't the BACK key or there's no web page history, bubble up to the default
+ // system behavior (probably exit the activity)
+ return super.onKeyDown(keyCode, event);
+}
+</pre>
+
+<p>The {@link android.webkit.WebView#canGoBack()} method returns
+true if there is actually web page history for the user to visit. Likewise, you can use {@link
+android.webkit.WebView#canGoForward()} to check whether there is a forward history. If you don't
+perform this check, then once the user reaches the end of the history, {@link
+android.webkit.WebView#goBack()} or {@link android.webkit.WebView#goForward()} does nothing.</p>
+
+
+
+
+
+
diff --git a/docs/html/images/webapps/compare-default.png b/docs/html/images/webapps/compare-default.png
new file mode 100644
index 0000000..9495a05
--- /dev/null
+++ b/docs/html/images/webapps/compare-default.png
Binary files differ
diff --git a/docs/html/images/webapps/compare-initialscale-devicedpi.png b/docs/html/images/webapps/compare-initialscale-devicedpi.png
new file mode 100644
index 0000000..6bb758a
--- /dev/null
+++ b/docs/html/images/webapps/compare-initialscale-devicedpi.png
Binary files differ
diff --git a/docs/html/images/webapps/compare-initialscale.png b/docs/html/images/webapps/compare-initialscale.png
new file mode 100644
index 0000000..2232d5b
--- /dev/null
+++ b/docs/html/images/webapps/compare-initialscale.png
Binary files differ
diff --git a/docs/html/images/webapps/compare-width-devicedpi-css.png b/docs/html/images/webapps/compare-width-devicedpi-css.png
new file mode 100644
index 0000000..bb4ab31
--- /dev/null
+++ b/docs/html/images/webapps/compare-width-devicedpi-css.png
Binary files differ
diff --git a/docs/html/images/webapps/compare-width400.png b/docs/html/images/webapps/compare-width400.png
new file mode 100644
index 0000000..669a234
--- /dev/null
+++ b/docs/html/images/webapps/compare-width400.png
Binary files differ
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index d5be8f1..7a0b8ac 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -164,6 +164,11 @@
http://developer.android.com/guide/practices/design/performance.html
http://developer.android.com/guide/practices/design/responsiveness.html
http://developer.android.com/guide/practices/design/seamlessness.html
+http://developer.android.com/guide/webapps/targetting.html
+http://developer.android.com/guide/webapps/webview.html
+http://developer.android.com/guide/webapps/debugging.html
+http://developer.android.com/guide/webapps/best-practices.html
+http://developer.android.com/guide/topics/admin/device-admin.html
http://developer.android.com/guide/appendix/api-levels.html
http://developer.android.com/guide/appendix/media-formats.html
http://developer.android.com/guide/appendix/g-app-intents.html
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 2c076b3..6c08ce5 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -90,6 +90,18 @@
subData1D(0, mType.getElementCount(), d);
}
+ public void updateFromBitmap(Bitmap b)
+ throws IllegalArgumentException {
+
+ mRS.validate();
+ if(mType.getX() != b.getWidth() ||
+ mType.getY() != b.getHeight()) {
+ throw new IllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch");
+ }
+
+ mRS.nAllocationUpdateFromBitmap(mID, b);
+ }
+
public void subData(int xoff, FieldPacker fp) {
int eSize = mType.mElement.getSizeBytes();
final byte[] data = fp.getData();
@@ -372,17 +384,6 @@
return a;
}
- static Allocation createFromBitmapBoxed(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
- throws IllegalArgumentException {
-
- rs.validate();
- int id = rs.nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b);
- if(id == 0) {
- throw new IllegalStateException("Load failed.");
- }
- return new Allocation(id, rs, null);
- }
-
static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
throws IllegalArgumentException {
@@ -415,24 +416,6 @@
return null;
}
- static public Allocation createFromBitmapResourceBoxed(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips)
- throws IllegalArgumentException {
-
- mBitmapOptions.inPreferredConfig = null;
- if (dstFmt == rs.mElement_RGBA_8888) {
- mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
- } else if (dstFmt == rs.mElement_RGB_888) {
- mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
- } else if (dstFmt == rs.mElement_RGBA_4444) {
- mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_4444;
- } else if (dstFmt == rs.mElement_RGB_565) {
- mBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
- }
-
- Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
- return createFromBitmapBoxed(rs, b, dstFmt, genMips);
- }
-
static public Allocation createFromString(RenderScript rs, String str)
throws IllegalArgumentException {
byte[] allocArray = null;
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 91824e6..dc421d8 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -47,7 +47,7 @@
UNSIGNED_8 (8, 1),
UNSIGNED_16 (9, 2),
UNSIGNED_32 (10, 4),
- //UNSIGNED_64 (11, 8),
+ UNSIGNED_64 (11, 8),
BOOLEAN(12, 1),
@@ -142,6 +142,13 @@
return rs.mElement_I32;
}
+ public static Element U64(RenderScript rs) {
+ if(rs.mElement_U64 == null) {
+ rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64);
+ }
+ return rs.mElement_U64;
+ }
+
public static Element I64(RenderScript rs) {
if(rs.mElement_I64 == null) {
rs.mElement_I64 = createUser(rs, DataType.SIGNED_64);
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
index f05e84c..2540d01 100644
--- a/graphics/java/android/renderscript/RSSurfaceView.java
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -25,7 +25,6 @@
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
@@ -146,22 +145,18 @@
// ----------------------------------------------------------------------
- public RenderScriptGL createRenderScript(boolean useDepth, boolean forceSW) {
+ public RenderScriptGL createRenderScript(RenderScriptGL.SurfaceConfig sc) {
Log.v(RenderScript.LOG_TAG, "createRenderScript");
- mRS = new RenderScriptGL(useDepth, forceSW);
+ mRS = new RenderScriptGL(sc);
return mRS;
}
- public RenderScriptGL createRenderScript(boolean useDepth) {
- return createRenderScript(useDepth, false);
- }
-
public void destroyRenderScript() {
Log.v(RenderScript.LOG_TAG, "destroyRenderScript");
mRS.destroy();
mRS = null;
}
-
+
public void createRenderScript(RenderScriptGL rs) {
mRS = rs;
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 0088373..0f9ed87 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -186,6 +186,10 @@
synchronized int nAllocationCreateTyped(int type) {
return rsnAllocationCreateTyped(mContext, type);
}
+ native void rsnAllocationUpdateFromBitmap(int con, int alloc, Bitmap bmp);
+ synchronized void nAllocationUpdateFromBitmap(int alloc, Bitmap bmp) {
+ rsnAllocationUpdateFromBitmap(mContext, alloc, bmp);
+ }
native int rsnAllocationCreateFromBitmap(int con, int dstFmt, boolean genMips, Bitmap bmp);
synchronized int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp) {
return rsnAllocationCreateFromBitmap(mContext, dstFmt, genMips, bmp);
@@ -194,10 +198,6 @@
synchronized int nAllocationCreateBitmapRef(int type, Bitmap bmp) {
return rsnAllocationCreateBitmapRef(mContext, type, bmp);
}
- native int rsnAllocationCreateFromBitmapBoxed(int con, int dstFmt, boolean genMips, Bitmap bmp);
- synchronized int nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp) {
- return rsnAllocationCreateFromBitmapBoxed(mContext, dstFmt, genMips, bmp);
- }
native int rsnAllocationCreateFromAssetStream(int con, int dstFmt, boolean genMips, int assetStream);
synchronized int nAllocationCreateFromAssetStream(int dstFmt, boolean genMips, int assetStream) {
return rsnAllocationCreateFromAssetStream(mContext, dstFmt, genMips, assetStream);
@@ -363,6 +363,10 @@
synchronized void nScriptSetVarI(int id, int slot, int val) {
rsnScriptSetVarI(mContext, id, slot, val);
}
+ native void rsnScriptSetVarJ(int con, int id, int slot, long val);
+ synchronized void nScriptSetVarJ(int id, int slot, long val) {
+ rsnScriptSetVarJ(mContext, id, slot, val);
+ }
native void rsnScriptSetVarF(int con, int id, int slot, float val);
synchronized void nScriptSetVarF(int id, int slot, float val) {
rsnScriptSetVarF(mContext, id, slot, val);
@@ -510,6 +514,7 @@
Element mElement_I16;
Element mElement_U32;
Element mElement_I32;
+ Element mElement_U64;
Element mElement_I64;
Element mElement_F32;
Element mElement_F64;
diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java
index 61ecc8d..b60c689 100644
--- a/graphics/java/android/renderscript/RenderScriptGL.java
+++ b/graphics/java/android/renderscript/RenderScriptGL.java
@@ -23,7 +23,8 @@
import android.util.Config;
import android.util.Log;
import android.view.Surface;
-
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
/**
* @hide
@@ -34,16 +35,90 @@
int mWidth;
int mHeight;
+ public static class SurfaceConfig {
+ int mDepthMin = 0;
+ int mDepthPref = 0;
+ int mStencilMin = 0;
+ int mStencilPref = 0;
+ int mColorMin = 8;
+ int mColorPref = 8;
+ int mAlphaMin = 0;
+ int mAlphaPref = 0;
+ int mSamplesMin = 1;
+ int mSamplesPref = 1;
+ float mSamplesQ = 1.f;
- public RenderScriptGL(boolean useDepth, boolean forceSW) {
+ public SurfaceConfig() {
+ }
+
+ public SurfaceConfig(SurfaceConfig sc) {
+ mDepthMin = sc.mDepthMin;
+ mDepthPref = sc.mDepthPref;
+ mStencilMin = sc.mStencilMin;
+ mStencilPref = sc.mStencilPref;
+ mColorMin = sc.mColorMin;
+ mColorPref = sc.mColorPref;
+ mAlphaMin = sc.mAlphaMin;
+ mAlphaPref = sc.mAlphaPref;
+ mSamplesMin = sc.mSamplesMin;
+ mSamplesPref = sc.mSamplesPref;
+ mSamplesQ = sc.mSamplesQ;
+ }
+
+ private void validateRange(int umin, int upref, int rmin, int rmax) {
+ if (umin < rmin || umin > rmax) {
+ throw new IllegalArgumentException("Minimum value provided out of range.");
+ }
+ if (upref < umin) {
+ throw new IllegalArgumentException("Prefered must be >= Minimum.");
+ }
+ }
+
+ public void setColor(int minimum, int prefered) {
+ validateRange(minimum, prefered, 5, 8);
+ mColorMin = minimum;
+ mColorPref = prefered;
+ }
+ public void setAlpha(int minimum, int prefered) {
+ validateRange(minimum, prefered, 0, 8);
+ mAlphaMin = minimum;
+ mAlphaPref = prefered;
+ }
+ public void setDepth(int minimum, int prefered) {
+ validateRange(minimum, prefered, 0, 24);
+ mDepthMin = minimum;
+ mDepthPref = prefered;
+ }
+ public void setSamples(int minimum, int prefered, float Q) {
+ validateRange(minimum, prefered, 0, 24);
+ if (Q < 0.0f || Q > 1.0f) {
+ throw new IllegalArgumentException("Quality out of 0-1 range.");
+ }
+ mSamplesMin = minimum;
+ mSamplesPref = prefered;
+ mSamplesQ = Q;
+ }
+ };
+
+ SurfaceConfig mSurfaceConfig;
+
+ public void configureSurface(SurfaceHolder sh) {
+ //getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ public void checkSurface(SurfaceHolder sh) {
+ }
+
+ public RenderScriptGL(SurfaceConfig sc) {
+ mSurfaceConfig = new SurfaceConfig(sc);
+
+
+
mSurface = null;
mWidth = 0;
mHeight = 0;
mDev = nDeviceCreate();
- if(forceSW) {
- nDeviceSetConfig(mDev, 0, 1);
- }
- mContext = nContextCreateGL(mDev, 0, useDepth);
+ mContext = nContextCreateGL(mDev, 0, mSurfaceConfig.mDepthMin > 0);
mMessageThread = new MessageThread(this);
mMessageThread.start();
Element.initPredefined(this);
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index 8772c4c..53a33e4 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -80,6 +80,10 @@
mRS.nScriptSetVarI(mID, index, v);
}
+ public void setVar(int index, long v) {
+ mRS.nScriptSetVarJ(mID, index, v);
+ }
+
public void setVar(int index, boolean v) {
mRS.nScriptSetVarI(mID, index, v ? 1 : 0);
}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 8f1e93c..014f03b 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -423,6 +423,23 @@
return 0;
}
+static void
+nAllocationUpdateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jobject jbitmap)
+{
+ SkBitmap const * nativeBitmap =
+ (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
+ const SkBitmap& bitmap(*nativeBitmap);
+ SkBitmap::Config config = bitmap.getConfig();
+
+ RsElement e = SkBitmapToPredefined(config);
+ if (e) {
+ bitmap.lockPixels();
+ const void* ptr = bitmap.getPixels();
+ rsAllocationUpdateFromBitmap(con, (RsAllocation)alloc, e, ptr);
+ bitmap.unlockPixels();
+ }
+}
+
static void ReleaseBitmapCallback(void *bmp)
{
SkBitmap const * nativeBitmap = (SkBitmap const *)bmp;
@@ -466,29 +483,6 @@
return 0;
}
-static int
-nAllocationCreateFromBitmapBoxed(JNIEnv *_env, jobject _this, RsContext con, jint dstFmt, jboolean genMips, jobject jbitmap)
-{
- SkBitmap const * nativeBitmap =
- (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID);
- const SkBitmap& bitmap(*nativeBitmap);
- SkBitmap::Config config = bitmap.getConfig();
-
- RsElement e = SkBitmapToPredefined(config);
-
- if (e) {
- bitmap.lockPixels();
- const int w = bitmap.width();
- const int h = bitmap.height();
- const void* ptr = bitmap.getPixels();
- jint id = (jint)rsAllocationCreateFromBitmapBoxed(con, w, h, (RsElement)dstFmt, e, genMips, ptr);
- bitmap.unlockPixels();
- return id;
- }
- return 0;
-}
-
-
static void
nAllocationSubData1D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint count, jintArray data, int sizeBytes)
{
@@ -803,6 +797,13 @@
}
static void
+nScriptSetVarJ(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jlong val)
+{
+ LOG_API("nScriptSetVarJ, con(%p), s(%p), slot(%i), val(%lli)", con, (void *)script, slot, val);
+ rsScriptSetVarJ(con, (RsScript)script, slot, val);
+}
+
+static void
nScriptSetVarF(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, float val)
{
LOG_API("nScriptSetVarF, con(%p), s(%p), slot(%i), val(%f)", con, (void *)script, slot, val);
@@ -1250,9 +1251,9 @@
{"rsnTypeGetNativeData", "(II[I)V", (void*)nTypeGetNativeData },
{"rsnAllocationCreateTyped", "(II)I", (void*)nAllocationCreateTyped },
+{"rsnAllocationUpdateFromBitmap", "(IILandroid/graphics/Bitmap;)V", (void*)nAllocationUpdateFromBitmap },
{"rsnAllocationCreateFromBitmap", "(IIZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap },
{"rsnAllocationCreateBitmapRef", "(IILandroid/graphics/Bitmap;)I", (void*)nAllocationCreateBitmapRef },
-{"rsnAllocationCreateFromBitmapBoxed","(IIZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmapBoxed },
{"rsnAllocationCreateFromAssetStream","(IIZI)I", (void*)nAllocationCreateFromAssetStream },
{"rsnAllocationUploadToTexture", "(IIZI)V", (void*)nAllocationUploadToTexture },
{"rsnAllocationUploadToBufferObject","(II)V", (void*)nAllocationUploadToBufferObject },
@@ -1290,6 +1291,7 @@
{"rsnScriptInvoke", "(III)V", (void*)nScriptInvoke },
{"rsnScriptInvokeV", "(III[B)V", (void*)nScriptInvokeV },
{"rsnScriptSetVarI", "(IIII)V", (void*)nScriptSetVarI },
+{"rsnScriptSetVarJ", "(IIIJ)V", (void*)nScriptSetVarJ },
{"rsnScriptSetVarF", "(IIIF)V", (void*)nScriptSetVarF },
{"rsnScriptSetVarD", "(IIID)V", (void*)nScriptSetVarD },
{"rsnScriptSetVarV", "(III[B)V", (void*)nScriptSetVarV },
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 13c73ac..eae0d7b 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -77,6 +77,7 @@
virtual uint32_t latency() const = 0;
virtual float msecsPerFrame() const = 0;
virtual status_t getPosition(uint32_t *position) = 0;
+ virtual int getSessionId() = 0;
// If no callback is specified, use the "write" API below to submit
// audio data.
diff --git a/include/media/Metadata.h b/include/media/Metadata.h
index 241868a..9c915ce 100644
--- a/include/media/Metadata.h
+++ b/include/media/Metadata.h
@@ -91,6 +91,7 @@
static const Type kPauseAvailable = 29; // Boolean
static const Type kSeekBackwardAvailable = 30; // Boolean
static const Type kSeekForwardAvailable = 31; // Boolean
+ static const Type kSeekAvailable = 32; // Boolean
// @param p[inout] The parcel to append the metadata records
// to. The global metadata header should have been set already.
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 21338ca..16b0a4c 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -45,13 +45,14 @@
virtual sp<MetaData> getMetaData();
enum Flags {
- CAN_SEEK_BACKWARD = 1,
- CAN_SEEK_FORWARD = 2,
+ CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
+ CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
CAN_PAUSE = 4,
+ CAN_SEEK = 8, // the "seek bar"
};
// If subclasses do _not_ override this, the default is
- // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE
+ // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
virtual uint32_t flags() const;
protected:
diff --git a/include/ui/Input.h b/include/ui/Input.h
index ee40b85..8c6018b 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -71,6 +71,8 @@
/*
* Flags that flow alongside events in the input dispatch system to help with certain
* policy decisions such as waking from device sleep.
+ *
+ * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java.
*/
enum {
/* These flags originate in RawEvents and are generally set in the key map.
@@ -93,6 +95,10 @@
// Indicates that the input event was injected.
POLICY_FLAG_INJECTED = 0x01000000,
+ // Indicates that the input event is from a trusted source such as a directly attached
+ // input device or an application with system-wide event injection permission.
+ POLICY_FLAG_TRUSTED = 0x02000000,
+
/* These flags are set by the input reader policy as it intercepts each event. */
// Indicates that the screen was off when the event was received and the event
@@ -102,6 +108,11 @@
// Indicates that the screen was dim when the event was received and the event
// should brighten the device.
POLICY_FLAG_BRIGHT_HERE = 0x20000000,
+
+ // Indicates that the event should be dispatched to applications.
+ // The input event should still be sent to the InputDispatcher so that it can see all
+ // input events received include those that it will not deliver.
+ POLICY_FLAG_PASS_TO_USER = 0x40000000,
};
/*
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index 246df8f8..63185d3 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -282,10 +282,35 @@
*/
virtual int32_t getMaxEventsPerSecond() = 0;
+ /* Intercepts a key event immediately before queueing it.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing such as updating policy flags.
+ *
+ * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+ * should be dispatched to applications.
+ */
+ virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
+ int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
+ uint32_t& policyFlags) = 0;
+
+ /* Intercepts a generic touch, trackball or other event before queueing it.
+ * The policy can use this method as an opportunity to perform power management functions
+ * and early event preprocessing such as updating policy flags.
+ *
+ * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
+ * should be dispatched to applications.
+ */
+ virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0;
+
/* Allows the policy a chance to intercept a key before dispatching. */
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
+ /* Notifies the policy about switch events.
+ */
+ virtual void notifySwitch(nsecs_t when,
+ int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0;
+
/* Poke user activity for an event dispatched to a window. */
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;
@@ -333,6 +358,8 @@
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime) = 0;
+ virtual void notifySwitch(nsecs_t when,
+ int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0;
/* Injects an input event and optionally waits for sync.
* The synchronization mode determines whether the method blocks while waiting for
@@ -416,6 +443,8 @@
int32_t metaState, int32_t edgeFlags,
uint32_t pointerCount, const int32_t* pointerIds, const PointerCoords* pointerCoords,
float xPrecision, float yPrecision, nsecs_t downTime);
+ virtual void notifySwitch(nsecs_t when,
+ int32_t switchCode, int32_t switchValue, uint32_t policyFlags) ;
virtual int32_t injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis);
@@ -458,6 +487,7 @@
mutable int32_t refCount;
int32_t type;
nsecs_t eventTime;
+ uint32_t policyFlags;
InjectionState* injectionState;
bool dispatchInProgress; // initially false, set to true while dispatching
@@ -471,7 +501,6 @@
struct KeyEntry : EventEntry {
int32_t deviceId;
int32_t source;
- uint32_t policyFlags;
int32_t action;
int32_t flags;
int32_t keyCode;
@@ -500,7 +529,6 @@
struct MotionEntry : EventEntry {
int32_t deviceId;
int32_t source;
- uint32_t policyFlags;
int32_t action;
int32_t flags;
int32_t metaState;
@@ -675,7 +703,8 @@
Pool<DispatchEntry> mDispatchEntryPool;
Pool<CommandEntry> mCommandEntryPool;
- void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime);
+ void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime,
+ uint32_t policyFlags);
void releaseEventEntryInjectionState(EventEntry* entry);
};
@@ -696,21 +725,19 @@
BROKEN
};
+ // Specifies the sources to cancel.
+ enum CancelationOptions {
+ CANCEL_ALL_EVENTS = 0,
+ CANCEL_POINTER_EVENTS = 1,
+ CANCEL_NON_POINTER_EVENTS = 2,
+ };
+
InputState();
~InputState();
// Returns true if there is no state to be canceled.
bool isNeutral() const;
- // Returns true if the input state believes it is out of sync.
- bool isOutOfSync() const;
-
- // Sets the input state to be out of sync if it is not neutral.
- void setOutOfSync();
-
- // Resets the input state out of sync flag.
- void resetOutOfSync();
-
// Records tracking information for an event that has just been published.
// Returns whether the event is consistent with the current input state.
Consistency trackEvent(const EventEntry* entry);
@@ -723,16 +750,17 @@
// Returns whether the event is consistent with the current input state.
Consistency trackMotion(const MotionEntry* entry);
- // Synthesizes cancelation events for the current state.
- void synthesizeCancelationEvents(Allocator* allocator,
- Vector<EventEntry*>& outEvents) const;
+ // Synthesizes cancelation events for the current state and resets the tracked state.
+ void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
+ Vector<EventEntry*>& outEvents, CancelationOptions options);
// Clears the current state.
void clear();
- private:
- bool mIsOutOfSync;
+ // Copies pointer-related parts of the input state to another instance.
+ void copyPointerStateTo(InputState& other) const;
+ private:
struct KeyMemento {
int32_t deviceId;
int32_t source;
@@ -756,6 +784,8 @@
Vector<KeyMemento> mKeyMementos;
Vector<MotionMemento> mMotionMementos;
+
+ static bool shouldCancelEvent(int32_t eventSource, CancelationOptions options);
};
/* Manages the dispatch state associated with a single input channel. */
@@ -805,6 +835,13 @@
status_t initialize();
};
+ enum DropReason {
+ DROP_REASON_NOT_DROPPED = 0,
+ DROP_REASON_POLICY = 1,
+ DROP_REASON_APP_SWITCH = 2,
+ DROP_REASON_DISABLED = 3,
+ };
+
sp<InputDispatcherPolicyInterface> mPolicy;
Mutex mLock;
@@ -824,12 +861,16 @@
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
bool enqueueInboundEventLocked(EventEntry* entry);
+ // Cleans up input state when dropping an inbound event.
+ void dropInboundEventLocked(EventEntry* entry, DropReason dropReason);
+
// App switch latency optimization.
+ bool mAppSwitchSawKeyDown;
nsecs_t mAppSwitchDueTime;
- static bool isAppSwitchKey(int32_t keyCode);
+ static bool isAppSwitchKeyCode(int32_t keyCode);
+ bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry);
bool isAppSwitchPendingLocked();
- bool detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry);
void resetPendingAppSwitchLocked(bool handled);
// All registered connections mapped by receive pipe file descriptor.
@@ -851,7 +892,7 @@
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
- EventEntry* createEntryFromInjectedInputEventLocked(const InputEvent* event);
+ bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult);
Condition mInjectionSyncFinishedCondition;
@@ -886,7 +927,6 @@
void drainInboundQueueLocked();
void releasePendingEventLocked();
void releaseInboundEventLocked(EventEntry* entry);
- bool isEventFromReliableSourceLocked(EventEntry* entry);
// Dispatch state.
bool mDispatchEnabled;
@@ -933,10 +973,10 @@
nsecs_t currentTime, ConfigurationChangedEntry* entry);
bool dispatchKeyLocked(
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
- bool dropEvent, nsecs_t* nextWakeupTime);
+ DropReason* dropReason, nsecs_t* nextWakeupTime);
bool dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry,
- bool dropEvent, nsecs_t* nextWakeupTime);
+ DropReason* dropReason, nsecs_t* nextWakeupTime);
void dispatchEventToCurrentInputTargetsLocked(
nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
@@ -995,11 +1035,17 @@
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
- void abortDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- bool broken);
+ void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void drainOutboundQueueLocked(Connection* connection);
static int handleReceiveCallback(int receiveFd, int events, void* data);
+ void synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CancelationOptions options, const char* reason);
+ void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel,
+ InputState::CancelationOptions options, const char* reason);
+ void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection,
+ InputState::CancelationOptions options, const char* reason);
+
// Splitting motion events across windows.
MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds);
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index 3619189..c15e382 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -87,49 +87,12 @@
ROTATION_270 = 3
};
- /* Actions returned by interceptXXX methods. */
- enum {
- // The input dispatcher should do nothing and discard the input unless other
- // flags are set.
- ACTION_NONE = 0,
-
- // The input dispatcher should dispatch the input to the application.
- ACTION_DISPATCH = 0x00000001,
- };
-
/* Gets information about the display with the specified id.
* Returns true if the display info is available, false otherwise.
*/
virtual bool getDisplayInfo(int32_t displayId,
int32_t* width, int32_t* height, int32_t* orientation) = 0;
- /* Intercepts a key event.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * Returns a policy action constant such as ACTION_DISPATCH.
- */
- virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) = 0;
-
- /* Intercepts a switch event.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * Switches are not dispatched to applications so this method should
- * usually return ACTION_NONE.
- */
- virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
- uint32_t& policyFlags) = 0;
-
- /* Intercepts a generic touch, trackball or other event.
- * The policy can use this method as an opportunity to perform power management functions
- * and early event preprocessing such as updating policy flags.
- *
- * Returns a policy action constant such as ACTION_DISPATCH.
- */
- virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags) = 0;
-
/* Determines whether to turn on some hacks we have to improve the touch interaction with a
* certain device whose screen currently is not all that good.
*/
@@ -403,8 +366,6 @@
protected:
InputDevice* mDevice;
InputReaderContext* mContext;
-
- bool applyStandardPolicyActions(nsecs_t when, int32_t policyActions);
};
@@ -466,8 +427,6 @@
void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
uint32_t policyFlags);
- void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags,
- bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime);
ssize_t findKeyDownLocked(int32_t scanCode);
};
@@ -525,8 +484,6 @@
void initializeLocked();
void sync(nsecs_t when);
- void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
- PointerCoords* pointerCoords, nsecs_t downTime);
};
@@ -829,10 +786,6 @@
BitSet32 idBits, uint32_t changedId, uint32_t pointerCount,
int32_t motionEventAction);
- void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags,
- int32_t keyCode, int32_t scanCode, nsecs_t downTime);
-
bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5b226b4..57de43a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -43,6 +43,9 @@
#define RAD_TO_DEG (180.0f / 3.14159265f)
#define MIN_ANGLE 0.001f
+// TODO: This should be set in properties
+#define ALPHA_THRESHOLD (0x7f / PANEL_BIT_DEPTH)
+
///////////////////////////////////////////////////////////////////////////////
// Globals
///////////////////////////////////////////////////////////////////////////////
@@ -294,7 +297,9 @@
mode = SkXfermode::kSrcOver_Mode;
}
- createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo);
+ if (!mSnapshot->previous->invisible) {
+ createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags, previousFbo);
+ }
return count;
}
@@ -380,6 +385,14 @@
if (bounds.isEmpty() || bounds.getWidth() > mMaxTextureSize ||
bounds.getHeight() > mMaxTextureSize) {
+ snapshot->invisible = true;
+ } else {
+ // TODO: Should take the mode into account
+ snapshot->invisible = snapshot->previous->invisible || alpha <= ALPHA_THRESHOLD;
+ }
+
+ // Bail out if we won't draw in this snapshot
+ if (snapshot->invisible) {
return false;
}
@@ -536,7 +549,7 @@
}
void OpenGLRenderer::clearLayerRegions() {
- if (mLayers.size() == 0) return;
+ if (mLayers.size() == 0 || mSnapshot->invisible) return;
for (uint32_t i = 0; i < mLayers.size(); i++) {
Rect* bounds = mLayers.itemAt(i);
@@ -598,6 +611,10 @@
}
bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
+ if (mSnapshot->invisible) {
+ return true;
+ }
+
Rect r(left, top, right, bottom);
mSnapshot->transform->mapRect(r);
return !mSnapshot->clipRect->intersects(r);
@@ -703,6 +720,8 @@
}
void OpenGLRenderer::drawLines(float* points, int count, const SkPaint* paint) {
+ if (mSnapshot->invisible) return;
+
int alpha;
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
@@ -802,6 +821,7 @@
if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
return;
}
+ if (mSnapshot->invisible) return;
paint->setAntiAlias(true);
@@ -866,6 +886,8 @@
}
void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) {
+ if (mSnapshot->invisible) return;
+
GLuint textureUnit = 0;
glActiveTexture(gTextureUnits[textureUnit]);
@@ -985,6 +1007,7 @@
ProgramDescription description;
description.hasTexture = true;
description.hasAlpha8Texture = true;
+ const bool setColor = description.setAlpha8Color(r, g, b, a);
if (applyFilters) {
if (mShader) {
@@ -1021,7 +1044,9 @@
mModelView.loadIdentity();
}
mCaches.currentProgram->set(mOrthoMatrix, mModelView, *mSnapshot->transform);
- glUniform4f(mCaches.currentProgram->color, r, g, b, a);
+ if (setColor) {
+ mCaches.currentProgram->setColor(r, g, b, a);
+ }
textureUnit++;
if (applyFilters) {
@@ -1126,6 +1151,8 @@
// Describe the required shaders
ProgramDescription description;
+ const bool setColor = description.setColor(r, g, b, a);
+
if (mShader) {
mShader->describe(description, mExtensions);
}
@@ -1152,7 +1179,7 @@
mat4 identity;
mCaches.currentProgram->set(mOrthoMatrix, mModelView, identity);
}
- glUniform4f(mCaches.currentProgram->color, r, g, b, a);
+ mCaches.currentProgram->setColor(r, g, b, a);
// Setup attributes and uniforms required by the shaders
if (mShader) {
@@ -1189,6 +1216,7 @@
ProgramDescription description;
description.hasTexture = true;
+ const bool setColor = description.setColor(alpha, alpha, alpha, alpha);
if (mColorFilter) {
mColorFilter->describe(description, mExtensions);
}
@@ -1211,7 +1239,9 @@
glUniform1i(mCaches.currentProgram->getUniform("sampler"), 0);
// Always premultiplied
- glUniform4f(mCaches.currentProgram->color, alpha, alpha, alpha, alpha);
+ if (setColor) {
+ mCaches.currentProgram->setColor(alpha, alpha, alpha, alpha);
+ }
// Mesh
int texCoordsSlot = mCaches.currentProgram->getAttrib("texCoords");
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index 2e1b9a0..25674c6 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -58,7 +58,6 @@
mUse = false;
position = addAttrib("position");
- color = addUniform("color");
transform = addUniform("transform");
}
@@ -124,6 +123,10 @@
glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]);
}
+void Program::setColor(const float r, const float g, const float b, const float a) {
+ glUniform4f(getUniform("color"), r, g, b, a);
+}
+
void Program::use() {
glUseProgram(id);
mUse = true;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 6531c74..026097c 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -77,16 +77,16 @@
const mat4& transformMatrix);
/**
+ * Sets the color associated with this shader.
+ */
+ void setColor(const float r, const float g, const float b, const float a);
+
+ /**
* Name of the position attribute.
*/
int position;
/**
- * Name of the color uniform.
- */
- int color;
-
- /**
* Name of the transform uniform.
*/
int transform;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 439e6fb..1282b710 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -24,6 +24,14 @@
namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////
+
+#define MODULATE_OP_NO_MODULATE 0
+#define MODULATE_OP_MODULATE 1
+#define MODULATE_OP_MODULATE_A8 2
+
+///////////////////////////////////////////////////////////////////////////////
// Vertex shaders snippets
///////////////////////////////////////////////////////////////////////////////
@@ -50,7 +58,7 @@
"varying vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_HasGradient[3] = {
// Linear
- "varying float index;\n",
+ "varying vec2 linear;\n",
// Circular
"varying vec2 circular;\n",
// Sweep
@@ -62,15 +70,14 @@
" outTexCoords = texCoords;\n";
const char* gVS_Main_OutGradient[3] = {
// Linear
- " index = (screenSpace * position).x;\n",
+ " linear = vec2((screenSpace * position).x, 0.5);\n",
// Circular
" circular = (screenSpace * position).xy;\n",
// Sweep
" sweep = (screenSpace * position).xy;\n"
};
const char* gVS_Main_OutBitmapTexCoords =
- " vec4 bitmapCoords = textureTransform * position;\n"
- " outBitmapTexCoords = bitmapCoords.xy * textureDimension;\n";
+ " outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
const char* gVS_Main_Position =
" gl_Position = transform * position;\n";
const char* gVS_Footer =
@@ -113,15 +120,55 @@
const char* gFS_Main =
"\nvoid main(void) {\n"
" lowp vec4 fragColor;\n";
+
+// Fast cases
+const char* gFS_Fast_SingleColor =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = color;\n"
+ "}\n\n";
+const char* gFS_Fast_SingleTexture =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = texture2D(sampler, outTexCoords);\n"
+ "}\n\n";
+const char* gFS_Fast_SingleModulateTexture =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = color.a * texture2D(sampler, outTexCoords);\n"
+ "}\n\n";
+const char* gFS_Fast_SingleA8Texture =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n"
+ "}\n\n";
+const char* gFS_Fast_SingleModulateA8Texture =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = color * texture2D(sampler, outTexCoords).a;\n"
+ "}\n\n";
+const char* gFS_Fast_SingleGradient =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = texture2D(gradientSampler, linear);\n"
+ "}\n\n";
+const char* gFS_Fast_SingleModulateGradient =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = color.a * texture2D(gradientSampler, linear);\n"
+ "}\n\n";
+
+// General case
const char* gFS_Main_FetchColor =
" fragColor = color;\n";
-const char* gFS_Main_FetchTexture =
- " fragColor = color * texture2D(sampler, outTexCoords);\n";
-const char* gFS_Main_FetchA8Texture =
- " fragColor = color * texture2D(sampler, outTexCoords).a;\n";
+const char* gFS_Main_FetchTexture[2] = {
+ // Don't modulate
+ " fragColor = texture2D(sampler, outTexCoords);\n",
+ // Modulate
+ " fragColor = color * texture2D(sampler, outTexCoords);\n"
+};
+const char* gFS_Main_FetchA8Texture[2] = {
+ // Don't modulate
+ " fragColor = vec4(0.0, 0.0, 0.0, texture2D(sampler, outTexCoords).a);\n",
+ // Modulate
+ " fragColor = color * texture2D(sampler, outTexCoords).a;\n"
+};
const char* gFS_Main_FetchGradient[3] = {
// Linear
- " vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
+ " vec4 gradientColor = texture2D(gradientSampler, linear);\n",
// Circular
" float index = length(circular);\n"
" vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
@@ -137,12 +184,30 @@
" fragColor = blendShaders(gradientColor, bitmapColor)";
const char* gFS_Main_BlendShadersGB =
" fragColor = blendShaders(bitmapColor, gradientColor)";
-const char* gFS_Main_BlendShaders_Modulate =
- " * fragColor.a;\n";
-const char* gFS_Main_GradientShader_Modulate =
- " fragColor = gradientColor * fragColor.a;\n";
-const char* gFS_Main_BitmapShader_Modulate =
- " fragColor = bitmapColor * fragColor.a;\n";
+const char* gFS_Main_BlendShaders_Modulate[3] = {
+ // Don't modulate
+ ";\n",
+ // Modulate
+ " * fragColor.a;\n",
+ // Modulate with alpha 8 texture
+ " * texture2D(sampler, outTexCoords).a;\n"
+};
+const char* gFS_Main_GradientShader_Modulate[3] = {
+ // Don't modulate
+ " fragColor = gradientColor;\n",
+ // Modulate
+ " fragColor = gradientColor * fragColor.a;\n",
+ // Modulate with alpha 8 texture
+ " fragColor = gradientColor * texture2D(sampler, outTexCoords).a;\n"
+ };
+const char* gFS_Main_BitmapShader_Modulate[3] = {
+ // Don't modulate
+ " fragColor = bitmapColor;\n",
+ // Modulate
+ " fragColor = bitmapColor * fragColor.a;\n",
+ // Modulate with alpha 8 texture
+ " fragColor = bitmapColor * texture2D(sampler, outTexCoords).a;\n"
+ };
const char* gFS_Main_FragColor =
" gl_FragColor = fragColor;\n";
const char* gFS_Main_FragColor_Blend =
@@ -317,7 +382,7 @@
// Set the default precision
String8 shader;
- bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
+ const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
if (blendFramebuffer) {
shader.append(gFS_Header_Extension_FramebufferFetch);
}
@@ -335,15 +400,72 @@
shader.append(gVS_Header_Varyings_HasBitmap);
}
-
// Uniforms
- shader.append(gFS_Uniforms_Color);
+ int modulateOp = MODULATE_OP_NO_MODULATE;
+ const bool singleColor = !description.hasTexture &&
+ !description.hasGradient && !description.hasBitmap;
+
+ if (description.modulate || singleColor) {
+ shader.append(gFS_Uniforms_Color);
+ if (!singleColor) modulateOp = MODULATE_OP_MODULATE;
+ }
if (description.hasTexture) {
shader.append(gFS_Uniforms_TextureSampler);
}
if (description.hasGradient) {
shader.append(gFS_Uniforms_GradientSampler[description.gradientType]);
}
+
+ // Optimization for common cases
+ if (!blendFramebuffer) {
+ bool fast = false;
+
+ const bool noShader = !description.hasGradient && !description.hasBitmap;
+ const bool singleTexture = description.hasTexture &&
+ !description.hasAlpha8Texture && noShader;
+ const bool singleA8Texture = description.hasTexture &&
+ description.hasAlpha8Texture && noShader;
+ const bool singleGradient = !description.hasTexture &&
+ description.hasGradient && !description.hasBitmap &&
+ description.gradientType == ProgramDescription::kGradientLinear;
+
+ if (singleColor) {
+ shader.append(gFS_Fast_SingleColor);
+ fast = true;
+ } else if (singleTexture) {
+ if (!description.modulate) {
+ shader.append(gFS_Fast_SingleTexture);
+ } else {
+ shader.append(gFS_Fast_SingleModulateTexture);
+ }
+ fast = true;
+ } else if (singleA8Texture) {
+ if (!description.modulate) {
+ shader.append(gFS_Fast_SingleA8Texture);
+ } else {
+ shader.append(gFS_Fast_SingleModulateA8Texture);
+ }
+ fast = true;
+ } else if (singleGradient) {
+ if (!description.modulate) {
+ shader.append(gFS_Fast_SingleGradient);
+ } else {
+ shader.append(gFS_Fast_SingleModulateGradient);
+ }
+ fast = true;
+ }
+
+ if (fast) {
+ if (DEBUG_PROGRAM_CACHE) {
+ PROGRAM_LOGD("*** Fast case:\n");
+ PROGRAM_LOGD("*** Generated fragment shader:\n\n");
+ printLongString(shader);
+ }
+
+ return shader;
+ }
+ }
+
if (description.hasBitmap) {
shader.append(gFS_Uniforms_BitmapSampler);
}
@@ -368,12 +490,16 @@
// Stores the result in fragColor directly
if (description.hasTexture) {
if (description.hasAlpha8Texture) {
- shader.append(gFS_Main_FetchA8Texture);
+ if (!description.hasGradient && !description.hasBitmap) {
+ shader.append(gFS_Main_FetchA8Texture[modulateOp]);
+ }
} else {
- shader.append(gFS_Main_FetchTexture);
+ shader.append(gFS_Main_FetchTexture[modulateOp]);
}
} else {
- shader.append(gFS_Main_FetchColor);
+ if ((!description.hasGradient && !description.hasBitmap) || description.modulate) {
+ shader.append(gFS_Main_FetchColor);
+ }
}
if (description.hasGradient) {
shader.append(gFS_Main_FetchGradient[description.gradientType]);
@@ -387,17 +513,20 @@
}
// Case when we have two shaders set
if (description.hasGradient && description.hasBitmap) {
+ int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
if (description.isBitmapFirst) {
shader.append(gFS_Main_BlendShadersBG);
} else {
shader.append(gFS_Main_BlendShadersGB);
}
- shader.append(gFS_Main_BlendShaders_Modulate);
+ shader.append(gFS_Main_BlendShaders_Modulate[op]);
} else {
if (description.hasGradient) {
- shader.append(gFS_Main_GradientShader_Modulate);
+ int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
+ shader.append(gFS_Main_GradientShader_Modulate[op]);
} else if (description.hasBitmap) {
- shader.append(gFS_Main_BitmapShader_Modulate);
+ int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
+ shader.append(gFS_Main_BitmapShader_Modulate[op]);
}
}
// Apply the color op if needed
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 4fa8011..ec9851e 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -44,6 +44,11 @@
#define PROGRAM_LOGD(...)
#endif
+// TODO: This should be set in properties
+#define PANEL_BIT_DEPTH 20
+#define COLOR_COMPONENT_THRESHOLD (1.0f - (0.5f / PANEL_BIT_DEPTH))
+#define COLOR_COMPONENT_INV_THRESHOLD (0.5f / PANEL_BIT_DEPTH)
+
#define PROGRAM_KEY_TEXTURE 0x1
#define PROGRAM_KEY_A8_TEXTURE 0x2
#define PROGRAM_KEY_BITMAP 0x4
@@ -68,6 +73,7 @@
#define PROGRAM_BITMAP_WRAPT_SHIFT 11
#define PROGRAM_GRADIENT_TYPE_SHIFT 33
+#define PROGRAM_MODULATE 35
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -99,7 +105,7 @@
};
ProgramDescription():
- hasTexture(false), hasAlpha8Texture(false),
+ hasTexture(false), hasAlpha8Texture(false), modulate(false),
hasBitmap(false), isBitmapNpot(false), hasGradient(false),
gradientType(kGradientLinear),
shadersMode(SkXfermode::kClear_Mode), isBitmapFirst(false),
@@ -112,6 +118,9 @@
bool hasTexture;
bool hasAlpha8Texture;
+ // Modulate, this should only be set when setColor() return true
+ bool modulate;
+
// Shaders
bool hasBitmap;
bool isBitmapNpot;
@@ -134,18 +143,31 @@
SkXfermode::Mode framebufferMode;
bool swapSrcDst;
- inline uint32_t getEnumForWrap(GLenum wrap) const {
- switch (wrap) {
- case GL_CLAMP_TO_EDGE:
- return 0;
- case GL_REPEAT:
- return 1;
- case GL_MIRRORED_REPEAT:
- return 2;
- }
- return 0;
+ /**
+ * Indicates, for a given color, whether color modulation is required in
+ * the fragment shader. When this method returns true, the program should
+ * be provided with a modulation color.
+ */
+ bool setColor(const float r, const float g, const float b, const float a) {
+ modulate = a < COLOR_COMPONENT_THRESHOLD || r < COLOR_COMPONENT_THRESHOLD ||
+ g < COLOR_COMPONENT_THRESHOLD || b < COLOR_COMPONENT_THRESHOLD;
+ return modulate;
}
+ /**
+ * Indicates, for a given color, whether color modulation is required in
+ * the fragment shader. When this method returns true, the program should
+ * be provided with a modulation color.
+ */
+ bool setAlpha8Color(const float r, const float g, const float b, const float a) {
+ modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
+ g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
+ return modulate;
+ }
+
+ /**
+ * Computes the unique key identifying this program.
+ */
programid key() const {
programid key = 0;
if (hasTexture) key |= PROGRAM_KEY_TEXTURE;
@@ -180,14 +202,32 @@
}
key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
if (swapSrcDst) key |= PROGRAM_KEY_SWAP_SRC_DST;
+ if (modulate) key |= programid(0x1) << PROGRAM_MODULATE;
return key;
}
+ /**
+ * Logs the specified message followed by the key identifying this program.
+ */
void log(const char* message) const {
programid k = key();
PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
uint32_t(k & 0xffffffff));
}
+
+private:
+ inline uint32_t getEnumForWrap(GLenum wrap) const {
+ switch (wrap) {
+ case GL_CLAMP_TO_EDGE:
+ return 0;
+ case GL_REPEAT:
+ return 1;
+ case GL_MIRRORED_REPEAT:
+ return 2;
+ }
+ return 0;
+ }
+
}; // struct ProgramDescription
/**
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 3d74b4c..35cdf6f 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -43,7 +43,7 @@
*/
class Snapshot: public LightRefBase<Snapshot> {
public:
- Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0) {
+ Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false) {
transform = &mTransformRoot;
clipRect = &mClipRectRoot;
}
@@ -53,8 +53,8 @@
* the previous snapshot.
*/
Snapshot(const sp<Snapshot>& s, int saveFlags):
- flags(0), previous(s), layer(NULL),
- fbo(s->fbo), viewport(s->viewport), height(s->height) {
+ flags(0), previous(s), layer(NULL), fbo(s->fbo),
+ invisible(s->invisible), viewport(s->viewport), height(s->height) {
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
mTransformRoot.load(*s->transform);
transform = &mTransformRoot;
@@ -212,6 +212,12 @@
GLuint fbo;
/**
+ * Indicates that this snapshot is invisible and nothing should be drawn
+ * inside it.
+ */
+ bool invisible;
+
+ /**
* Current viewport.
*/
Rect viewport;
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
index c1411656b..987bebe 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainView.java
@@ -52,7 +52,8 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
if (mRS == null) {
- mRS = createRenderScript(false);
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScript(sc);
mRS.contextSetSurface(w, h, holder.getSurface());
mRender = new FountainRS();
mRender.init(mRS, getResources(), w, h);
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
index b5592f0..81bd578 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java
@@ -128,7 +128,7 @@
}
private void loadImage() {
- mGridImage = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true);
+ mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true);
mGridImage.uploadToTexture(0);
mScript.set_gTGrid(mGridImage);
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
index 44a59b2..9457fd7 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SceneGraphView.java
@@ -53,7 +53,9 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
if (mRS == null) {
- mRS = createRenderScript(true);
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 24);
+ mRS = createRenderScript(sc);
mRS.contextSetSurface(w, h, holder.getSurface());
mRender = new SceneGraphRS();
mRender.init(mRS, getResources(), w, h);
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
index afbf30b..ccbecd8 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java
@@ -124,7 +124,7 @@
}
private void loadImage() {
- mGridImage = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true);
+ mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, Element.RGB_565(mRS), true);
mGridImage.uploadToTexture(0);
mScript.set_gTGrid(mGridImage);
diff --git a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
index 2574fdd..4253085 100644
--- a/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
+++ b/libs/rs/java/ModelViewer/src/com/android/modelviewer/SimpleModelView.java
@@ -53,7 +53,9 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
if (mRS == null) {
- mRS = createRenderScript(true);
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 24);
+ mRS = createRenderScript(sc);
mRS.contextSetSurface(w, h, holder.getSurface());
mRender = new SimpleModelRS();
mRender.init(mRS, getResources(), w, h);
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsListView.java b/libs/rs/java/Samples/src/com/android/samples/RsListView.java
index b98ea08..cd66fbb 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsListView.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsListView.java
@@ -53,7 +53,9 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
if (mRS == null) {
- mRS = createRenderScript(true);
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 24);
+ mRS = createRenderScript(sc);
mRS.contextSetSurface(w, h, holder.getSurface());
mRender = new RsListRS();
mRender.init(mRS, getResources(), w, h);
diff --git a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesView.java b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesView.java
index 5548de3..c434c09 100644
--- a/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesView.java
+++ b/libs/rs/java/Samples/src/com/android/samples/RsRenderStatesView.java
@@ -53,7 +53,9 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
if (mRS == null) {
- mRS = createRenderScript(true);
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 24);
+ mRS = createRenderScript(sc);
mRS.contextSetSurface(w, h, holder.getSurface());
mRender = new RsRenderStatesRS();
mRender.init(mRS, getResources(), w, h);
diff --git a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java
index b811d48..c65f8c6 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/RSTestView.java
@@ -52,7 +52,8 @@
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
super.surfaceChanged(holder, format, w, h);
if (mRS == null) {
- mRS = createRenderScript(false);
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScript(sc);
mRS.contextSetSurface(w, h, holder.getSurface());
mRender = new RSTestCore();
mRender.init(mRS, getResources(), w, h);
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java
index fb355dd..da995da 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/UT_primitives.java
@@ -27,13 +27,77 @@
mRes = res;
}
+ private boolean initializeGlobals(ScriptC_primitives s) {
+ float pF = s.get_floatTest();
+ if (pF != 1.99f) {
+ return false;
+ }
+ s.set_floatTest(2.99f);
+
+ double pD = s.get_doubleTest();
+ if (pD != 2.05) {
+ return false;
+ }
+ s.set_doubleTest(3.05);
+
+ byte pC = s.get_charTest();
+ if (pC != -8) {
+ return false;
+ }
+ s.set_charTest((byte)-16);
+
+ short pS = s.get_shortTest();
+ if (pS != -16) {
+ return false;
+ }
+ s.set_shortTest((short)-32);
+
+ int pI = s.get_intTest();
+ if (pI != -32) {
+ return false;
+ }
+ s.set_intTest(-64);
+
+ long pL = s.get_longTest();
+ if (pL != 17179869184l) {
+ return false;
+ }
+ s.set_longTest(17179869185l);
+
+ long puL = s.get_ulongTest();
+ if (puL != 4611686018427387904L) {
+ return false;
+ }
+ s.set_ulongTest(4611686018427387903L);
+
+
+ long pLL = s.get_longlongTest();
+ if (pLL != 68719476736L) {
+ return false;
+ }
+ s.set_longlongTest(68719476735L);
+
+ long pu64 = s.get_uint64_tTest();
+ if (pu64 != 117179869184l) {
+ return false;
+ }
+ s.set_uint64_tTest(117179869185l);
+
+ return true;
+ }
+
public void run() {
RenderScript pRS = RenderScript.create();
ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives, true);
pRS.mMessageCallback = mRsMessage;
- s.invoke_primitives_test(0, 0);
- pRS.finish();
- waitForMessage();
+ if (!initializeGlobals(s)) {
+ // initializeGlobals failed
+ result = -1;
+ } else {
+ s.invoke_primitives_test(0, 0);
+ pRS.finish();
+ waitForMessage();
+ }
pRS.destroy();
}
}
diff --git a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java
index c9d88a6..90bb8a3 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java
+++ b/libs/rs/java/tests/src/com/android/rs/test/UnitTest.java
@@ -55,16 +55,18 @@
protected RSMessage mRsMessage = new RSMessage() {
public void run() {
- switch (mID) {
- case RS_MSG_TEST_PASSED:
- result = 1;
- break;
- case RS_MSG_TEST_FAILED:
- result = -1;
- break;
- default:
- android.util.Log.v("RenderScript", "Unit test got unexpected message");
- return;
+ if (result == 0) {
+ switch (mID) {
+ case RS_MSG_TEST_PASSED:
+ result = 1;
+ break;
+ case RS_MSG_TEST_FAILED:
+ result = -1;
+ break;
+ default:
+ android.util.Log.v("RenderScript", "Unit test got unexpected message");
+ return;
+ }
}
if (mItem != null) {
diff --git a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs
index ac0dc12..351a8a5 100644
--- a/libs/rs/java/tests/src/com/android/rs/test/primitives.rs
+++ b/libs/rs/java/tests/src/com/android/rs/test/primitives.rs
@@ -14,24 +14,28 @@
uchar ucharTest = 8;
ushort ushortTest = 16;
uint uintTest = 32;
+ulong ulongTest = 4611686018427387904L;
int64_t int64_tTest = -17179869184l; // - 1 << 34
+uint64_t uint64_tTest = 117179869184l;
static bool test_primitive_types(uint32_t index) {
bool failed = false;
start();
- _RS_ASSERT(floatTest == 1.99f);
- _RS_ASSERT(doubleTest == 2.05);
- _RS_ASSERT(charTest == -8);
- _RS_ASSERT(shortTest == -16);
- _RS_ASSERT(intTest == -32);
- _RS_ASSERT(longTest == 17179869184l);
- _RS_ASSERT(longlongTest == 68719476736l);
+ _RS_ASSERT(floatTest == 2.99f);
+ _RS_ASSERT(doubleTest == 3.05);
+ _RS_ASSERT(charTest == -16);
+ _RS_ASSERT(shortTest == -32);
+ _RS_ASSERT(intTest == -64);
+ _RS_ASSERT(longTest == 17179869185l);
+ _RS_ASSERT(longlongTest == 68719476735l);
_RS_ASSERT(ucharTest == 8);
_RS_ASSERT(ushortTest == 16);
_RS_ASSERT(uintTest == 32);
+ _RS_ASSERT(ulongTest == 4611686018427387903L);
_RS_ASSERT(int64_tTest == -17179869184l);
+ _RS_ASSERT(uint64_tTest == 117179869185l);
float time = end(index);
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 0da637e..27bb006 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -127,6 +127,12 @@
ret RsAllocation
}
+AllocationUpdateFromBitmap {
+ param RsAllocation alloc
+ param RsElement srcFmt
+ param const void * data
+ }
+
AllocationCreateBitmapRef {
param RsType type
param void * bmpPtr
@@ -145,16 +151,6 @@
ret RsAllocation
}
-AllocationCreateFromBitmapBoxed {
- param uint32_t width
- param uint32_t height
- param RsElement dstFmt
- param RsElement srcFmt
- param bool genMips
- param const void * data
- ret RsAllocation
- }
-
AllocationUploadToTexture {
param RsAllocation alloc
@@ -348,6 +344,12 @@
param int value
}
+ScriptSetVarJ {
+ param RsScript s
+ param uint32_t slot
+ param int64_t value
+ }
+
ScriptSetVarF {
param RsScript s
param uint32_t slot
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 2e9e0b3..172d07d 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -26,6 +26,8 @@
#include <OpenGl/glext.h>
#endif
+#include "utils/StopWatch.h"
+
using namespace android;
using namespace android::renderscript;
@@ -150,6 +152,8 @@
return;
}
+ bool isFirstUpload = false;
+
if (!mTextureID) {
glGenTextures(1, &mTextureID);
@@ -162,6 +166,7 @@
mUploadDefered = true;
return;
}
+ isFirstUpload = true;
}
glBindTexture(GL_TEXTURE_2D, mTextureID);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
@@ -171,9 +176,15 @@
adapt.setLOD(lod+mTextureLOD);
uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
- glTexImage2D(GL_TEXTURE_2D, lod, format,
- adapt.getDimX(), adapt.getDimY(),
- 0, format, type, ptr);
+ if(isFirstUpload) {
+ glTexImage2D(GL_TEXTURE_2D, lod, format,
+ adapt.getDimX(), adapt.getDimY(),
+ 0, format, type, ptr);
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0,
+ adapt.getDimX(), adapt.getDimY(),
+ format, type, ptr);
+ }
}
if (mTextureGenMipmap) {
#ifndef ANDROID_RS_BUILD_FOR_HOST
@@ -751,6 +762,32 @@
return alloc;
}
+void rsi_AllocationUpdateFromBitmap(Context *rsc, RsAllocation va, RsElement _src, const void *data)
+{
+ Allocation *texAlloc = static_cast<Allocation *>(va);
+ const Element *src = static_cast<const Element *>(_src);
+ const Element *dst = texAlloc->getType()->getElement();
+ uint32_t w = texAlloc->getType()->getDimX();
+ uint32_t h = texAlloc->getType()->getDimY();
+ bool genMips = texAlloc->getType()->getDimLOD();
+
+ ElementConverter_t cvt = pickConverter(dst, src);
+ if (cvt) {
+ cvt(texAlloc->getPtr(), data, w * h);
+ if (genMips) {
+ Adapter2D adapt(rsc, texAlloc);
+ Adapter2D adapt2(rsc, texAlloc);
+ for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
+ adapt.setLOD(lod);
+ adapt2.setLOD(lod + 1);
+ mip(adapt2, adapt);
+ }
+ }
+ } else {
+ rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format");
+ }
+}
+
RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data)
{
const Element *src = static_cast<const Element *>(_src);
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 0b9e28c..2becab0 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -65,7 +65,7 @@
size_t total = 0;
for (size_t ct=0; ct < mFieldCount; ct++) {
- total += mFields[ct].e->mBits * mFields[ct].arraySize;;
+ total += mFields[ct].e->mBits * mFields[ct].arraySize;
}
return total;
}
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 50bca85..70e2619 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -50,6 +50,7 @@
uint32_t getFieldCount() const {return mFieldCount;}
const Element * getField(uint32_t idx) const {return mFields[idx].e.get();}
const char * getFieldName(uint32_t idx) const {return mFields[idx].name.string();}
+ uint32_t getFieldArraySize(uint32_t idx) const {return mFields[idx].arraySize;}
const Component & getComponent() const {return mComponent;}
RsDataType getType() const {return mComponent.getType();}
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index 0e76dae..c5632b5 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -66,7 +66,9 @@
memcpy(destPtr, val, len);
//LOGE("setVar f2 %f", ((const float *)destPtr)[0]);
} else {
- LOGE("Calling setVar on slot = %i which is null", slot);
+ //if (rsc->props.mLogScripts) {
+ LOGV("Calling setVar on slot = %i which is null", slot);
+ //}
}
}
@@ -113,6 +115,12 @@
s->setVar(slot, &value, sizeof(value));
}
+void rsi_ScriptSetVarJ(Context *rsc, RsScript vs, uint32_t slot, long long value)
+{
+ Script *s = static_cast<Script *>(vs);
+ s->setVar(slot, &value, sizeof(value));
+}
+
void rsi_ScriptSetVarF(Context *rsc, RsScript vs, uint32_t slot, float value)
{
Script *s = static_cast<Script *>(vs);
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index d961fed..e60255a 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -81,7 +81,9 @@
if (dest) {
*dest = ptr;
} else {
- LOGE("ScriptC::setupScript, NULL var binding address.");
+ if (rsc->props.mLogScripts) {
+ LOGV("ScriptC::setupScript, NULL var binding address.");
+ }
}
}
}
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 33776c3..e0716eb 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -149,13 +149,37 @@
return offset;
}
+bool Type::isValidGLComponent(uint32_t fieldIdx) {
+ // Do not create attribs for padding
+ if(mElement->getFieldName(fieldIdx)[0] == '#') {
+ return false;
+ }
+
+ // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
+ // Filter rs types accordingly
+ RsDataType dt = mElement->getField(fieldIdx)->getComponent().getType();
+ if(dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
+ dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
+ dt != RS_TYPE_SIGNED_16) {
+ return false;
+ }
+
+ // Now make sure they are not arrays
+ uint32_t arraySize = mElement->getFieldArraySize(fieldIdx);
+ if(arraySize != 1) {
+ return false;
+ }
+
+ return true;
+}
void Type::makeGLComponents()
{
// Count the number of gl attrs to initialize
mAttribsSize = 0;
- for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
- if(getElement()->getFieldName(ct)[0] != '#') {
+
+ for (uint32_t ct=0; ct < mElement->getFieldCount(); ct++) {
+ if(isValidGLComponent(ct)) {
mAttribsSize ++;
}
}
@@ -168,10 +192,10 @@
}
uint32_t userNum = 0;
- for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
- const Component &c = getElement()->getField(ct)->getComponent();
+ for (uint32_t ct=0; ct < mElement->getFieldCount(); ct++) {
+ const Component &c = mElement->getField(ct)->getComponent();
- if(getElement()->getFieldName(ct)[0] == '#') {
+ if(!isValidGLComponent(ct)) {
continue;
}
@@ -180,7 +204,7 @@
mAttribs[userNum].type = c.getGLType();
mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
String8 tmp(RS_SHADER_ATTR);
- tmp.append(getElement()->getFieldName(ct));
+ tmp.append(mElement->getFieldName(ct));
mAttribs[userNum].name.setTo(tmp.string());
userNum ++;
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 9099bf1..891edd4 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -121,6 +121,7 @@
VertexArray::Attrib *mAttribs;
uint32_t mAttribsSize;
+ bool isValidGLComponent(uint32_t fieldIdx);
void makeGLComponents();
private:
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 75b2294..52e488a 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -95,16 +95,19 @@
return true;
}
-static bool isValidMotionAction(int32_t action) {
+static bool isValidMotionAction(int32_t action, size_t pointerCount) {
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_MOVE:
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_OUTSIDE:
return true;
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
+ case AMOTION_EVENT_ACTION_POINTER_UP: {
+ int32_t index = getMotionEventActionPointerIndex(action);
+ return index >= 0 && size_t(index) < pointerCount;
+ }
default:
return false;
}
@@ -112,7 +115,7 @@
static bool validateMotionEvent(int32_t action, size_t pointerCount,
const int32_t* pointerIds) {
- if (! isValidMotionAction(action)) {
+ if (! isValidMotionAction(action, pointerCount)) {
LOGE("Motion event has invalid action code 0x%x", action);
return false;
}
@@ -235,16 +238,6 @@
resetKeyRepeatLocked();
}
- // If dispatching is disabled, drop all events in the queue.
- if (! mDispatchEnabled) {
- if (mPendingEvent || ! mInboundQueue.isEmpty()) {
- LOGI("Dropping pending events because input dispatch is disabled.");
- releasePendingEventLocked();
- drainInboundQueueLocked();
- }
- return;
- }
-
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
#if DEBUG_FOCUS
@@ -294,7 +287,11 @@
// samples may be appended to this event by the time the throttling timeout
// expires.
// TODO Make this smarter and consider throttling per device independently.
- if (entry->type == EventEntry::TYPE_MOTION) {
+ if (entry->type == EventEntry::TYPE_MOTION
+ && !isAppSwitchDue
+ && mDispatchEnabled
+ && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
+ && !entry->isInjected()) {
MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
int32_t deviceId = motionEntry->deviceId;
uint32_t source = motionEntry->source;
@@ -347,39 +344,43 @@
// Now we have an event to dispatch.
assert(mPendingEvent != NULL);
bool done = false;
+ DropReason dropReason = DROP_REASON_NOT_DROPPED;
+ if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
+ dropReason = DROP_REASON_POLICY;
+ } else if (!mDispatchEnabled) {
+ dropReason = DROP_REASON_DISABLED;
+ }
switch (mPendingEvent->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
+ dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
- bool appSwitchKey = isAppSwitchKey(typedEntry->keyCode);
- bool dropEvent = isAppSwitchDue && ! appSwitchKey;
- done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout, dropEvent,
- nextWakeupTime);
- if (done) {
- if (dropEvent) {
- LOGI("Dropped key because of pending overdue app switch.");
- } else if (appSwitchKey) {
+ if (isAppSwitchDue) {
+ if (isAppSwitchKeyEventLocked(typedEntry)) {
resetPendingAppSwitchLocked(true);
+ isAppSwitchDue = false;
+ } else if (dropReason == DROP_REASON_NOT_DROPPED) {
+ dropReason = DROP_REASON_APP_SWITCH;
}
}
+ done = dispatchKeyLocked(currentTime, typedEntry, keyRepeatTimeout,
+ &dropReason, nextWakeupTime);
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
- bool dropEvent = isAppSwitchDue;
- done = dispatchMotionLocked(currentTime, typedEntry, dropEvent, nextWakeupTime);
- if (done) {
- if (dropEvent) {
- LOGI("Dropped motion because of pending overdue app switch.");
- }
+ if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
+ dropReason = DROP_REASON_APP_SWITCH;
}
+ done = dispatchMotionLocked(currentTime, typedEntry,
+ &dropReason, nextWakeupTime);
break;
}
@@ -389,6 +390,10 @@
}
if (done) {
+ if (dropReason != DROP_REASON_NOT_DROPPED) {
+ dropInboundEventLocked(mPendingEvent, dropReason);
+ }
+
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
@@ -399,36 +404,86 @@
mInboundQueue.enqueueAtTail(entry);
switch (entry->type) {
- case EventEntry::TYPE_KEY:
- needWake |= detectPendingAppSwitchLocked(static_cast<KeyEntry*>(entry));
+ case EventEntry::TYPE_KEY: {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
+ if (isAppSwitchKeyEventLocked(keyEntry)) {
+ if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
+ mAppSwitchSawKeyDown = true;
+ } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+ if (mAppSwitchSawKeyDown) {
+#if DEBUG_APP_SWITCH
+ LOGD("App switch is pending!");
+#endif
+ mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
+ mAppSwitchSawKeyDown = false;
+ needWake = true;
+ }
+ }
+ }
break;
}
+ }
return needWake;
}
-bool InputDispatcher::isAppSwitchKey(int32_t keyCode) {
+void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
+ const char* reason;
+ switch (dropReason) {
+ case DROP_REASON_POLICY:
+#if DEBUG_INBOUND_EVENT_DETAILS
+ LOGD("Dropped event because policy requested that it not be delivered to the application.");
+#endif
+ reason = "inbound event was dropped because the policy requested that it not be "
+ "delivered to the application";
+ break;
+ case DROP_REASON_DISABLED:
+ LOGI("Dropped event because input dispatch is disabled.");
+ reason = "inbound event was dropped because input dispatch is disabled";
+ break;
+ case DROP_REASON_APP_SWITCH:
+ LOGI("Dropped event because of pending overdue app switch.");
+ reason = "inbound event was dropped because of pending overdue app switch";
+ break;
+ default:
+ assert(false);
+ return;
+ }
+
+ switch (entry->type) {
+ case EventEntry::TYPE_KEY:
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_NON_POINTER_EVENTS, reason);
+ break;
+ case EventEntry::TYPE_MOTION: {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
+ if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_POINTER_EVENTS, reason);
+ } else {
+ synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CANCEL_NON_POINTER_EVENTS, reason);
+ }
+ break;
+ }
+ }
+}
+
+bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) {
return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL;
}
+bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) {
+ return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
+ && isAppSwitchKeyCode(keyEntry->keyCode)
+ && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED)
+ && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER);
+}
+
bool InputDispatcher::isAppSwitchPendingLocked() {
return mAppSwitchDueTime != LONG_LONG_MAX;
}
-bool InputDispatcher::detectPendingAppSwitchLocked(KeyEntry* inboundKeyEntry) {
- if (inboundKeyEntry->action == AKEY_EVENT_ACTION_UP
- && ! (inboundKeyEntry->flags & AKEY_EVENT_FLAG_CANCELED)
- && isAppSwitchKey(inboundKeyEntry->keyCode)
- && isEventFromReliableSourceLocked(inboundKeyEntry)) {
-#if DEBUG_APP_SWITCH
- LOGD("App switch is pending!");
-#endif
- mAppSwitchDueTime = inboundKeyEntry->eventTime + APP_SWITCH_TIMEOUT;
- return true; // need wake
- }
- return false;
-}
-
void InputDispatcher::resetPendingAppSwitchLocked(bool handled) {
mAppSwitchDueTime = LONG_LONG_MAX;
@@ -489,14 +544,6 @@
mAllocator.releaseEventEntry(entry);
}
-bool InputDispatcher::isEventFromReliableSourceLocked(EventEntry* entry) {
- InjectionState* injectionState = entry->injectionState;
- return ! injectionState
- || injectionState->injectorUid == 0
- || mPolicy->checkInjectEventsPermissionNonReentrant(
- injectionState->injectorPid, injectionState->injectorUid);
-}
-
void InputDispatcher::resetKeyRepeatLocked() {
if (mKeyRepeatState.lastKeyEntry) {
mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry);
@@ -509,7 +556,8 @@
KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
// Reuse the repeated key entry if it is otherwise unreferenced.
- uint32_t policyFlags = entry->policyFlags & POLICY_FLAG_RAW_MASK;
+ uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK)
+ | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED;
if (entry->refCount == 1) {
mAllocator.recycleKeyEntry(entry);
entry->eventTime = currentTime;
@@ -558,19 +606,13 @@
bool InputDispatcher::dispatchKeyLocked(
nsecs_t currentTime, KeyEntry* entry, nsecs_t keyRepeatTimeout,
- bool dropEvent, nsecs_t* nextWakeupTime) {
+ DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
- bool trusted;
- if (! dropEvent && mFocusedWindow) {
- trusted = checkInjectionPermission(mFocusedWindow, entry->injectionState);
- } else {
- trusted = isEventFromReliableSourceLocked(entry);
- }
- if (trusted) {
+ if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
- if (! dropEvent && mFocusedWindow) {
+ if (mFocusedWindow) {
commandEntry->inputChannel = mFocusedWindow->inputChannel;
}
commandEntry->keyEntry = entry;
@@ -580,13 +622,16 @@
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
+ if (*dropReason == DROP_REASON_NOT_DROPPED) {
+ *dropReason = DROP_REASON_POLICY;
+ }
resetTargetsLocked();
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_SUCCEEDED);
return true;
}
// Clean up if dropping the event.
- if (dropEvent) {
+ if (*dropReason != DROP_REASON_NOT_DROPPED) {
resetTargetsLocked();
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
return true;
@@ -598,7 +643,8 @@
if (entry->repeatCount == 0
&& entry->action == AKEY_EVENT_ACTION_DOWN
- && ! entry->isInjected()) {
+ && (entry->policyFlags & POLICY_FLAG_TRUSTED)
+ && !entry->isInjected()) {
if (mKeyRepeatState.lastKeyEntry
&& mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
// We have seen two identical key downs in a row which indicates that the device
@@ -663,9 +709,9 @@
}
bool InputDispatcher::dispatchMotionLocked(
- nsecs_t currentTime, MotionEntry* entry, bool dropEvent, nsecs_t* nextWakeupTime) {
+ nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Clean up if dropping the event.
- if (dropEvent) {
+ if (*dropReason != DROP_REASON_NOT_DROPPED) {
resetTargetsLocked();
setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
return true;
@@ -793,9 +839,11 @@
prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
resumeWithAppendedMotionSample);
} else {
- LOGW("Framework requested delivery of an input event to channel '%s' but it "
- "is not registered with the input dispatcher.",
+#if DEBUG_FOCUS
+ LOGD("Dropping event delivery to target with channel '%s' because it "
+ "is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().string());
+#endif
}
}
}
@@ -876,7 +924,9 @@
ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- connection->inputState.setOutOfSync();
+ synthesizeCancelationEventsForConnectionLocked(
+ connection, InputState::CANCEL_ALL_EVENTS,
+ "application not responding");
}
}
}
@@ -1236,7 +1286,9 @@
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
if (mTouchState.down) {
- LOGW("Pointer down received while already down.");
+#if DEBUG_FOCUS
+ LOGD("Pointer down received while already down.");
+#endif
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
// One pointer went up.
@@ -1307,23 +1359,19 @@
bool InputDispatcher::checkInjectionPermission(const InputWindow* window,
const InjectionState* injectionState) {
if (injectionState
- && injectionState->injectorUid > 0
- && (window == NULL || window->ownerUid != injectionState->injectorUid)) {
- bool result = mPolicy->checkInjectEventsPermissionNonReentrant(
- injectionState->injectorPid, injectionState->injectorUid);
- if (! result) {
- if (window) {
- LOGW("Permission denied: injecting event from pid %d uid %d to window "
- "with input channel %s owned by uid %d",
- injectionState->injectorPid, injectionState->injectorUid,
- window->inputChannel->getName().string(),
- window->ownerUid);
- } else {
- LOGW("Permission denied: injecting event from pid %d uid %d",
- injectionState->injectorPid, injectionState->injectorUid);
- }
- return false;
+ && (window == NULL || window->ownerUid != injectionState->injectorUid)
+ && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
+ if (window) {
+ LOGW("Permission denied: injecting event from pid %d uid %d to window "
+ "with input channel %s owned by uid %d",
+ injectionState->injectorPid, injectionState->injectorUid,
+ window->inputChannel->getName().string(),
+ window->ownerUid);
+ } else {
+ LOGW("Permission denied: injecting event from pid %d uid %d",
+ injectionState->injectorPid, injectionState->injectorUid);
}
+ return false;
}
return true;
}
@@ -1408,8 +1456,10 @@
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
- LOGW("channel '%s' ~ Dropping event because the channel status is %s",
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ Dropping event because the channel status is %s",
connection->getInputChannelName(), connection->getStatusLabel());
+#endif
return;
}
@@ -1508,40 +1558,6 @@
}
}
- // Bring the input state back in line with reality in case it drifted off during an ANR.
- if (connection->inputState.isOutOfSync()) {
- mTempCancelationEvents.clear();
- connection->inputState.synthesizeCancelationEvents(& mAllocator, mTempCancelationEvents);
- connection->inputState.resetOutOfSync();
-
- if (! mTempCancelationEvents.isEmpty()) {
- LOGI("channel '%s' ~ Generated %d cancelation events to bring channel back in sync "
- "with reality.",
- connection->getInputChannelName(), mTempCancelationEvents.size());
-
- for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
- EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
- switch (cancelationEventEntry->type) {
- case EventEntry::TYPE_KEY:
- logOutboundKeyDetailsLocked(" ",
- static_cast<KeyEntry*>(cancelationEventEntry));
- break;
- case EventEntry::TYPE_MOTION:
- logOutboundMotionDetailsLocked(" ",
- static_cast<MotionEntry*>(cancelationEventEntry));
- break;
- }
-
- DispatchEntry* cancelationDispatchEntry =
- mAllocator.obtainDispatchEntry(cancelationEventEntry,
- 0, inputTarget->xOffset, inputTarget->yOffset); // increments ref
- connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
-
- mAllocator.releaseEventEntry(cancelationEventEntry);
- }
- }
- }
-
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref
@@ -1635,7 +1651,7 @@
if (status) {
LOGE("channel '%s' ~ Could not publish key event, "
"status=%d", connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
break;
@@ -1685,7 +1701,7 @@
if (status) {
LOGE("channel '%s' ~ Could not publish motion event, "
"status=%d", connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
@@ -1706,7 +1722,7 @@
LOGE("channel '%s' ~ Could not append motion sample "
"for a reason other than out of memory, status=%d",
connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
}
@@ -1727,7 +1743,7 @@
if (status) {
LOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
@@ -1764,7 +1780,7 @@
if (status) {
LOGE("channel '%s' ~ Could not reset publisher, status=%d",
connection->getInputChannelName(), status);
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
return;
}
@@ -1806,28 +1822,23 @@
deactivateConnectionLocked(connection.get());
}
-void InputDispatcher::abortDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, bool broken) {
+void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
+ const sp<Connection>& connection) {
#if DEBUG_DISPATCH_CYCLE
- LOGD("channel '%s' ~ abortDispatchCycle - broken=%s",
+ LOGD("channel '%s' ~ abortBrokenDispatchCycle - broken=%s",
connection->getInputChannelName(), toString(broken));
#endif
- // Input state will no longer be realistic.
- connection->inputState.setOutOfSync();
-
// Clear the outbound queue.
drainOutboundQueueLocked(connection.get());
- // Handle the case where the connection appears to be unrecoverably broken.
+ // The connection appears to be unrecoverably broken.
// Ignore already broken or zombie connections.
- if (broken) {
- if (connection->status == Connection::STATUS_NORMAL) {
- connection->status = Connection::STATUS_BROKEN;
+ if (connection->status == Connection::STATUS_NORMAL) {
+ connection->status = Connection::STATUS_BROKEN;
- // Notify other system components.
- onDispatchCycleBrokenLocked(currentTime, connection);
- }
+ // Notify other system components.
+ onDispatchCycleBrokenLocked(currentTime, connection);
}
}
@@ -1862,7 +1873,7 @@
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
LOGE("channel '%s' ~ Consumer closed input channel or an error occurred. "
"events=0x%x", connection->getInputChannelName(), events);
- d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ d->abortBrokenDispatchCycleLocked(currentTime, connection);
d->runCommandsLockedInterruptible();
return 0; // remove the callback
}
@@ -1877,7 +1888,7 @@
if (status) {
LOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
connection->getInputChannelName(), status);
- d->abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ d->abortBrokenDispatchCycleLocked(currentTime, connection);
d->runCommandsLockedInterruptible();
return 0; // remove the callback
}
@@ -1888,6 +1899,77 @@
} // release lock
}
+void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
+ InputState::CancelationOptions options, const char* reason) {
+ for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
+ synthesizeCancelationEventsForConnectionLocked(
+ mConnectionsByReceiveFd.valueAt(i), options, reason);
+ }
+}
+
+void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
+ const sp<InputChannel>& channel, InputState::CancelationOptions options,
+ const char* reason) {
+ ssize_t index = getConnectionIndexLocked(channel);
+ if (index >= 0) {
+ synthesizeCancelationEventsForConnectionLocked(
+ mConnectionsByReceiveFd.valueAt(index), options, reason);
+ }
+}
+
+void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
+ const sp<Connection>& connection, InputState::CancelationOptions options,
+ const char* reason) {
+ nsecs_t currentTime = now();
+
+ mTempCancelationEvents.clear();
+ connection->inputState.synthesizeCancelationEvents(currentTime, & mAllocator,
+ mTempCancelationEvents, options);
+
+ if (! mTempCancelationEvents.isEmpty()
+ && connection->status != Connection::STATUS_BROKEN) {
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
+ "with reality: %s, options=%d.",
+ connection->getInputChannelName(), mTempCancelationEvents.size(), reason, options);
+#endif
+ for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
+ EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
+ switch (cancelationEventEntry->type) {
+ case EventEntry::TYPE_KEY:
+ logOutboundKeyDetailsLocked("cancel - ",
+ static_cast<KeyEntry*>(cancelationEventEntry));
+ break;
+ case EventEntry::TYPE_MOTION:
+ logOutboundMotionDetailsLocked("cancel - ",
+ static_cast<MotionEntry*>(cancelationEventEntry));
+ break;
+ }
+
+ int32_t xOffset, yOffset;
+ const InputWindow* window = getWindowLocked(connection->inputChannel);
+ if (window) {
+ xOffset = -window->frameLeft;
+ yOffset = -window->frameTop;
+ } else {
+ xOffset = 0;
+ yOffset = 0;
+ }
+
+ DispatchEntry* cancelationDispatchEntry =
+ mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref
+ 0, xOffset, yOffset);
+ connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
+
+ mAllocator.releaseEventEntry(cancelationEventEntry);
+ }
+
+ if (!connection->outboundQueue.headSentinel.next->inProgress) {
+ startDispatchCycleLocked(currentTime, connection);
+ }
+ }
+}
+
InputDispatcher::MotionEntry*
InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) {
assert(pointerIds.value != 0);
@@ -1999,6 +2081,10 @@
return;
}
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
+ keyCode, scanCode, /*byref*/ policyFlags);
+
bool needWake;
{ // acquire lock
AutoMutex _l(mLock);
@@ -2041,6 +2127,9 @@
return;
}
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
+
bool needWake;
{ // acquire lock
AutoMutex _l(mLock);
@@ -2165,6 +2254,17 @@
}
}
+void InputDispatcher::notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
+ uint32_t policyFlags) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+ LOGD("notifySwitch - switchCode=%d, switchValue=%d, policyFlags=0x%x",
+ switchCode, switchValue, policyFlags);
+#endif
+
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ mPolicy->notifySwitch(when, switchCode, switchValue, policyFlags);
+}
+
int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis) {
#if DEBUG_INBOUND_EVENT_DETAILS
@@ -2175,26 +2275,81 @@
nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
- InjectionState* injectionState;
- bool needWake;
- { // acquire lock
- AutoMutex _l(mLock);
+ uint32_t policyFlags = POLICY_FLAG_INJECTED;
+ if (hasInjectionPermission(injectorPid, injectorUid)) {
+ policyFlags |= POLICY_FLAG_TRUSTED;
+ }
- EventEntry* injectedEntry = createEntryFromInjectedInputEventLocked(event);
- if (! injectedEntry) {
+ EventEntry* injectedEntry;
+ switch (event->getType()) {
+ case AINPUT_EVENT_TYPE_KEY: {
+ const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
+ int32_t action = keyEvent->getAction();
+ if (! validateKeyEvent(action)) {
return INPUT_EVENT_INJECTION_FAILED;
}
- injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid);
- if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
- injectionState->injectionIsAsync = true;
+ nsecs_t eventTime = keyEvent->getEventTime();
+ int32_t deviceId = keyEvent->getDeviceId();
+ int32_t flags = keyEvent->getFlags();
+ int32_t keyCode = keyEvent->getKeyCode();
+ int32_t scanCode = keyEvent->getScanCode();
+ mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
+ keyCode, scanCode, /*byref*/ policyFlags);
+
+ mLock.lock();
+ injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
+ policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(),
+ keyEvent->getRepeatCount(), keyEvent->getDownTime());
+ break;
+ }
+
+ case AINPUT_EVENT_TYPE_MOTION: {
+ const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
+ int32_t action = motionEvent->getAction();
+ size_t pointerCount = motionEvent->getPointerCount();
+ const int32_t* pointerIds = motionEvent->getPointerIds();
+ if (! validateMotionEvent(action, pointerCount, pointerIds)) {
+ return INPUT_EVENT_INJECTION_FAILED;
}
- injectionState->refCount += 1;
- injectedEntry->injectionState = injectionState;
+ nsecs_t eventTime = motionEvent->getEventTime();
+ mPolicy->interceptGenericBeforeQueueing(eventTime, /*byref*/ policyFlags);
- needWake = enqueueInboundEventLocked(injectedEntry);
- } // release lock
+ mLock.lock();
+ const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
+ const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
+ MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
+ motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+ action, motionEvent->getFlags(),
+ motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
+ motionEvent->getXPrecision(), motionEvent->getYPrecision(),
+ motionEvent->getDownTime(), uint32_t(pointerCount),
+ pointerIds, samplePointerCoords);
+ for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
+ sampleEventTimes += 1;
+ samplePointerCoords += pointerCount;
+ mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords);
+ }
+ injectedEntry = motionEntry;
+ break;
+ }
+
+ default:
+ LOGW("Cannot inject event of type %d", event->getType());
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
+
+ InjectionState* injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid);
+ if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) {
+ injectionState->injectionIsAsync = true;
+ }
+
+ injectionState->refCount += 1;
+ injectedEntry->injectionState = injectionState;
+
+ bool needWake = enqueueInboundEventLocked(injectedEntry);
+ mLock.unlock();
if (needWake) {
mLooper->wake();
@@ -2260,6 +2415,11 @@
return injectionResult;
}
+bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) {
+ return injectorUid == 0
+ || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
+}
+
void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) {
InjectionState* injectionState = entry->injectionState;
if (injectionState) {
@@ -2310,59 +2470,6 @@
}
}
-InputDispatcher::EventEntry* InputDispatcher::createEntryFromInjectedInputEventLocked(
- const InputEvent* event) {
- switch (event->getType()) {
- case AINPUT_EVENT_TYPE_KEY: {
- const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
- if (! validateKeyEvent(keyEvent->getAction())) {
- return NULL;
- }
-
- uint32_t policyFlags = POLICY_FLAG_INJECTED;
-
- KeyEntry* keyEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
- keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags,
- keyEvent->getAction(), keyEvent->getFlags(),
- keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
- keyEvent->getRepeatCount(), keyEvent->getDownTime());
- return keyEntry;
- }
-
- case AINPUT_EVENT_TYPE_MOTION: {
- const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event);
- if (! validateMotionEvent(motionEvent->getAction(),
- motionEvent->getPointerCount(), motionEvent->getPointerIds())) {
- return NULL;
- }
-
- uint32_t policyFlags = POLICY_FLAG_INJECTED;
-
- const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
- const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
- size_t pointerCount = motionEvent->getPointerCount();
-
- MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes,
- motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
- motionEvent->getAction(), motionEvent->getFlags(),
- motionEvent->getMetaState(), motionEvent->getEdgeFlags(),
- motionEvent->getXPrecision(), motionEvent->getYPrecision(),
- motionEvent->getDownTime(), uint32_t(pointerCount),
- motionEvent->getPointerIds(), samplePointerCoords);
- for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
- sampleEventTimes += 1;
- samplePointerCoords += pointerCount;
- mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords);
- }
- return motionEntry;
- }
-
- default:
- assert(false);
- return NULL;
- }
-}
-
const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) {
for (size_t i = 0; i < mWindows.size(); i++) {
const InputWindow* window = & mWindows[i];
@@ -2381,7 +2488,12 @@
AutoMutex _l(mLock);
// Clear old window pointers.
- mFocusedWindow = NULL;
+ sp<InputChannel> oldFocusedWindowChannel;
+ if (mFocusedWindow) {
+ oldFocusedWindowChannel = mFocusedWindow->inputChannel;
+ mFocusedWindow = NULL;
+ }
+
mWindows.clear();
// Loop over new windows and rebuild the necessary window pointers for
@@ -2397,6 +2509,24 @@
}
}
+ if (oldFocusedWindowChannel != NULL) {
+ if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) {
+#if DEBUG_FOCUS
+ LOGD("Focus left window: %s",
+ oldFocusedWindowChannel->getName().string());
+#endif
+ synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel,
+ InputState::CANCEL_NON_POINTER_EVENTS, "focus left window");
+ oldFocusedWindowChannel.clear();
+ }
+ }
+ if (mFocusedWindow && oldFocusedWindowChannel == NULL) {
+#if DEBUG_FOCUS
+ LOGD("Focus entered window: %s",
+ mFocusedWindow->inputChannel->getName().string());
+#endif
+ }
+
for (size_t i = 0; i < mTouchState.windows.size(); ) {
TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
const InputWindow* window = getWindowLocked(touchedWindow.channel);
@@ -2404,12 +2534,17 @@
touchedWindow.window = window;
i += 1;
} else {
+#if DEBUG_FOCUS
+ LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
+#endif
mTouchState.windows.removeAt(i);
+ synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel,
+ InputState::CANCEL_POINTER_EVENTS, "touched window was removed");
}
}
#if DEBUG_FOCUS
- logDispatchStateLocked();
+ //logDispatchStateLocked();
#endif
} // release lock
@@ -2432,7 +2567,7 @@
}
#if DEBUG_FOCUS
- logDispatchStateLocked();
+ //logDispatchStateLocked();
#endif
} // release lock
@@ -2469,7 +2604,7 @@
}
#if DEBUG_FOCUS
- logDispatchStateLocked();
+ //logDispatchStateLocked();
#endif
} // release lock
@@ -2533,6 +2668,18 @@
return false;
}
+ ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
+ ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
+ if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
+ sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
+ sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+
+ fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
+ synthesizeCancelationEventsForConnectionLocked(fromConnection,
+ InputState::CANCEL_POINTER_EVENTS,
+ "transferring touch focus from this window to another window");
+ }
+
#if DEBUG_FOCUS
logDispatchStateLocked();
#endif
@@ -2635,11 +2782,10 @@
for (size_t i = 0; i < mActiveConnections.size(); i++) {
const Connection* connection = mActiveConnections[i];
dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u"
- "inputState.isNeutral=%s, inputState.isOutOfSync=%s\n",
+ "inputState.isNeutral=%s\n",
i, connection->getInputChannelName(), connection->getStatusLabel(),
connection->outboundQueue.count(),
- toString(connection->inputState.isNeutral()),
- toString(connection->inputState.isOutOfSync()));
+ toString(connection->inputState.isNeutral()));
}
} else {
dump.append(INDENT "ActiveConnections: <none>\n");
@@ -2720,7 +2866,7 @@
mLooper->removeFd(inputChannel->getReceivePipeFd());
nsecs_t currentTime = now();
- abortDispatchCycleLocked(currentTime, connection, true /*broken*/);
+ abortBrokenDispatchCycleLocked(currentTime, connection);
runCommandsLockedInterruptible();
} // release lock
@@ -2901,11 +3047,12 @@
}
void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type,
- nsecs_t eventTime) {
+ nsecs_t eventTime, uint32_t policyFlags) {
entry->type = type;
entry->refCount = 1;
entry->dispatchInProgress = false;
entry->eventTime = eventTime;
+ entry->policyFlags = policyFlags;
entry->injectionState = NULL;
}
@@ -2919,7 +3066,7 @@
InputDispatcher::ConfigurationChangedEntry*
InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) {
ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc();
- initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime);
+ initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime, 0);
return entry;
}
@@ -2928,11 +3075,10 @@
int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
int32_t repeatCount, nsecs_t downTime) {
KeyEntry* entry = mKeyEntryPool.alloc();
- initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime);
+ initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime, policyFlags);
entry->deviceId = deviceId;
entry->source = source;
- entry->policyFlags = policyFlags;
entry->action = action;
entry->flags = flags;
entry->keyCode = keyCode;
@@ -2951,12 +3097,11 @@
nsecs_t downTime, uint32_t pointerCount,
const int32_t* pointerIds, const PointerCoords* pointerCoords) {
MotionEntry* entry = mMotionEntryPool.alloc();
- initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime);
+ initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags);
entry->eventTime = eventTime;
entry->deviceId = deviceId;
entry->source = source;
- entry->policyFlags = policyFlags;
entry->action = action;
entry->flags = flags;
entry->metaState = metaState;
@@ -3103,8 +3248,7 @@
// --- InputDispatcher::InputState ---
-InputDispatcher::InputState::InputState() :
- mIsOutOfSync(false) {
+InputDispatcher::InputState::InputState() {
}
InputDispatcher::InputState::~InputState() {
@@ -3114,20 +3258,6 @@
return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
}
-bool InputDispatcher::InputState::isOutOfSync() const {
- return mIsOutOfSync;
-}
-
-void InputDispatcher::InputState::setOutOfSync() {
- if (! isNeutral()) {
- mIsOutOfSync = true;
- }
-}
-
-void InputDispatcher::InputState::resetOutOfSync() {
- mIsOutOfSync = false;
-}
-
InputDispatcher::InputState::Consistency InputDispatcher::InputState::trackEvent(
const EventEntry* entry) {
switch (entry->type) {
@@ -3154,9 +3284,6 @@
switch (action) {
case AKEY_EVENT_ACTION_UP:
mKeyMementos.removeAt(i);
- if (isNeutral()) {
- mIsOutOfSync = false;
- }
return CONSISTENT;
case AKEY_EVENT_ACTION_DOWN:
@@ -3196,9 +3323,6 @@
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_CANCEL:
mMotionMementos.removeAt(i);
- if (isNeutral()) {
- mIsOutOfSync = false;
- }
return CONSISTENT;
case AMOTION_EVENT_ACTION_DOWN:
@@ -3256,30 +3380,70 @@
}
}
-void InputDispatcher::InputState::synthesizeCancelationEvents(
- Allocator* allocator, Vector<EventEntry*>& outEvents) const {
- for (size_t i = 0; i < mKeyMementos.size(); i++) {
+void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
+ Allocator* allocator, Vector<EventEntry*>& outEvents,
+ CancelationOptions options) {
+ for (size_t i = 0; i < mKeyMementos.size(); ) {
const KeyMemento& memento = mKeyMementos.itemAt(i);
- outEvents.push(allocator->obtainKeyEntry(now(),
- memento.deviceId, memento.source, 0,
- AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
- memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
+ if (shouldCancelEvent(memento.source, options)) {
+ outEvents.push(allocator->obtainKeyEntry(currentTime,
+ memento.deviceId, memento.source, 0,
+ AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_CANCELED,
+ memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
+ mKeyMementos.removeAt(i);
+ } else {
+ i += 1;
+ }
}
for (size_t i = 0; i < mMotionMementos.size(); i++) {
const MotionMemento& memento = mMotionMementos.itemAt(i);
- outEvents.push(allocator->obtainMotionEntry(now(),
- memento.deviceId, memento.source, 0,
- AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
- memento.xPrecision, memento.yPrecision, memento.downTime,
- memento.pointerCount, memento.pointerIds, memento.pointerCoords));
+ if (shouldCancelEvent(memento.source, options)) {
+ outEvents.push(allocator->obtainMotionEntry(currentTime,
+ memento.deviceId, memento.source, 0,
+ AMOTION_EVENT_ACTION_CANCEL, 0, 0, 0,
+ memento.xPrecision, memento.yPrecision, memento.downTime,
+ memento.pointerCount, memento.pointerIds, memento.pointerCoords));
+ mMotionMementos.removeAt(i);
+ } else {
+ i += 1;
+ }
}
}
void InputDispatcher::InputState::clear() {
mKeyMementos.clear();
mMotionMementos.clear();
- mIsOutOfSync = false;
+}
+
+void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos.itemAt(i);
+ if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
+ for (size_t j = 0; j < other.mMotionMementos.size(); ) {
+ const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
+ if (memento.deviceId == otherMemento.deviceId
+ && memento.source == otherMemento.source) {
+ other.mMotionMementos.removeAt(j);
+ } else {
+ j += 1;
+ }
+ }
+ other.mMotionMementos.push(memento);
+ }
+ }
+}
+
+bool InputDispatcher::InputState::shouldCancelEvent(int32_t eventSource,
+ CancelationOptions options) {
+ switch (options) {
+ case CANCEL_POINTER_EVENTS:
+ return eventSource & AINPUT_SOURCE_CLASS_POINTER;
+ case CANCEL_NON_POINTER_EVENTS:
+ return !(eventSource & AINPUT_SOURCE_CLASS_POINTER);
+ default:
+ return true;
+ }
}
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 7adc764..0560bb8 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -796,10 +796,6 @@
return 0;
}
-bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) {
- return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
-}
-
// --- SwitchInputMapper ---
@@ -823,11 +819,7 @@
}
void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) {
- uint32_t policyFlags = 0;
- int32_t policyActions = getPolicy()->interceptSwitch(
- when, switchCode, switchValue, policyFlags);
-
- applyStandardPolicyActions(when, policyActions);
+ getDispatcher()->notifySwitch(when, switchCode, switchValue, 0);
}
int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
@@ -983,29 +975,9 @@
getContext()->updateGlobalMetaState();
}
- applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime);
-}
-
-void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down,
- int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
- int32_t policyActions = getPolicy()->interceptKey(when,
- getDeviceId(), down, keyCode, scanCode, policyFlags);
-
- if (! applyStandardPolicyActions(when, policyActions)) {
- return; // event dropped
- }
-
- int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
- int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
- if (policyFlags & POLICY_FLAG_WOKE_HERE) {
- keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE;
- }
- if (policyFlags & POLICY_FLAG_VIRTUAL) {
- keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
- }
-
getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
- keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+ down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
+ AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
}
ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) {
@@ -1215,26 +1187,13 @@
}
} // release lock
- applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
-
- mAccumulator.clear();
-}
-
-void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
- PointerCoords* pointerCoords, nsecs_t downTime) {
- uint32_t policyFlags = 0;
- int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
-
- if (! applyStandardPolicyActions(when, policyActions)) {
- return; // event dropped
- }
-
int32_t metaState = mContext->getGlobalMetaState();
int32_t pointerId = 0;
-
- getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, 0,
motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
- 1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime);
+ 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime);
+
+ mAccumulator.clear();
}
int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
@@ -2012,15 +1971,7 @@
}
void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
- // Apply generic policy actions.
-
uint32_t policyFlags = 0;
- int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
-
- if (! applyStandardPolicyActions(when, policyActions)) {
- mLastTouch.clear();
- return; // event dropped
- }
// Preprocess pointer data.
@@ -2160,24 +2111,11 @@
} // release lock
// Dispatch virtual key.
- applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags,
- keyCode, scanCode, downTime);
- return touchResult;
-}
-
-void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags,
- int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
int32_t metaState = mContext->getGlobalMetaState();
-
policyFlags |= POLICY_FLAG_VIRTUAL;
- int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
- keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
-
- if (applyStandardPolicyActions(when, policyActions)) {
- getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
- keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
- }
+ getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
+ keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+ return touchResult;
}
void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index bd25da2..8d408c2 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -102,8 +102,9 @@
public static final int PAUSE_AVAILABLE = 29; // Boolean
public static final int SEEK_BACKWARD_AVAILABLE = 30; // Boolean
public static final int SEEK_FORWARD_AVAILABLE = 31; // Boolean
+ public static final int SEEK_AVAILABLE = 32; // Boolean
- private static final int LAST_SYSTEM = 31;
+ private static final int LAST_SYSTEM = 32;
private static final int FIRST_CUSTOM = 8192;
// Shorthands to set the MediaPlayer's metadata filter.
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 630d7112e..fa015cc 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -42,6 +42,7 @@
private final IContentProvider mMediaProvider;
private final String mVolumeName;
private final Uri mObjectsUri;
+ private final String mMediaStoragePath;
// true if the database has been modified in the current MTP session
private boolean mDatabaseModified;
@@ -84,12 +85,13 @@
System.loadLibrary("media_jni");
}
- public MtpDatabase(Context context, String volumeName) {
+ public MtpDatabase(Context context, String volumeName, String storagePath) {
native_setup();
mContext = context;
mMediaProvider = context.getContentResolver().acquireProvider("media");
mVolumeName = volumeName;
+ mMediaStoragePath = storagePath;
mObjectsUri = Files.getMtpObjectsUri(volumeName);
mMediaScanner = new MediaScanner(context);
openDevicePropertiesDatabase(context);
@@ -701,6 +703,13 @@
private int getObjectFilePath(int handle, char[] outFilePath, long[] outFileLength) {
Log.d(TAG, "getObjectFilePath: " + handle);
+ if (handle == 0) {
+ // special case root directory
+ mMediaStoragePath.getChars(0, mMediaStoragePath.length(), outFilePath, 0);
+ outFilePath[mMediaStoragePath.length()] = 0;
+ outFileLength[0] = 0;
+ return MtpConstants.RESPONSE_OK;
+ }
Cursor c = null;
try {
c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION,
diff --git a/media/java/android/media/videoeditor/EffectColor.java b/media/java/android/media/videoeditor/EffectColor.java
index f38cf75..ac48e37 100755
--- a/media/java/android/media/videoeditor/EffectColor.java
+++ b/media/java/android/media/videoeditor/EffectColor.java
@@ -25,7 +25,7 @@
/**
* Change the video frame color to the RGB color value provided
*/
- public static final int TYPE_COLOR = 1; // color as 888 RGB
+ public static final int TYPE_COLOR = 1;
/**
* Change the video frame color to a gradation from RGB color (at the top of
* the frame) to black (at the bottom of the frame).
@@ -44,7 +44,7 @@
*/
public static final int TYPE_FIFTIES = 5;
- // Colors for the color effect
+ // Predefined colors
public static final int GREEN = 0x0000ff00;
public static final int PINK = 0x00ff66cc;
public static final int GRAY = 0x007f7f7f;
@@ -52,8 +52,8 @@
// The effect type
private final int mType;
- // The effect parameter
- private final int mParam;
+ // The effect color
+ private final int mColor;
/**
* An object of this type cannot be instantiated by using the default
@@ -73,29 +73,47 @@
* is applied
* @param durationMs The duration of this effect in milliseconds
* @param type type of the effect. type is one of: TYPE_COLOR,
- * TYPE_GRADIENT, TYPE_SEPIA, TYPE_NEGATIVE, TYPE_FIFTIES. If
- * type is not supported, the argument is ignored
- * @param param if type is TYPE_COLOR, param is the RGB color as 888.
- * Otherwise, param is ignored
+ * TYPE_GRADIENT, TYPE_SEPIA, TYPE_NEGATIVE, TYPE_FIFTIES.
+ * @param color If type is TYPE_COLOR, color is the RGB color as 888.
+ * If type is TYPE_GRADIENT, color is the RGB color at the
+ * top of the frame. Otherwise, color is ignored
*/
public EffectColor(MediaItem mediaItem, String effectId, long startTimeMs, long durationMs,
- int type, int param) {
+ int type, int color) {
super(mediaItem, effectId, startTimeMs, durationMs);
+ switch (type) {
+ case TYPE_COLOR:
+ case TYPE_GRADIENT: {
+ mColor = color;
+ break;
+ }
+
+ case TYPE_SEPIA:
+ case TYPE_NEGATIVE:
+ case TYPE_FIFTIES: {
+ mColor = -1;
+ break;
+ }
+
+ default: {
+ throw new IllegalArgumentException("Invalid type: " + type);
+ }
+ }
+
mType = type;
- mParam = param;
}
/**
- * @return The type of this effect
+ * @return The effect type
*/
public int getType() {
return mType;
}
/**
- * @return the color as RGB 888 if type is TYPE_COLOR. Otherwise, ignore.
+ * @return the color as RGB 888 if type is TYPE_COLOR or TYPE_GRADIENT.
*/
- public int getParam() {
- return mParam;
+ public int getColor() {
+ return mColor;
}
}
diff --git a/media/java/android/media/videoeditor/VideoEditorTestImpl.java b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
index c3cb82ac..cf0e3ba 100644
--- a/media/java/android/media/videoeditor/VideoEditorTestImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorTestImpl.java
@@ -643,7 +643,7 @@
Integer.toString(colorEffect.getType()));
if (colorEffect.getType() == EffectColor.TYPE_COLOR) {
serializer.attribute("", ATTR_COLOR_EFFECT_VALUE,
- Integer.toString(colorEffect.getParam()));
+ Integer.toString(colorEffect.getColor()));
}
} else if (effect instanceof EffectKenBurns) {
final Rect startRect = ((EffectKenBurns)effect).getStartRect();
@@ -972,7 +972,8 @@
final int colorEffectType =
Integer.parseInt(parser.getAttributeValue("", ATTR_COLOR_EFFECT_TYPE));
final int color;
- if (colorEffectType == EffectColor.TYPE_COLOR) {
+ if (colorEffectType == EffectColor.TYPE_COLOR
+ || colorEffectType == EffectColor.TYPE_GRADIENT) {
color = Integer.parseInt(parser.getAttributeValue("", ATTR_COLOR_EFFECT_VALUE));
} else {
color = 0;
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d4aacaf..eb3d27b 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -727,7 +727,7 @@
}
static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) {
- LOGV("attachAuxEffect(): %d", sessionId);
+ LOGV("attachAuxEffect(): %d", effectId);
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
diff --git a/media/jni/android_media_MtpServer.cpp b/media/jni/android_media_MtpServer.cpp
index 4567965..f16cdd9 100644
--- a/media/jni/android_media_MtpServer.cpp
+++ b/media/jni/android_media_MtpServer.cpp
@@ -125,8 +125,6 @@
sMutex.lock();
if (mServer)
mServer->sendObjectAdded(handle);
- else
- LOGE("sendObjectAdded called while disconnected\n");
sMutex.unlock();
}
@@ -134,8 +132,6 @@
sMutex.lock();
if (mServer)
mServer->sendObjectRemoved(handle);
- else
- LOGE("sendObjectRemoved called while disconnected\n");
sMutex.unlock();
}
};
@@ -187,12 +183,9 @@
android_media_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
{
#ifdef HAVE_ANDROID_OS
- LOGD("send_object_added %d\n", handle);
MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
if (thread)
thread->sendObjectAdded(handle);
- else
- LOGE("sendObjectAdded called while disconnected\n");
#endif
}
@@ -200,12 +193,9 @@
android_media_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
{
#ifdef HAVE_ANDROID_OS
- LOGD("send_object_removed %d\n", handle);
MtpThread *thread = (MtpThread *)env->GetIntField(thiz, field_context);
if (thread)
thread->sendObjectRemoved(handle);
- else
- LOGE("sendObjectRemoved called while disconnected\n");
#endif
}
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index da1f7e5..ee3f660 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -56,6 +56,7 @@
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
mAudioSessionId = AudioSystem::newAudioSessionId();
+ mSendLevel = 0;
}
MediaPlayer::~MediaPlayer()
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 877e787..80922d6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1554,6 +1554,11 @@
}
+int MediaPlayerService::AudioOutput::getSessionId()
+{
+ return mSessionId;
+}
+
#undef LOG_TAG
#define LOG_TAG "AudioCache"
MediaPlayerService::AudioCache::AudioCache(const char* name) :
@@ -1741,4 +1746,9 @@
p->mSignal.signal();
}
+int MediaPlayerService::AudioCache::getSessionId()
+{
+ return 0;
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index deb458c..c4e78f7 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -77,6 +77,7 @@
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position);
+ virtual int getSessionId();
virtual status_t open(
uint32_t sampleRate, int channelCount,
@@ -133,6 +134,7 @@
virtual uint32_t latency() const;
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position);
+ virtual int getSessionId();
virtual status_t open(
uint32_t sampleRate, int channelCount, int format,
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 6b9bf85..b3e2da0 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -187,6 +187,10 @@
Metadata::kSeekForwardAvailable,
flags & MediaExtractor::CAN_SEEK_FORWARD);
+ metadata.appendBool(
+ Metadata::kSeekAvailable,
+ flags & MediaExtractor::CAN_SEEK);
+
return OK;
}
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 71d48b3..c0b1abe 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -15,7 +15,6 @@
*/
#include <media/stagefright/AMRWriter.h>
-
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
@@ -23,6 +22,8 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
namespace android {
@@ -194,6 +195,7 @@
int64_t maxTimestampUs = 0;
status_t err = OK;
+ prctl(PR_SET_NAME, (unsigned long)"AMRWriter", 0, 0, 0);
while (!mDone) {
MediaBuffer *buffer;
err = mSource->read(&buffer);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 82f14a3..fcc3e81 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -888,9 +888,7 @@
}
status_t AwesomePlayer::seekTo(int64_t timeUs) {
- if (mExtractorFlags
- & (MediaExtractor::CAN_SEEK_FORWARD
- | MediaExtractor::CAN_SEEK_BACKWARD)) {
+ if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
Mutex::Autolock autoLock(mLock);
return seekTo_l(timeUs);
}
@@ -898,12 +896,19 @@
return OK;
}
+// static
+void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) {
+ static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone();
+}
+
+void AwesomePlayer::onRTSPSeekDone() {
+ notifyListener_l(MEDIA_SEEK_COMPLETE);
+ mSeekNotificationSent = true;
+}
+
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
if (mRTSPController != NULL) {
- mRTSPController->seek(timeUs);
-
- notifyListener_l(MEDIA_SEEK_COMPLETE);
- mSeekNotificationSent = true;
+ mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this);
return OK;
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 6d00d7c..e53b0a0 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -20,8 +20,9 @@
#include <arpa/inet.h>
-#include <ctype.h>
#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaBuffer.h>
@@ -1104,6 +1105,7 @@
void MPEG4Writer::threadFunc() {
LOGV("threadFunc");
+ prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
while (!mDone) {
{
Mutex::Autolock autolock(mLock);
@@ -1632,6 +1634,11 @@
int64_t previousPausedDurationUs = 0;
int64_t timestampUs;
+ if (mIsAudio) {
+ prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
+ } else {
+ prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
+ }
sp<MetaData> meta_data;
mNumSamples = 0;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 9bc94de..8a5fb11 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -41,7 +41,7 @@
}
uint32_t MediaExtractor::flags() const {
- return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE;
+ return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
}
// static
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index a8f1104..478e40c 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -18,6 +18,9 @@
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
namespace android {
@@ -41,10 +44,12 @@
br.skipBits(16);
parseUE(&br); // seq_parameter_set_id
+ unsigned chroma_format_idc = 1; // 4:2:0 chroma format
+
if (profile_idc == 100 || profile_idc == 110
|| profile_idc == 122 || profile_idc == 244
|| profile_idc == 44 || profile_idc == 83 || profile_idc == 86) {
- unsigned chroma_format_idc = parseUE(&br);
+ chroma_format_idc = parseUE(&br);
if (chroma_format_idc == 3) {
br.skipBits(1); // residual_colour_transform_flag
}
@@ -85,6 +90,212 @@
*height = (2 - frame_mbs_only_flag)
* (pic_height_in_map_units_minus1 * 16 + 16);
+
+ if (!frame_mbs_only_flag) {
+ br.getBits(1); // mb_adaptive_frame_field_flag
+ }
+
+ br.getBits(1); // direct_8x8_inference_flag
+
+ if (br.getBits(1)) { // frame_cropping_flag
+ unsigned frame_crop_left_offset = parseUE(&br);
+ unsigned frame_crop_right_offset = parseUE(&br);
+ unsigned frame_crop_top_offset = parseUE(&br);
+ unsigned frame_crop_bottom_offset = parseUE(&br);
+
+ unsigned cropUnitX, cropUnitY;
+ if (chroma_format_idc == 0 /* monochrome */) {
+ cropUnitX = 1;
+ cropUnitY = 2 - frame_mbs_only_flag;
+ } else {
+ unsigned subWidthC = (chroma_format_idc == 3) ? 1 : 2;
+ unsigned subHeightC = (chroma_format_idc == 1) ? 2 : 1;
+
+ cropUnitX = subWidthC;
+ cropUnitY = subHeightC * (2 - frame_mbs_only_flag);
+ }
+
+ LOGV("frame_crop = (%u, %u, %u, %u), cropUnitX = %u, cropUnitY = %u",
+ frame_crop_left_offset, frame_crop_right_offset,
+ frame_crop_top_offset, frame_crop_bottom_offset,
+ cropUnitX, cropUnitY);
+
+ *width -=
+ (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX;
+ *height -=
+ (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
+ }
+}
+
+status_t getNextNALUnit(
+ const uint8_t **_data, size_t *_size,
+ const uint8_t **nalStart, size_t *nalSize,
+ bool startCodeFollows) {
+ const uint8_t *data = *_data;
+ size_t size = *_size;
+
+ *nalStart = NULL;
+ *nalSize = 0;
+
+ if (size == 0) {
+ return -EAGAIN;
+ }
+
+ // Skip any number of leading 0x00.
+
+ size_t offset = 0;
+ while (offset < size && data[offset] == 0x00) {
+ ++offset;
+ }
+
+ if (offset == size) {
+ return -EAGAIN;
+ }
+
+ // A valid startcode consists of at least two 0x00 bytes followed by 0x01.
+
+ if (offset < 2 || data[offset] != 0x01) {
+ return ERROR_MALFORMED;
+ }
+
+ ++offset;
+
+ size_t startOffset = offset;
+
+ for (;;) {
+ while (offset < size && data[offset] != 0x01) {
+ ++offset;
+ }
+
+ if (offset == size) {
+ if (startCodeFollows) {
+ offset = size + 2;
+ break;
+ }
+
+ return -EAGAIN;
+ }
+
+ if (data[offset - 1] == 0x00 && data[offset - 2] == 0x00) {
+ break;
+ }
+
+ ++offset;
+ }
+
+ size_t endOffset = offset - 2;
+ while (data[endOffset - 1] == 0x00) {
+ --endOffset;
+ }
+
+ *nalStart = &data[startOffset];
+ *nalSize = endOffset - startOffset;
+
+ if (offset + 2 < size) {
+ *_data = &data[offset - 2];
+ *_size = size - offset + 2;
+ } else {
+ *_data = NULL;
+ *_size = 0;
+ }
+
+ return OK;
+}
+
+static sp<ABuffer> FindNAL(
+ const uint8_t *data, size_t size, unsigned nalType,
+ size_t *stopOffset) {
+ const uint8_t *nalStart;
+ size_t nalSize;
+ while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
+ if ((nalStart[0] & 0x1f) == nalType) {
+ sp<ABuffer> buffer = new ABuffer(nalSize);
+ memcpy(buffer->data(), nalStart, nalSize);
+ return buffer;
+ }
+ }
+
+ return NULL;
+}
+
+sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit) {
+ const uint8_t *data = accessUnit->data();
+ size_t size = accessUnit->size();
+
+ sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
+ if (seqParamSet == NULL) {
+ return NULL;
+ }
+
+ int32_t width, height;
+ FindAVCDimensions(seqParamSet, &width, &height);
+
+ size_t stopOffset;
+ sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
+ CHECK(picParamSet != NULL);
+
+ size_t csdSize =
+ 1 + 3 + 1 + 1
+ + 2 * 1 + seqParamSet->size()
+ + 1 + 2 * 1 + picParamSet->size();
+
+ sp<ABuffer> csd = new ABuffer(csdSize);
+ uint8_t *out = csd->data();
+
+ *out++ = 0x01; // configurationVersion
+ memcpy(out, seqParamSet->data() + 1, 3); // profile/level...
+ out += 3;
+ *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes
+ *out++ = 0xe0 | 1;
+
+ *out++ = seqParamSet->size() >> 8;
+ *out++ = seqParamSet->size() & 0xff;
+ memcpy(out, seqParamSet->data(), seqParamSet->size());
+ out += seqParamSet->size();
+
+ *out++ = 1;
+
+ *out++ = picParamSet->size() >> 8;
+ *out++ = picParamSet->size() & 0xff;
+ memcpy(out, picParamSet->data(), picParamSet->size());
+
+#if 0
+ LOGI("AVC seq param set");
+ hexdump(seqParamSet->data(), seqParamSet->size());
+#endif
+
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+
+ meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
+ meta->setInt32(kKeyWidth, width);
+ meta->setInt32(kKeyHeight, height);
+
+ LOGI("found AVC codec config (%d x %d)", width, height);
+
+ return meta;
+}
+
+bool IsIDR(const sp<ABuffer> &buffer) {
+ const uint8_t *data = buffer->data();
+ size_t size = buffer->size();
+
+ bool foundIDR = false;
+
+ const uint8_t *nalStart;
+ size_t nalSize;
+ while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
+ CHECK_GT(nalSize, 0u);
+
+ unsigned nalType = nalStart[0] & 0x1f;
+
+ if (nalType == 5) {
+ foundIDR = true;
+ break;
+ }
+ }
+
+ return foundIDR;
}
} // namespace android
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp
index 35b6475..286c636 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.cpp
@@ -40,7 +40,7 @@
int32 xr[ ], rescaled data
struct gr_info_s *gr_info, granule structure
mp3Header *info, mp3 header info
- int32 Scratch_mem[168] for temporary usage
+ int32 Scratch_mem[198] for temporary usage
Outputs:
@@ -120,7 +120,7 @@
granuleInfo *gr_info,
int32 *used_freq_lines,
mp3Header *info,
- int32 Scratch_mem[168])
+ int32 Scratch_mem[198])
{
int32 sfreq = info->version_x + (info->version_x << 1);
sfreq += info->sampling_frequency;
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h
index ba6ec16..5248951 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_reorder.h
@@ -89,7 +89,7 @@
granuleInfo *gr_info,
int32 *used_freq_lines,
mp3Header *info,
- int32 Scratch_mem[168]);
+ int32 Scratch_mem[198]);
#ifdef __cplusplus
}
diff --git a/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h b/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h
index 805cedb..611e08f 100644
--- a/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h
+++ b/media/libstagefright/codecs/mp3dec/src/s_tmp3dec_file.h
@@ -87,7 +87,7 @@
int32 num_channels;
int32 predicted_frame_size;
int32 frame_start;
- int32 Scratch_mem[168];
+ int32 Scratch_mem[198];
tmp3dec_chan perChan[CHAN];
mp3ScaleFactors scaleFactors[CHAN];
mp3SideInfo sideInfo;
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index 300d8f7..ce7ffe5 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -33,7 +33,7 @@
status_t connect(const char *url);
void disconnect();
- void seek(int64_t timeUs);
+ void seekAsync(int64_t timeUs, void (*seekDoneCb)(void *), void *cookie);
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
@@ -46,6 +46,14 @@
void onMessageReceived(const sp<AMessage> &msg);
+ virtual uint32_t flags() const {
+ // Seeking 10secs forward or backward is a very expensive operation
+ // for rtsp, so let's not enable that.
+ // The user can always use the seek bar.
+
+ return CAN_PAUSE | CAN_SEEK;
+ }
+
protected:
virtual ~ARTSPController();
@@ -53,6 +61,7 @@
enum {
kWhatConnectDone = 'cdon',
kWhatDisconnectDone = 'ddon',
+ kWhatSeekDone = 'sdon',
};
enum State {
@@ -71,6 +80,10 @@
sp<MyHandler> mHandler;
sp<AHandlerReflector<ARTSPController> > mReflector;
+ void (*mSeekDoneCb)(void *);
+ void *mSeekDoneCookie;
+ int64_t mLastSeekCompletedTimeUs;
+
DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
};
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 6ebf4ce..8efe634d 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -254,6 +254,9 @@
static bool ContinuePreparation(void *cookie);
+ static void OnRTSPSeekDoneWrapper(void *cookie);
+ void onRTSPSeekDone();
+
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
};
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index 6602852..62cfc36 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -29,6 +29,16 @@
unsigned parseUE(ABitReader *br);
+status_t getNextNALUnit(
+ const uint8_t **_data, size_t *_size,
+ const uint8_t **nalStart, size_t *nalSize,
+ bool startCodeFollows = false);
+
+struct MetaData;
+sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
+
+bool IsIDR(const sp<ABuffer> &accessUnit);
+
} // namespace android
#endif // AVC_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 4a75ee4..a13287e 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -40,81 +40,6 @@
return mFormat;
}
-static status_t getNextNALUnit(
- const uint8_t **_data, size_t *_size,
- const uint8_t **nalStart, size_t *nalSize,
- bool startCodeFollows = false) {
- const uint8_t *data = *_data;
- size_t size = *_size;
-
- *nalStart = NULL;
- *nalSize = 0;
-
- if (size == 0) {
- return -EAGAIN;
- }
-
- // Skip any number of leading 0x00.
-
- size_t offset = 0;
- while (offset < size && data[offset] == 0x00) {
- ++offset;
- }
-
- if (offset == size) {
- return -EAGAIN;
- }
-
- // A valid startcode consists of at least two 0x00 bytes followed by 0x01.
-
- if (offset < 2 || data[offset] != 0x01) {
- return ERROR_MALFORMED;
- }
-
- ++offset;
-
- size_t startOffset = offset;
-
- for (;;) {
- while (offset < size && data[offset] != 0x01) {
- ++offset;
- }
-
- if (offset == size) {
- if (startCodeFollows) {
- offset = size + 2;
- break;
- }
-
- return -EAGAIN;
- }
-
- if (data[offset - 1] == 0x00 && data[offset - 2] == 0x00) {
- break;
- }
-
- ++offset;
- }
-
- size_t endOffset = offset - 2;
- while (data[endOffset - 1] == 0x00) {
- --endOffset;
- }
-
- *nalStart = &data[startOffset];
- *nalSize = endOffset - startOffset;
-
- if (offset + 2 < size) {
- *_data = &data[offset - 2];
- *_size = size - offset + 2;
- } else {
- *_data = NULL;
- *_size = 0;
- }
-
- return OK;
-}
-
void ElementaryStreamQueue::clear() {
mBuffer->setRange(0, 0);
mFormat.clear();
@@ -433,79 +358,4 @@
return NULL;
}
-static sp<ABuffer> FindNAL(
- const uint8_t *data, size_t size, unsigned nalType,
- size_t *stopOffset) {
- const uint8_t *nalStart;
- size_t nalSize;
- while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
- if ((nalStart[0] & 0x1f) == nalType) {
- sp<ABuffer> buffer = new ABuffer(nalSize);
- memcpy(buffer->data(), nalStart, nalSize);
- return buffer;
- }
- }
-
- return NULL;
-}
-
-sp<MetaData> ElementaryStreamQueue::MakeAVCCodecSpecificData(
- const sp<ABuffer> &accessUnit) {
- const uint8_t *data = accessUnit->data();
- size_t size = accessUnit->size();
-
- sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
- if (seqParamSet == NULL) {
- return NULL;
- }
-
- int32_t width, height;
- FindAVCDimensions(seqParamSet, &width, &height);
-
- size_t stopOffset;
- sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
- CHECK(picParamSet != NULL);
-
- size_t csdSize =
- 1 + 3 + 1 + 1
- + 2 * 1 + seqParamSet->size()
- + 1 + 2 * 1 + picParamSet->size();
-
- sp<ABuffer> csd = new ABuffer(csdSize);
- uint8_t *out = csd->data();
-
- *out++ = 0x01; // configurationVersion
- memcpy(out, seqParamSet->data() + 1, 3); // profile/level...
- out += 3;
- *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes
- *out++ = 0xe0 | 1;
-
- *out++ = seqParamSet->size() >> 8;
- *out++ = seqParamSet->size() & 0xff;
- memcpy(out, seqParamSet->data(), seqParamSet->size());
- out += seqParamSet->size();
-
- *out++ = 1;
-
- *out++ = picParamSet->size() >> 8;
- *out++ = picParamSet->size() & 0xff;
- memcpy(out, picParamSet->data(), picParamSet->size());
-
-#if 0
- LOGI("AVC seq param set");
- hexdump(seqParamSet->data(), seqParamSet->size());
-#endif
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-
- meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
- meta->setInt32(kKeyWidth, width);
- meta->setInt32(kKeyHeight, height);
-
- LOGI("found AVC codec config (%d x %d)", width, height);
-
- return meta;
-}
-
} // namespace android
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 246c390..9eaf834 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -56,9 +56,6 @@
unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration);
- static sp<MetaData> MakeAVCCodecSpecificData(
- const sp<ABuffer> &accessUnit);
-
DISALLOW_EVIL_CONSTRUCTORS(ElementaryStreamQueue);
};
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 78754e6..10cc88b 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -490,6 +490,8 @@
: mInitCheck(NO_INIT),
mFormat(new MetaData),
mEOSResult(OK),
+ mIsAVC(false),
+ mScanForIDR(true),
mRTPTimeBase(0),
mNormalPlayTimeBaseUs(0),
mLastNormalPlayTimeUs(0) {
@@ -509,6 +511,8 @@
mInitCheck = OK;
if (!strncmp(desc.c_str(), "H264/", 5)) {
+ mIsAVC = true;
+
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
int32_t width, height;
@@ -719,6 +723,20 @@
return;
}
+ if (mScanForIDR && mIsAVC) {
+ // This pretty piece of code ensures that the first access unit
+ // fed to the decoder after stream-start or seek is guaranteed to
+ // be an IDR frame. This is to workaround limitations of a certain
+ // hardware h.264 decoder that requires this to be the case.
+
+ if (!IsIDR(buffer)) {
+ LOGV("skipping AU while scanning for next IDR frame.");
+ return;
+ }
+
+ mScanForIDR = false;
+ }
+
Mutex::Autolock autoLock(mLock);
mBuffers.push_back(buffer);
mCondition.signal();
@@ -735,6 +753,8 @@
void APacketSource::flushQueue() {
Mutex::Autolock autoLock(mLock);
mBuffers.clear();
+
+ mScanForIDR = true;
}
int64_t APacketSource::getNormalPlayTimeUs() {
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 076ddc47..7a77fc6 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -65,6 +65,9 @@
List<sp<ABuffer> > mBuffers;
status_t mEOSResult;
+ bool mIsAVC;
+ bool mScanForIDR;
+
uint32_t mClockRate;
uint32_t mRTPTimeBase;
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
index 4c53639..a7563ff 100644
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ b/media/libstagefright/rtsp/ARTSPController.cpp
@@ -27,7 +27,10 @@
ARTSPController::ARTSPController(const sp<ALooper> &looper)
: mState(DISCONNECTED),
- mLooper(looper) {
+ mLooper(looper),
+ mSeekDoneCb(NULL),
+ mSeekDoneCookie(NULL),
+ mLastSeekCompletedTimeUs(-1) {
mReflector = new AHandlerReflector<ARTSPController>(this);
looper->registerHandler(mReflector);
}
@@ -80,14 +83,31 @@
mHandler.clear();
}
-void ARTSPController::seek(int64_t timeUs) {
+void ARTSPController::seekAsync(
+ int64_t timeUs,
+ void (*seekDoneCb)(void *), void *cookie) {
Mutex::Autolock autoLock(mLock);
- if (mState != CONNECTED) {
+ CHECK(seekDoneCb != NULL);
+ CHECK(mSeekDoneCb == NULL);
+
+ // Ignore seek requests that are too soon after the previous one has
+ // completed, we don't want to swamp the server.
+
+ bool tooEarly =
+ mLastSeekCompletedTimeUs >= 0
+ && ALooper::GetNowUs() < mLastSeekCompletedTimeUs + 500000ll;
+
+ if (mState != CONNECTED || tooEarly) {
+ (*seekDoneCb)(cookie);
return;
}
- mHandler->seek(timeUs);
+ mSeekDoneCb = seekDoneCb;
+ mSeekDoneCookie = cookie;
+
+ sp<AMessage> msg = new AMessage(kWhatSeekDone, mReflector->id());
+ mHandler->seek(timeUs, msg);
}
size_t ARTSPController::countTracks() {
@@ -132,6 +152,19 @@
break;
}
+ case kWhatSeekDone:
+ {
+ LOGI("seek done");
+
+ mLastSeekCompletedTimeUs = ALooper::GetNowUs();
+
+ void (*seekDoneCb)(void *) = mSeekDoneCb;
+ mSeekDoneCb = NULL;
+
+ (*seekDoneCb)(mSeekDoneCookie);
+ break;
+ }
+
default:
TRESPASS();
break;
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 09dc156..846d1d5 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -86,8 +86,10 @@
mFirstAccessUnitNTP(0),
mNumAccessUnitsReceived(0),
mCheckPending(false),
+ mCheckGeneration(0),
mTryTCPInterleaving(false),
- mReceivedFirstRTCPPacket(false) {
+ mReceivedFirstRTCPPacket(false),
+ mSeekable(false) {
mNetLooper->setName("rtsp net");
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
@@ -114,9 +116,10 @@
(new AMessage('abor', id()))->post();
}
- void seek(int64_t timeUs) {
+ void seek(int64_t timeUs, const sp<AMessage> &doneMsg) {
sp<AMessage> msg = new AMessage('seek', id());
msg->setInt64("time", timeUs);
+ msg->setMessage("doneMsg", doneMsg);
msg->post();
}
@@ -378,6 +381,7 @@
mFirstAccessUnitNTP = 0;
mNumAccessUnitsReceived = 0;
mReceivedFirstRTCPPacket = false;
+ mSeekable = false;
sp<AMessage> reply = new AMessage('tear', id());
@@ -434,6 +438,13 @@
case 'chek':
{
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ if (generation != mCheckGeneration) {
+ // This is an outdated message. Ignore.
+ break;
+ }
+
if (mNumAccessUnitsReceived == 0) {
LOGI("stream ended? aborting.");
(new AMessage('abor', id()))->post();
@@ -454,12 +465,7 @@
}
++mNumAccessUnitsReceived;
-
- if (!mCheckPending) {
- mCheckPending = true;
- sp<AMessage> check = new AMessage('chek', id());
- check->post(kAccessUnitTimeoutUs);
- }
+ postAccessUnitTimeoutCheck();
size_t trackIndex;
CHECK(msg->findSize("track-index", &trackIndex));
@@ -548,7 +554,17 @@
case 'seek':
{
+ sp<AMessage> doneMsg;
+ CHECK(msg->findMessage("doneMsg", &doneMsg));
+
if (mSeekPending) {
+ doneMsg->post();
+ break;
+ }
+
+ if (!mSeekable) {
+ LOGW("This is a live stream, ignoring seek request.");
+ doneMsg->post();
break;
}
@@ -557,6 +573,11 @@
mSeekPending = true;
+ // Disable the access unit timeout until we resumed
+ // playback again.
+ mCheckPending = true;
+ ++mCheckGeneration;
+
AString request = "PAUSE ";
request.append(mSessionURL);
request.append(" RTSP/1.0\r\n");
@@ -569,6 +590,7 @@
sp<AMessage> reply = new AMessage('see1', id());
reply->setInt64("time", timeUs);
+ reply->setMessage("doneMsg", doneMsg);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -597,7 +619,11 @@
request.append("\r\n");
+ sp<AMessage> doneMsg;
+ CHECK(msg->findMessage("doneMsg", &doneMsg));
+
sp<AMessage> reply = new AMessage('see2', id());
+ reply->setMessage("doneMsg", doneMsg);
mConn->sendRequest(request.c_str(), reply);
break;
}
@@ -612,6 +638,9 @@
LOGI("PLAY completed with result %d (%s)",
result, strerror(-result));
+ mCheckPending = false;
+ postAccessUnitTimeoutCheck();
+
if (result == OK) {
sp<RefBase> obj;
CHECK(msg->findObject("response", &obj));
@@ -633,6 +662,11 @@
}
mSeekPending = false;
+
+ sp<AMessage> doneMsg;
+ CHECK(msg->findMessage("doneMsg", &doneMsg));
+
+ doneMsg->post();
break;
}
@@ -674,6 +708,17 @@
}
}
+ void postAccessUnitTimeoutCheck() {
+ if (mCheckPending) {
+ return;
+ }
+
+ mCheckPending = true;
+ sp<AMessage> check = new AMessage('chek', id());
+ check->setInt32("generation", mCheckGeneration);
+ check->post(kAccessUnitTimeoutUs);
+ }
+
static void SplitString(
const AString &s, const char *separator, List<AString> *items) {
items->clear();
@@ -692,6 +737,8 @@
}
void parsePlayResponse(const sp<ARTSPResponse> &response) {
+ mSeekable = false;
+
ssize_t i = response->mHeaders.indexOfKey("range");
if (i < 0) {
// Server doesn't even tell use what range it is going to
@@ -755,6 +802,8 @@
++n;
}
+
+ mSeekable = true;
}
sp<APacketSource> getPacketSource(size_t index) {
@@ -783,8 +832,10 @@
uint64_t mFirstAccessUnitNTP;
int64_t mNumAccessUnitsReceived;
bool mCheckPending;
+ int32_t mCheckGeneration;
bool mTryTCPInterleaving;
bool mReceivedFirstRTCPPacket;
+ bool mSeekable;
struct TrackInfo {
AString mURL;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 84a3e2c..f74f395 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -163,6 +163,7 @@
mData.setOperationCode(operation);
mData.setTransactionID(transaction);
LOGV("sending data:");
+ mData.dump();
ret = mData.write(fd);
if (ret < 0) {
LOGE("request write returned %d, errno: %d", ret, errno);
@@ -177,6 +178,7 @@
mResponse.setTransactionID(transaction);
LOGV("sending response %04X", mResponse.getResponseCode());
ret = mResponse.write(fd);
+ mResponse.dump();
if (ret < 0) {
LOGE("request write returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
@@ -546,7 +548,7 @@
// send data header
mData.setOperationCode(mRequest.getOperationCode());
mData.setTransactionID(mRequest.getTransactionID());
- mData.writeDataHeader(mFD, fileLength);
+ mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
// then transfer the file
int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 68e0e32..449bd4c 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1123,6 +1123,10 @@
@Override
public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
int keyCode, int metaState, int repeatCount, int policyFlags) {
+ if ((policyFlags & WindowManagerPolicy.FLAG_TRUSTED) == 0) {
+ return false;
+ }
+
final boolean keyguardOn = keyguardOn();
final boolean down = (action == KeyEvent.ACTION_DOWN);
final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
@@ -1149,7 +1153,7 @@
if (!down) {
mHomePressed = false;
- if (! canceled) {
+ if (!canceled) {
// If an incoming call is ringing, HOME is totally disabled.
// (The user is already on the InCallScreen at this point,
// and his ONLY options are to answer or reject the call.)
@@ -1831,7 +1835,14 @@
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
int policyFlags, boolean isScreenOn) {
int result = ACTION_PASS_TO_USER;
-
+ if ((policyFlags & WindowManagerPolicy.FLAG_TRUSTED) == 0) {
+ return result;
+ }
+
+ if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ }
+
final boolean isWakeKey = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 808c679..d09dfff 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -320,6 +320,7 @@
// Callback is disabled by default
mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
mOrientation = 0;
+ mPreviewWindowFlag = 0;
mOrientationChanged = false;
mPlayShutterSound = true;
cameraService->setCameraBusy(cameraId);
@@ -508,6 +509,8 @@
if (mUseOverlay) {
result = setOverlay();
} else if (mPreviewWindow != 0) {
+ native_window_set_buffers_transform(mPreviewWindow.get(),
+ mPreviewWindowFlag);
result = mHardware->setPreviewWindow(mPreviewWindow);
}
}
@@ -633,7 +636,10 @@
if (result != NO_ERROR) return result;
result = mHardware->startPreview();
} else {
- // XXX: Set the orientation of the ANativeWindow.
+ if (mPreviewWindow != 0) {
+ native_window_set_buffers_transform(mPreviewWindow.get(),
+ mPreviewWindowFlag);
+ }
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview();
}
@@ -818,15 +824,19 @@
switch (arg1) {
case 0:
orientation = ISurface::BufferHeap::ROT_0;
+ mPreviewWindowFlag = 0;
break;
case 90:
orientation = ISurface::BufferHeap::ROT_90;
+ mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_90;
break;
case 180:
orientation = ISurface::BufferHeap::ROT_180;
+ mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_180;
break;
case 270:
orientation = ISurface::BufferHeap::ROT_270;
+ mPreviewWindowFlag = NATIVE_WINDOW_TRANSFORM_ROT_270;
break;
default:
return BAD_VALUE;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d57364a..c8e0c88 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -166,6 +166,7 @@
sp<CameraService> mCameraService; // immutable after constructor
sp<ICameraClient> mCameraClient;
int mCameraId; // immutable after constructor
+ int mCameraFacing; // immutable after constructor
pid_t mClientPid;
sp<CameraHardwareInterface> mHardware; // cleared after disconnect()
bool mUseOverlay; // immutable after constructor
@@ -176,6 +177,7 @@
int mOrientation; // Current display orientation
// True if display orientation has been changed. This is only used in overlay.
int mOrientationChanged;
+ int mPreviewWindowFlag;
bool mPlayShutterSound;
// Ensures atomicity among the public methods
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 4e2f1e3..4931cc7 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -124,6 +124,14 @@
public AlarmManagerService(Context context) {
mContext = context;
mDescriptor = init();
+
+ // We have to set current TimeZone info to kernel
+ // because kernel doesn't keep this after reboot
+ String tz = SystemProperties.get(TIMEZONE_PROPERTY);
+ if (tz != null) {
+ setTimeZone(tz);
+ }
+
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6095117..ee0cc4b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -1139,10 +1139,8 @@
if (mNetAttributes[checkType] == null) continue;
if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
noMobileData) {
- if (DBG) {
- Slog.d(TAG, "not failing over to mobile type " + checkType +
- " because Mobile Data Disabled");
- }
+ Slog.e(TAG, "not failing over to mobile type " + checkType +
+ " because Mobile Data Disabled");
continue;
}
if (mNetAttributes[checkType].isDefault()) {
@@ -1190,6 +1188,8 @@
newNet = null; // not officially avail.. try anyway, but
// report no failover
}
+ } else {
+ Slog.e(TAG, "Network failover failing.");
}
}
@@ -1232,16 +1232,13 @@
String reason = info.getReason();
String extraInfo = info.getExtraInfo();
- if (DBG) {
- String reasonText;
- if (reason == null) {
- reasonText = ".";
- } else {
- reasonText = " (" + reason + ").";
- }
- Slog.v(TAG, "Attempt to connect to " + info.getTypeName() +
- " failed" + reasonText);
+ String reasonText;
+ if (reason == null) {
+ reasonText = ".";
+ } else {
+ reasonText = " (" + reason + ").";
}
+ Slog.e(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
@@ -1265,9 +1262,9 @@
if (newNet != null) {
NetworkInfo switchTo = newNet.getNetworkInfo();
if (!switchTo.isConnected()) {
- // if the other net is connected they've already reset this and perhaps even gotten
- // a positive report we don't want to overwrite, but if not we need to clear this now
- // to turn our cellular sig strength white
+ // if the other net is connected they've already reset this and perhaps
+ // even gotten a positive report we don't want to overwrite, but if not
+ // we need to clear this now to turn our cellular sig strength white
mDefaultInetConditionPublished = 0;
}
intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index fe306b3..cb4071a 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -49,6 +49,8 @@
public class InputManager {
static final String TAG = "InputManager";
+ private static final boolean DEBUG = false;
+
private final Callbacks mCallbacks;
private final Context mContext;
private final WindowManagerService mWindowManagerService;
@@ -131,7 +133,9 @@
throw new IllegalArgumentException("Invalid display id or dimensions.");
}
- Slog.i(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+ if (DEBUG) {
+ Slog.d(TAG, "Setting display #" + displayId + " size to " + width + "x" + height);
+ }
nativeSetDisplaySize(displayId, width, height);
}
@@ -140,7 +144,9 @@
throw new IllegalArgumentException("Invalid rotation.");
}
- Slog.i(TAG, "Setting display #" + displayId + " orientation to " + rotation);
+ if (DEBUG) {
+ Slog.d(TAG, "Setting display #" + displayId + " orientation to " + rotation);
+ }
nativeSetDisplayOrientation(displayId, rotation);
}
@@ -378,11 +384,6 @@
private static final String CALIBRATION_DIR_PATH = "usr/idc/";
@SuppressWarnings("unused")
- public void virtualKeyDownFeedback() {
- mWindowManagerService.mInputMonitor.virtualKeyDownFeedback();
- }
-
- @SuppressWarnings("unused")
public void notifyConfigurationChanged(long whenNanos) {
mWindowManagerService.sendNewConfiguration();
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 19ea4e1..556aad1 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -130,6 +130,7 @@
// Handler messages
private static final int MESSAGE_LOCATION_CHANGED = 1;
+ private static final int MESSAGE_PACKAGE_UPDATED = 2;
// wakelock variables
private final static String WAKELOCK_KEY = "LocationManagerService";
@@ -1829,6 +1830,19 @@
handleLocationChangedLocked(location, passive);
}
}
+ } else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
+ String packageName = (String) msg.obj;
+ String packageDot = packageName + ".";
+
+ // reconnect to external providers after their packages have been updated
+ if (mNetworkLocationProvider != null &&
+ mNetworkLocationProviderPackageName.startsWith(packageDot)) {
+ mNetworkLocationProvider.reconnect();
+ }
+ if (mGeocodeProvider != null &&
+ mGeocodeProviderPackageName.startsWith(packageDot)) {
+ mGeocodeProvider.reconnect();
+ }
}
} catch (Exception e) {
// Log, don't crash!
@@ -1931,17 +1945,8 @@
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
- String packageDot = packageName + ".";
-
- // reconnect to external providers after their packages have been updated
- if (mNetworkLocationProvider != null &&
- mNetworkLocationProviderPackageName.startsWith(packageDot)) {
- mNetworkLocationProvider.reconnect();
- }
- if (mGeocodeProvider != null &&
- mGeocodeProviderPackageName.startsWith(packageDot)) {
- mGeocodeProvider.reconnect();
- }
+ // Called by main thread; divert work to LocationWorker.
+ Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
}
};
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 9d4064d..a4cbcdb 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3931,17 +3931,22 @@
allowed = false;
} else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE
|| bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
- allowed = (checkSignaturesLP(bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
+ allowed = (checkSignaturesLP(
+ bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
|| (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
- if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
+ if (!allowed && bp.protectionLevel
+ == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
if (isSystemApp(pkg)) {
// For updated system applications, the signatureOrSystem permission
// is granted only if it had been defined by the original application.
if (isUpdatedSystemApp(pkg)) {
- PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName);
- if(sysPs.grantedPermissions.contains(perm)) {
+ PackageSetting sysPs = mSettings.getDisabledSystemPkg(
+ pkg.packageName);
+ final GrantedPermissions origGp = sysPs.sharedUser != null
+ ? sysPs.sharedUser : sysPs;
+ if (origGp.grantedPermissions.contains(perm)) {
allowed = true;
} else {
allowed = false;
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 540c7fe..55b7c9e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1148,12 +1148,12 @@
if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
return false;
}
- if (ws != null) {
- enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
- }
if (ws != null && ws.size() == 0) {
ws = null;
}
+ if (ws != null) {
+ enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
+ }
if (ws == null) {
ws = new WorkSource(Binder.getCallingUid());
}
@@ -1201,17 +1201,18 @@
++mScanLocksAcquired;
break;
}
+
+ // Be aggressive about adding new locks into the accounted state...
+ // we want to over-report rather than under-report.
+ reportStartWorkSource();
+
+ updateWifiState();
+ return true;
} catch (RemoteException e) {
+ return false;
} finally {
Binder.restoreCallingIdentity(ident);
}
-
- // Be aggressive about adding new locks into the accounted state...
- // we want to over-report rather than under-report.
- reportStartWorkSource();
-
- updateWifiState();
- return true;
}
public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
@@ -1257,9 +1258,9 @@
hadLock = (wifiLock != null);
- if (hadLock) {
- long ident = Binder.clearCallingIdentity();
- try {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (hadLock) {
noteAcquireWifiLock(wifiLock);
switch(wifiLock.mMode) {
case WifiManager.WIFI_MODE_FULL:
@@ -1269,13 +1270,16 @@
++mScanLocksReleased;
break;
}
- } catch (RemoteException e) {
- } finally {
- Binder.restoreCallingIdentity(ident);
}
+
+ // TODO - should this only happen if you hadLock?
+ updateWifiState();
+
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- // TODO - should this only happen if you hadLock?
- updateWifiState();
+
return hadLock;
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 59f7434..8be980f 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -804,7 +804,9 @@
// stop intercepting input
mDragState.unregister();
- mInputMonitor.updateInputWindowsLw();
+ synchronized (mWindowMap) {
+ mInputMonitor.updateInputWindowsLw();
+ }
// free our resources and drop all the object references
mDragState.reset();
@@ -5670,13 +5672,6 @@
mTempInputWindows.clear();
}
- /* Provides feedback for a virtual key down. */
- public void virtualKeyDownFeedback() {
- synchronized (mWindowMap) {
- mPolicy.performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
- }
- }
-
/* Notifies that the lid switch changed state. */
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
mPolicy.notifyLidSwitchChanged(whenNanos, lidOpen);
@@ -8128,7 +8123,8 @@
WindowState win = allAppWindows.get(i);
if (win == startingWindow || win.mAppFreezing
|| win.mViewVisibility != View.VISIBLE
- || win.mAttrs.type == TYPE_APPLICATION_STARTING) {
+ || win.mAttrs.type == TYPE_APPLICATION_STARTING
+ || win.mDestroying) {
continue;
}
if (DEBUG_VISIBILITY) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3084c16..83351bc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6886,6 +6886,9 @@
sb.append("Subject: ").append(subject).append("\n");
}
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
+ if (Debug.isDebuggerConnected()) {
+ sb.append("Debugger: Connected\n");
+ }
sb.append("\n");
// Do the rest in a worker thread to avoid blocking the caller on I/O
diff --git a/services/java/com/android/server/location/GeocoderProxy.java b/services/java/com/android/server/location/GeocoderProxy.java
index d9b49fd..e3131fe 100644
--- a/services/java/com/android/server/location/GeocoderProxy.java
+++ b/services/java/com/android/server/location/GeocoderProxy.java
@@ -41,8 +41,8 @@
private final Context mContext;
private final Intent mIntent;
- private final Connection mServiceConnection = new Connection();
- private IGeocodeProvider mProvider;
+ private final Object mMutex = new Object(); // synchronizes access to mServiceConnection
+ private Connection mServiceConnection = new Connection(); // never null
public GeocoderProxy(Context context, String serviceName) {
mContext = context;
@@ -50,34 +50,48 @@
mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
+ /**
+ * When unbundled NetworkLocationService package is updated, we
+ * need to unbind from the old version and re-bind to the new one.
+ */
public void reconnect() {
- synchronized (mServiceConnection) {
+ synchronized (mMutex) {
mContext.unbindService(mServiceConnection);
+ mServiceConnection = new Connection();
mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
}
private class Connection implements ServiceConnection {
+
+ private IGeocodeProvider mProvider;
+
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "onServiceConnected " + className);
- synchronized (mServiceConnection) {
+ synchronized (this) {
mProvider = IGeocodeProvider.Stub.asInterface(service);
}
}
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, "onServiceDisconnected " + className);
- synchronized (mServiceConnection) {
+ synchronized (this) {
mProvider = null;
}
}
+
+ public IGeocodeProvider getProvider() {
+ synchronized (this) {
+ return mProvider;
+ }
+ }
}
public String getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
IGeocodeProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
+ synchronized (mMutex) {
+ provider = mServiceConnection.getProvider();
}
if (provider != null) {
try {
@@ -95,8 +109,8 @@
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
IGeocodeProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
+ synchronized (mMutex) {
+ provider = mServiceConnection.getProvider();
}
if (provider != null) {
try {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index e9eb4f0..87271e7 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -1228,6 +1228,7 @@
private void reportAGpsStatus(int type, int status) {
switch (status) {
case GPS_REQUEST_AGPS_DATA_CONN:
+ if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
// Set mAGpsDataConnectionState before calling startUsingNetworkFeature
// to avoid a race condition with handleUpdateNetworkState()
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
@@ -1250,6 +1251,7 @@
}
break;
case GPS_RELEASE_AGPS_DATA_CONN:
+ if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
mConnMgr.stopUsingNetworkFeature(
ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
@@ -1258,13 +1260,13 @@
}
break;
case GPS_AGPS_DATA_CONNECTED:
- // Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
+ if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
break;
case GPS_AGPS_DATA_CONN_DONE:
- // Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
+ if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
break;
case GPS_AGPS_DATA_CONN_FAILED:
- // Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
+ if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
break;
}
}
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index ef2056b..1a1a170 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -45,10 +45,10 @@
private final Context mContext;
private final String mName;
- private final String mServiceName;
- private ILocationProvider mProvider;
- private Handler mHandler;
- private final Connection mServiceConnection = new Connection();
+ private final Intent mIntent;
+ private final Handler mHandler;
+ private final Object mMutex = new Object(); // synchronizes access to non-final members
+ private Connection mServiceConnection = new Connection(); // never null
// cached values set by the location manager
private boolean mLocationTracking = false;
@@ -58,89 +58,105 @@
private int mNetworkState;
private NetworkInfo mNetworkInfo;
- // for caching requiresNetwork, requiresSatellite, etc.
- private DummyLocationProvider mCachedAttributes;
-
// constructor for proxying location providers implemented in a separate service
public LocationProviderProxy(Context context, String name, String serviceName,
Handler handler) {
mContext = context;
mName = name;
- mServiceName = serviceName;
+ mIntent = new Intent(serviceName);
mHandler = handler;
- mContext.bindService(new Intent(serviceName), mServiceConnection, Context.BIND_AUTO_CREATE);
+ mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
+ /**
+ * When unbundled NetworkLocationService package is updated, we
+ * need to unbind from the old version and re-bind to the new one.
+ */
public void reconnect() {
- synchronized (mServiceConnection) {
- // unbind first
+ synchronized (mMutex) {
mContext.unbindService(mServiceConnection);
- mContext.bindService(new Intent(mServiceName), mServiceConnection,
- Context.BIND_AUTO_CREATE);
+ mServiceConnection = new Connection();
+ mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
}
- private class Connection implements ServiceConnection {
+ private class Connection implements ServiceConnection, Runnable {
+
+ private ILocationProvider mProvider;
+
+ // for caching requiresNetwork, requiresSatellite, etc.
+ private DummyLocationProvider mCachedAttributes; // synchronized by mMutex
+
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "LocationProviderProxy.onServiceConnected " + className);
- synchronized (mServiceConnection) {
+ synchronized (this) {
mProvider = ILocationProvider.Stub.asInterface(service);
if (mProvider != null) {
- mHandler.post(mServiceConnectedTask);
+ mHandler.post(this);
}
}
}
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, "LocationProviderProxy.onServiceDisconnected " + className);
- synchronized (mServiceConnection) {
+ synchronized (this) {
mProvider = null;
}
}
- }
- private Runnable mServiceConnectedTask = new Runnable() {
+ public synchronized ILocationProvider getProvider() {
+ return mProvider;
+ }
+
+ public synchronized DummyLocationProvider getCachedAttributes() {
+ return mCachedAttributes;
+ }
+
public void run() {
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
+ synchronized (mMutex) {
+ if (mServiceConnection != this) {
+ // This ServiceConnection no longer the one we want to bind to.
+ return;
+ }
+ ILocationProvider provider = getProvider();
if (provider == null) {
return;
}
- }
- if (mCachedAttributes == null) {
+ // resend previous values from the location manager if the service has restarted
try {
- mCachedAttributes = new DummyLocationProvider(mName, null);
- mCachedAttributes.setRequiresNetwork(provider.requiresNetwork());
- mCachedAttributes.setRequiresSatellite(provider.requiresSatellite());
- mCachedAttributes.setRequiresCell(provider.requiresCell());
- mCachedAttributes.setHasMonetaryCost(provider.hasMonetaryCost());
- mCachedAttributes.setSupportsAltitude(provider.supportsAltitude());
- mCachedAttributes.setSupportsSpeed(provider.supportsSpeed());
- mCachedAttributes.setSupportsBearing(provider.supportsBearing());
- mCachedAttributes.setPowerRequirement(provider.getPowerRequirement());
- mCachedAttributes.setAccuracy(provider.getAccuracy());
+ if (mEnabled) {
+ provider.enable();
+ }
+ if (mLocationTracking) {
+ provider.enableLocationTracking(true);
+ }
+ if (mMinTime >= 0) {
+ provider.setMinTime(mMinTime, mMinTimeSource);
+ }
+ if (mNetworkInfo != null) {
+ provider.updateNetworkState(mNetworkState, mNetworkInfo);
+ }
} catch (RemoteException e) {
- mCachedAttributes = null;
}
- }
- // resend previous values from the location manager if the service has restarted
- try {
- if (mEnabled) {
- provider.enable();
+ // init cache of parameters
+ if (mCachedAttributes == null) {
+ try {
+ mCachedAttributes = new DummyLocationProvider(mName, null);
+ mCachedAttributes.setRequiresNetwork(provider.requiresNetwork());
+ mCachedAttributes.setRequiresSatellite(provider.requiresSatellite());
+ mCachedAttributes.setRequiresCell(provider.requiresCell());
+ mCachedAttributes.setHasMonetaryCost(provider.hasMonetaryCost());
+ mCachedAttributes.setSupportsAltitude(provider.supportsAltitude());
+ mCachedAttributes.setSupportsSpeed(provider.supportsSpeed());
+ mCachedAttributes.setSupportsBearing(provider.supportsBearing());
+ mCachedAttributes.setPowerRequirement(provider.getPowerRequirement());
+ mCachedAttributes.setAccuracy(provider.getAccuracy());
+ } catch (RemoteException e) {
+ mCachedAttributes = null;
+ }
}
- if (mLocationTracking) {
- provider.enableLocationTracking(true);
- }
- if (mMinTime >= 0) {
- provider.setMinTime(mMinTime, mMinTimeSource);
- }
- if (mNetworkInfo != null) {
- provider.updateNetworkState(mNetworkState, mNetworkInfo);
- }
- } catch (RemoteException e) {
}
}
};
@@ -149,79 +165,101 @@
return mName;
}
+ private DummyLocationProvider getCachedAttributes() {
+ synchronized (mMutex) {
+ return mServiceConnection.getCachedAttributes();
+ }
+ }
+
public boolean requiresNetwork() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.requiresNetwork();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.requiresNetwork();
} else {
return false;
}
}
public boolean requiresSatellite() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.requiresSatellite();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.requiresSatellite();
} else {
return false;
}
}
public boolean requiresCell() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.requiresCell();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.requiresCell();
} else {
return false;
}
}
public boolean hasMonetaryCost() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.hasMonetaryCost();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.hasMonetaryCost();
} else {
return false;
}
}
public boolean supportsAltitude() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.supportsAltitude();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.supportsAltitude();
} else {
return false;
}
}
public boolean supportsSpeed() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.supportsSpeed();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.supportsSpeed();
} else {
return false;
}
}
public boolean supportsBearing() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.supportsBearing();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.supportsBearing();
} else {
return false;
}
}
public int getPowerRequirement() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.getPowerRequirement();
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.getPowerRequirement();
+ } else {
+ return -1;
+ }
+ }
+
+ public int getAccuracy() {
+ DummyLocationProvider cachedAttributes = getCachedAttributes();
+ if (cachedAttributes != null) {
+ return cachedAttributes.getAccuracy();
} else {
return -1;
}
}
public boolean meetsCriteria(Criteria criteria) {
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- return provider.meetsCriteria(criteria);
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ return provider.meetsCriteria(criteria);
+ } catch (RemoteException e) {
+ }
}
}
// default implementation if we lost connection to the provider
@@ -246,50 +284,42 @@
return true;
}
- public int getAccuracy() {
- if (mCachedAttributes != null) {
- return mCachedAttributes.getAccuracy();
- } else {
- return -1;
- }
- }
-
public void enable() {
- mEnabled = true;
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.enable();
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ mEnabled = true;
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.enable();
+ } catch (RemoteException e) {
+ }
}
}
}
public void disable() {
- mEnabled = false;
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.disable();
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ mEnabled = false;
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.disable();
+ } catch (RemoteException e) {
+ }
}
}
}
public boolean isEnabled() {
- return mEnabled;
+ synchronized (mMutex) {
+ return mEnabled;
+ }
}
public int getStatus(Bundle extras) {
ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
+ synchronized (mMutex) {
+ provider = mServiceConnection.getProvider();
}
if (provider != null) {
try {
@@ -301,9 +331,9 @@
}
public long getStatusUpdateTime() {
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
+ ILocationProvider provider;
+ synchronized (mMutex) {
+ provider = mServiceConnection.getProvider();
}
if (provider != null) {
try {
@@ -315,32 +345,39 @@
}
public String getInternalState() {
- try {
- return mProvider.getInternalState();
- } catch (RemoteException e) {
- Log.e(TAG, "getInternalState failed", e);
- return null;
- }
- }
-
- public boolean isLocationTracking() {
- return mLocationTracking;
- }
-
- public void enableLocationTracking(boolean enable) {
- mLocationTracking = enable;
- if (!enable) {
- mMinTime = -1;
- mMinTimeSource.clear();
- }
ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
+ synchronized (mMutex) {
+ provider = mServiceConnection.getProvider();
}
if (provider != null) {
try {
- provider.enableLocationTracking(enable);
+ return provider.getInternalState();
} catch (RemoteException e) {
+ Log.e(TAG, "getInternalState failed", e);
+ }
+ }
+ return null;
+ }
+
+ public boolean isLocationTracking() {
+ synchronized (mMutex) {
+ return mLocationTracking;
+ }
+ }
+
+ public void enableLocationTracking(boolean enable) {
+ synchronized (mMutex) {
+ mLocationTracking = enable;
+ if (!enable) {
+ mMinTime = -1;
+ mMinTimeSource.clear();
+ }
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.enableLocationTracking(enable);
+ } catch (RemoteException e) {
+ }
}
}
}
@@ -350,88 +387,84 @@
}
public long getMinTime() {
- return mMinTime;
+ synchronized (mMutex) {
+ return mMinTime;
+ }
}
public void setMinTime(long minTime, WorkSource ws) {
- mMinTime = minTime;
- mMinTimeSource.set(ws);
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.setMinTime(minTime, ws);
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ mMinTime = minTime;
+ mMinTimeSource.set(ws);
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.setMinTime(minTime, ws);
+ } catch (RemoteException e) {
+ }
}
}
}
public void updateNetworkState(int state, NetworkInfo info) {
- mNetworkState = state;
- mNetworkInfo = info;
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.updateNetworkState(state, info);
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ mNetworkState = state;
+ mNetworkInfo = info;
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.updateNetworkState(state, info);
+ } catch (RemoteException e) {
+ }
}
}
}
public void updateLocation(Location location) {
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.updateLocation(location);
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.updateLocation(location);
+ } catch (RemoteException e) {
+ }
}
}
}
public boolean sendExtraCommand(String command, Bundle extras) {
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.sendExtraCommand(command, extras);
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ return provider.sendExtraCommand(command, extras);
+ } catch (RemoteException e) {
+ }
}
}
return false;
}
public void addListener(int uid) {
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.addListener(uid);
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.addListener(uid);
+ } catch (RemoteException e) {
+ }
}
}
}
public void removeListener(int uid) {
- ILocationProvider provider;
- synchronized (mServiceConnection) {
- provider = mProvider;
- }
- if (provider != null) {
- try {
- provider.removeListener(uid);
- } catch (RemoteException e) {
+ synchronized (mMutex) {
+ ILocationProvider provider = mServiceConnection.getProvider();
+ if (provider != null) {
+ try {
+ provider.removeListener(uid);
+ } catch (RemoteException e) {
+ }
}
}
}
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 8e7cadc..397a84a 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -67,6 +67,7 @@
jint healthDead;
jint healthOverVoltage;
jint healthUnspecifiedFailure;
+ jint healthCold;
};
static BatteryManagerConstants gConstants;
@@ -104,6 +105,7 @@
static jint getBatteryHealth(const char* status)
{
switch (status[0]) {
+ case 'C': return gConstants.healthCold; // Cold
case 'D': return gConstants.healthDead; // Dead
case 'G': return gConstants.healthGood; // Good
case 'O': {
@@ -390,6 +392,9 @@
gConstants.healthUnspecifiedFailure = env->GetStaticIntField(clazz,
env->GetStaticFieldID(clazz, "BATTERY_HEALTH_UNSPECIFIED_FAILURE", "I"));
+ gConstants.healthCold = env->GetStaticIntField(clazz,
+ env->GetStaticFieldID(clazz, "BATTERY_HEALTH_COLD", "I"));
+
return jniRegisterNativeMethods(env, "com/android/server/BatteryService", sMethods, NELEM(sMethods));
}
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 4f1fab7..e15e8d8 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -50,7 +50,6 @@
jmethodID notifyLidSwitchChanged;
jmethodID notifyInputChannelBroken;
jmethodID notifyANR;
- jmethodID virtualKeyDownFeedback;
jmethodID interceptKeyBeforeQueueing;
jmethodID interceptKeyBeforeDispatching;
jmethodID checkInjectEventsPermission;
@@ -182,11 +181,6 @@
virtual bool getDisplayInfo(int32_t displayId,
int32_t* width, int32_t* height, int32_t* orientation);
- virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags);
- virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
- uint32_t& policyFlags);
- virtual int32_t interceptGeneric(nsecs_t when, uint32_t& policyFlags);
virtual bool filterTouchEvents();
virtual bool filterJumpyTouchEvents();
virtual void getVirtualKeyDefinitions(const String8& deviceName,
@@ -197,6 +191,8 @@
/* --- InputDispatcherPolicyInterface implementation --- */
+ virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
+ uint32_t policyFlags);
virtual void notifyConfigurationChanged(nsecs_t when);
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputChannel>& inputChannel);
@@ -204,6 +200,10 @@
virtual nsecs_t getKeyRepeatTimeout();
virtual nsecs_t getKeyRepeatDelay();
virtual int32_t getMaxEventsPerSecond();
+ virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
+ int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
+ uint32_t& policyFlags);
+ virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags);
virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType);
@@ -254,7 +254,6 @@
static bool populateWindow(JNIEnv* env, jobject windowObj, InputWindow& outWindow);
- static bool isPolicyKey(int32_t keyCode, bool isScreenOn);
static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName);
static inline JNIEnv* jniEnv() {
@@ -290,37 +289,6 @@
dump.append("\n");
}
-bool NativeInputManager::isPolicyKey(int32_t keyCode, bool isScreenOn) {
- // Special keys that the WindowManagerPolicy might care about.
- switch (keyCode) {
- case AKEYCODE_VOLUME_UP:
- case AKEYCODE_VOLUME_DOWN:
- case AKEYCODE_ENDCALL:
- case AKEYCODE_POWER:
- case AKEYCODE_CALL:
- case AKEYCODE_HOME:
- case AKEYCODE_MENU:
- case AKEYCODE_SEARCH:
- // media keys
- case AKEYCODE_HEADSETHOOK:
- case AKEYCODE_MEDIA_PLAY_PAUSE:
- case AKEYCODE_MEDIA_STOP:
- case AKEYCODE_MEDIA_NEXT:
- case AKEYCODE_MEDIA_PREVIOUS:
- case AKEYCODE_MEDIA_REWIND:
- case AKEYCODE_MEDIA_FAST_FORWARD:
- // The policy always cares about these keys.
- return true;
- default:
- // We need to pass all keys to the policy in the following cases:
- // - screen is off
- // - keyguard is visible
- // - policy is performing key chording
- //return ! isScreenOn || keyguardVisible || chording;
- return true; // XXX stubbed out for now
- }
-}
-
bool NativeInputManager::checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
LOGE("An exception was thrown by callback '%s'.", methodName);
@@ -453,115 +421,6 @@
return result;
}
-bool NativeInputManager::isScreenOn() {
- return android_server_PowerManagerService_isScreenOn();
-}
-
-bool NativeInputManager::isScreenBright() {
- return android_server_PowerManagerService_isScreenBright();
-}
-
-int32_t NativeInputManager::interceptKey(nsecs_t when,
- int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
-#if DEBUG_INPUT_READER_POLICY
- LOGD("interceptKey - when=%lld, deviceId=%d, down=%d, keyCode=%d, scanCode=%d, "
- "policyFlags=0x%x",
- when, deviceId, down, keyCode, scanCode, policyFlags);
-#endif
-
- if (down && (policyFlags & POLICY_FLAG_VIRTUAL)) {
- JNIEnv* env = jniEnv();
- env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
- checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
- }
-
- const int32_t WM_ACTION_PASS_TO_USER = 1;
- const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
- const int32_t WM_ACTION_GO_TO_SLEEP = 4;
-
- bool isScreenOn = this->isScreenOn();
- bool isScreenBright = this->isScreenBright();
-
- jint wmActions = 0;
- if (isPolicyKey(keyCode, isScreenOn)) {
- JNIEnv* env = jniEnv();
-
- wmActions = env->CallIntMethod(mCallbacksObj,
- gCallbacksClassInfo.interceptKeyBeforeQueueing,
- when, keyCode, down, policyFlags, isScreenOn);
- if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
- wmActions = 0;
- }
- } else {
- wmActions = WM_ACTION_PASS_TO_USER;
- }
-
- int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
- if (! isScreenOn) {
- // Key presses and releases wake the device.
- policyFlags |= POLICY_FLAG_WOKE_HERE;
- }
-
- if (! isScreenBright) {
- // Key presses and releases brighten the screen if dimmed.
- policyFlags |= POLICY_FLAG_BRIGHT_HERE;
- }
-
- if (wmActions & WM_ACTION_GO_TO_SLEEP) {
- android_server_PowerManagerService_goToSleep(when);
- }
-
- if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
- android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
- }
-
- if (wmActions & WM_ACTION_PASS_TO_USER) {
- actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
- }
-
- return actions;
-}
-
-int32_t NativeInputManager::interceptGeneric(nsecs_t when, uint32_t& policyFlags) {
-#if DEBUG_INPUT_READER_POLICY
- LOGD("interceptGeneric - when=%lld, policyFlags=0x%x", when, policyFlags);
-#endif
-
- int32_t actions = InputReaderPolicyInterface::ACTION_NONE;
- if (isScreenOn()) {
- // Only dispatch events when the device is awake.
- // Do not wake the device.
- actions |= InputReaderPolicyInterface::ACTION_DISPATCH;
-
- if (! isScreenBright()) {
- // Brighten the screen if dimmed.
- policyFlags |= POLICY_FLAG_BRIGHT_HERE;
- }
- }
-
- return actions;
-}
-
-int32_t NativeInputManager::interceptSwitch(nsecs_t when, int32_t switchCode,
- int32_t switchValue, uint32_t& policyFlags) {
-#if DEBUG_INPUT_READER_POLICY
- LOGD("interceptSwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x",
- when, switchCode, switchValue, policyFlags);
-#endif
-
- JNIEnv* env = jniEnv();
-
- switch (switchCode) {
- case SW_LID:
- env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged,
- when, switchValue == 0);
- checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
- break;
- }
-
- return InputReaderPolicyInterface::ACTION_NONE;
-}
-
bool NativeInputManager::filterTouchEvents() {
if (mFilterTouchEvents < 0) {
JNIEnv* env = jniEnv();
@@ -691,6 +550,24 @@
}
}
+void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,
+ int32_t switchValue, uint32_t policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ LOGD("notifySwitch - when=%lld, switchCode=%d, switchValue=%d, policyFlags=0x%x",
+ when, switchCode, switchValue, policyFlags);
+#endif
+
+ JNIEnv* env = jniEnv();
+
+ switch (switchCode) {
+ case SW_LID:
+ env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.notifyLidSwitchChanged,
+ when, switchValue == 0);
+ checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
+ break;
+ }
+}
+
void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
#if DEBUG_INPUT_DISPATCHER_POLICY
LOGD("notifyConfigurationChanged - when=%lld", when);
@@ -943,13 +820,88 @@
mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
}
-bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
- const KeyEvent* keyEvent, uint32_t policyFlags) {
- bool isScreenOn = this->isScreenOn();
- if (! isPolicyKey(keyEvent->getKeyCode(), isScreenOn)) {
- return false;
+bool NativeInputManager::isScreenOn() {
+ return android_server_PowerManagerService_isScreenOn();
+}
+
+bool NativeInputManager::isScreenBright() {
+ return android_server_PowerManagerService_isScreenBright();
+}
+
+void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
+ int32_t deviceId, int32_t action, int32_t &flags,
+ int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ LOGD("interceptKeyBeforeQueueing - when=%lld, deviceId=%d, action=%d, flags=%d, "
+ "keyCode=%d, scanCode=%d, policyFlags=0x%x",
+ when, deviceId, action, flags, keyCode, scanCode, policyFlags);
+#endif
+
+ if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
+ policyFlags |= POLICY_FLAG_VIRTUAL;
+ flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
}
+ const int32_t WM_ACTION_PASS_TO_USER = 1;
+ const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
+ const int32_t WM_ACTION_GO_TO_SLEEP = 4;
+
+ bool isScreenOn = this->isScreenOn();
+ bool isScreenBright = this->isScreenBright();
+
+ JNIEnv* env = jniEnv();
+ jint wmActions = env->CallIntMethod(mCallbacksObj,
+ gCallbacksClassInfo.interceptKeyBeforeQueueing,
+ when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn);
+ if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+ wmActions = 0;
+ }
+
+ if (policyFlags & POLICY_FLAG_TRUSTED) {
+ if (! isScreenOn) {
+ // Key presses and releases wake the device.
+ policyFlags |= POLICY_FLAG_WOKE_HERE;
+ flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
+
+ if (! isScreenBright) {
+ // Key presses and releases brighten the screen if dimmed.
+ policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+ }
+
+ if (wmActions & WM_ACTION_GO_TO_SLEEP) {
+ android_server_PowerManagerService_goToSleep(when);
+ }
+
+ if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
+ android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT);
+ }
+ }
+
+ if (wmActions & WM_ACTION_PASS_TO_USER) {
+ policyFlags |= POLICY_FLAG_PASS_TO_USER;
+ }
+}
+
+void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags);
+#endif
+
+ if (isScreenOn()) {
+ // Only dispatch events when the device is awake.
+ // Do not wake the device.
+ policyFlags |= POLICY_FLAG_PASS_TO_USER;
+
+ if ((policyFlags & POLICY_FLAG_TRUSTED) && !isScreenBright()) {
+ // Brighten the screen if dimmed.
+ policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+ }
+ }
+}
+
+bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
+ const KeyEvent* keyEvent, uint32_t policyFlags) {
JNIEnv* env = jniEnv();
// Note: inputChannel may be null.
@@ -1281,7 +1233,6 @@
static jboolean android_server_InputManager_nativeTransferTouchFocus(JNIEnv* env,
jclass clazz, jobject fromChannelObj, jobject toChannelObj) {
if (checkInputManagerUnitialized(env)) {
- LOGD("input manager uninitialized; bailing");
return false;
}
@@ -1291,7 +1242,6 @@
android_view_InputChannel_getInputChannel(env, toChannelObj);
if (fromChannel == NULL || toChannel == NULL) {
- LOGD("bailing because from=%p to=%p", fromChannel, toChannel);
return false;
}
@@ -1387,9 +1337,6 @@
GET_METHOD_ID(gCallbacksClassInfo.notifyANR, gCallbacksClassInfo.clazz,
"notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
- GET_METHOD_ID(gCallbacksClassInfo.virtualKeyDownFeedback, gCallbacksClassInfo.clazz,
- "virtualKeyDownFeedback", "()V");
-
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
"interceptKeyBeforeQueueing", "(JIZIZ)I");
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 71c7aba..bd722d7 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -238,45 +238,57 @@
return interface;
}
-static const AGpsInterface* GetAGpsInterface()
-{
- if (!sGpsInterface)
+static const GpsInterface* GetGpsInterface(JNIEnv* env, jobject obj) {
+ // this must be set before calling into the HAL library
+ if (!mCallbacksObj)
+ mCallbacksObj = env->NewGlobalRef(obj);
+
+ if (!sGpsInterface) {
sGpsInterface = get_gps_interface();
- if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) {
+ sGpsInterface = NULL;
+ return NULL;
+ }
+ }
+ return sGpsInterface;
+}
+
+static const AGpsInterface* GetAGpsInterface(JNIEnv* env, jobject obj)
+{
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (!interface)
return NULL;
if (!sAGpsInterface) {
- sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
+ sAGpsInterface = (const AGpsInterface*)interface->get_extension(AGPS_INTERFACE);
if (sAGpsInterface)
sAGpsInterface->init(&sAGpsCallbacks);
}
return sAGpsInterface;
}
-static const GpsNiInterface* GetNiInterface()
+static const GpsNiInterface* GetNiInterface(JNIEnv* env, jobject obj)
{
- if (!sGpsInterface)
- sGpsInterface = get_gps_interface();
- if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (!interface)
return NULL;
if (!sGpsNiInterface) {
- sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+ sGpsNiInterface = (const GpsNiInterface*)interface->get_extension(GPS_NI_INTERFACE);
if (sGpsNiInterface)
sGpsNiInterface->init(&sGpsNiCallbacks);
}
return sGpsNiInterface;
}
-static const AGpsRilInterface* GetAGpsRilInterface()
+static const AGpsRilInterface* GetAGpsRilInterface(JNIEnv* env, jobject obj)
{
- if (!sGpsInterface)
- sGpsInterface = get_gps_interface();
- if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (!interface)
return NULL;
if (!sAGpsRilInterface) {
- sAGpsRilInterface = (const AGpsRilInterface*)sGpsInterface->get_extension(AGPS_RIL_INTERFACE);
+ sAGpsRilInterface = (const AGpsRilInterface*)interface->get_extension(AGPS_RIL_INTERFACE);
if (sAGpsRilInterface)
sAGpsRilInterface->init(&sAGpsRilCallbacks);
}
@@ -297,53 +309,62 @@
}
static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
- if (!sGpsInterface)
- sGpsInterface = get_gps_interface();
- return (sGpsInterface != NULL);
+ return (sGpsInterface != NULL || get_gps_interface() != NULL);
}
static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
{
- // this must be set before calling into the HAL library
- if (!mCallbacksObj)
- mCallbacksObj = env->NewGlobalRef(obj);
-
- if (!sGpsInterface)
- sGpsInterface = get_gps_interface();
- if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (!interface)
return false;
if (!sGpsDebugInterface)
- sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
+ sGpsDebugInterface = (const GpsDebugInterface*)interface->get_extension(GPS_DEBUG_INTERFACE);
return true;
}
static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
{
- sGpsInterface->cleanup();
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (interface)
+ interface->cleanup();
}
static jboolean android_location_GpsLocationProvider_set_position_mode(JNIEnv* env, jobject obj,
jint mode, jint recurrence, jint min_interval, jint preferred_accuracy, jint preferred_time)
{
- return (sGpsInterface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
- preferred_time) == 0);
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (interface)
+ return (interface->set_position_mode(mode, recurrence, min_interval, preferred_accuracy,
+ preferred_time) == 0);
+ else
+ return false;
}
static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj)
{
- return (sGpsInterface->start() == 0);
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (interface)
+ return (interface->start() == 0);
+ else
+ return false;
}
static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
{
- return (sGpsInterface->stop() == 0);
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (interface)
+ return (interface->stop() == 0);
+ else
+ return false;
}
static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
{
- sGpsInterface->delete_aiding_data(flags);
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (interface)
+ interface->delete_aiding_data(flags);
}
static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
@@ -381,7 +402,7 @@
jobject obj, jint type, jint mcc, jint mnc, jint lac, jint cid)
{
AGpsRefLocation location;
- const AGpsRilInterface* interface = GetAGpsRilInterface();
+ const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
if (!interface) {
LOGE("no AGPS RIL interface in agps_set_reference_location_cellid");
return;
@@ -408,7 +429,7 @@
jobject obj, jbyteArray ni_msg, jint size)
{
size_t sz;
- const AGpsRilInterface* interface = GetAGpsRilInterface();
+ const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
if (!interface) {
LOGE("no AGPS RIL interface in send_ni_message");
return;
@@ -424,7 +445,7 @@
static void android_location_GpsLocationProvider_agps_set_id(JNIEnv *env,
jobject obj, jint type, jstring setid_string)
{
- const AGpsRilInterface* interface = GetAGpsRilInterface();
+ const AGpsRilInterface* interface = GetAGpsRilInterface(env, obj);
if (!interface) {
LOGE("no AGPS RIL interface in agps_set_id");
return;
@@ -451,19 +472,26 @@
static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj,
jlong time, jlong timeReference, jint uncertainty)
{
- sGpsInterface->inject_time(time, timeReference, uncertainty);
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (interface)
+ interface->inject_time(time, timeReference, uncertainty);
}
static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
jdouble latitude, jdouble longitude, jfloat accuracy)
{
- sGpsInterface->inject_location(latitude, longitude, accuracy);
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (interface)
+ interface->inject_location(latitude, longitude, accuracy);
}
static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
{
if (!sGpsXtraInterface) {
- sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
+ const GpsInterface* interface = GetGpsInterface(env, obj);
+ if (!interface)
+ return false;
+ sGpsXtraInterface = (const GpsXtraInterface*)interface->get_extension(GPS_XTRA_INTERFACE);
if (sGpsXtraInterface) {
int result = sGpsXtraInterface->init(&sGpsXtraCallbacks);
if (result) {
@@ -485,7 +513,7 @@
static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
{
- const AGpsInterface* interface = GetAGpsInterface();
+ const AGpsInterface* interface = GetAGpsInterface(env, obj);
if (!interface) {
LOGE("no AGPS interface in agps_data_conn_open");
return;
@@ -501,7 +529,7 @@
static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
{
- const AGpsInterface* interface = GetAGpsInterface();
+ const AGpsInterface* interface = GetAGpsInterface(env, obj);
if (!interface) {
LOGE("no AGPS interface in agps_data_conn_open");
return;
@@ -511,7 +539,7 @@
static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
{
- const AGpsInterface* interface = GetAGpsInterface();
+ const AGpsInterface* interface = GetAGpsInterface(env, obj);
if (!interface) {
LOGE("no AGPS interface in agps_data_conn_open");
return;
@@ -522,7 +550,7 @@
static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
jint type, jstring hostname, jint port)
{
- const AGpsInterface* interface = GetAGpsInterface();
+ const AGpsInterface* interface = GetAGpsInterface(env, obj);
if (!interface) {
LOGE("no AGPS interface in agps_data_conn_open");
return;
@@ -535,7 +563,7 @@
static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
jint notifId, jint response)
{
- const GpsNiInterface* interface = GetNiInterface();
+ const GpsNiInterface* interface = GetNiInterface(env, obj);
if (!interface) {
LOGE("no NI interface in send_ni_response");
return;
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index e37733c..893ae88 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1823,12 +1823,19 @@
}
/**
+ * Determines if the specified number is actually a URI
+ * (i.e. a SIP address) rather than a regular PSTN phone number,
+ * based on whether or not the number contains an "@" character.
+ *
* @hide
* @param number
* @return true if number contains @
*/
public static boolean isUriNumber(String number) {
- return number != null && number.contains("@");
+ // Note we allow either "@" or "%40" to indicate a URI, in case
+ // the passed-in string is URI-escaped. (Neither "@" nor "%40"
+ // will ever be found in a legal PSTN number.)
+ return number != null && (number.contains("@") || number.contains("%40"));
}
/**
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 7a026fa..b09df82 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -925,7 +925,7 @@
}
if (hasActiveFgCall()) {
- getActiveFgCall().getPhone().sendDtmf(c);
+ getActiveFgCall().getPhone().startDtmf(c);
result = true;
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 8c2280b..35d5564 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1969,26 +1969,30 @@
sendScreenState(true);
}
- private void setRadioStateFromRILInt(int state) {
- RadioState newState;
+ private RadioState getRadioStateFromInt(int stateInt) {
+ RadioState state;
/* RIL_RadioState ril.h */
- switch(state) {
- case 0: newState = RadioState.RADIO_OFF; break;
- case 1: newState = RadioState.RADIO_UNAVAILABLE; break;
- case 2: newState = RadioState.SIM_NOT_READY; break;
- case 3: newState = RadioState.SIM_LOCKED_OR_ABSENT; break;
- case 4: newState = RadioState.SIM_READY; break;
- case 5: newState = RadioState.RUIM_NOT_READY; break;
- case 6: newState = RadioState.RUIM_READY; break;
- case 7: newState = RadioState.RUIM_LOCKED_OR_ABSENT; break;
- case 8: newState = RadioState.NV_NOT_READY; break;
- case 9: newState = RadioState.NV_READY; break;
+ switch(stateInt) {
+ case 0: state = RadioState.RADIO_OFF; break;
+ case 1: state = RadioState.RADIO_UNAVAILABLE; break;
+ case 2: state = RadioState.SIM_NOT_READY; break;
+ case 3: state = RadioState.SIM_LOCKED_OR_ABSENT; break;
+ case 4: state = RadioState.SIM_READY; break;
+ case 5: state = RadioState.RUIM_NOT_READY; break;
+ case 6: state = RadioState.RUIM_READY; break;
+ case 7: state = RadioState.RUIM_LOCKED_OR_ABSENT; break;
+ case 8: state = RadioState.NV_NOT_READY; break;
+ case 9: state = RadioState.NV_READY; break;
default:
throw new RuntimeException(
- "Unrecognized RIL_RadioState: " +state);
+ "Unrecognized RIL_RadioState: " + stateInt);
}
+ return state;
+ }
+
+ private void switchToRadioState(RadioState newState) {
if (mInitialRadioStateChange) {
if (newState.isOn()) {
@@ -2369,9 +2373,10 @@
switch(response) {
case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
/* has bonus radio state int */
- setRadioStateFromRILInt(p.readInt());
+ RadioState newState = getRadioStateFromInt(p.readInt());
+ if (RILJ_LOGD) unsljLogMore(response, newState.toString());
- if (RILJ_LOGD) unsljLogMore(response, mState.toString());
+ switchToRadioState(newState);
break;
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 30a6324..fc03d1a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1204,7 +1204,8 @@
// Check if this is a different SIM than the previous one. If so unset the
// voice mail number.
String imsi = getVmSimImsi();
- if (imsi != null && !getSubscriberId().equals(imsi)) {
+ String imsiFromSIM = getSubscriberId();
+ if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
storeVoiceMailNumber(null);
setVmSimImsi(null);
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 878d30c..a951040 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.net.rtp.AudioGroup;
-import android.net.rtp.AudioStream;
import android.net.sip.SipAudioCall;
import android.net.sip.SipErrorCode;
import android.net.sip.SipException;
@@ -29,11 +28,9 @@
import android.os.Message;
import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
-import android.text.TextUtils;
import android.util.Log;
import com.android.internal.telephony.Call;
-import com.android.internal.telephony.CallerInfo;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.Phone;
@@ -385,40 +382,6 @@
}
}
- private CallerInfo createCallerInfo(String number, SipProfile callee) {
- SipProfile p = callee;
- String name = p.getDisplayName();
- if (TextUtils.isEmpty(name)) name = p.getUserName();
- CallerInfo info = new CallerInfo();
- info.name = name;
- info.phoneNumber = number;
- if (DEBUG) {
- Log.d(LOG_TAG, "create caller info from scratch:");
- Log.d(LOG_TAG, " name: " + info.name);
- Log.d(LOG_TAG, " numb: " + info.phoneNumber);
- }
- return info;
- }
-
- // from contacts
- private CallerInfo findCallerInfo(String number) {
- CallerInfo info = CallerInfo.getCallerInfo(mContext, number);
- if ((info == null) || (info.name == null)) return null;
- if (DEBUG) {
- Log.d(LOG_TAG, "got caller info from contact:");
- Log.d(LOG_TAG, " name: " + info.name);
- Log.d(LOG_TAG, " numb: " + info.phoneNumber);
- Log.d(LOG_TAG, " pres: " + info.numberPresentation);
- }
- return info;
- }
-
- private CallerInfo getCallerInfo(String number, SipProfile callee) {
- CallerInfo info = findCallerInfo(number);
- if (info == null) info = createCallerInfo(number, callee);
- return info;
- }
-
Connection dial(String originalNumber) throws SipException {
String calleeSipUri = originalNumber;
if (!calleeSipUri.contains("@")) {
@@ -427,8 +390,7 @@
try {
SipProfile callee =
new SipProfile.Builder(calleeSipUri).build();
- CallerInfo info = getCallerInfo(originalNumber, callee);
- SipConnection c = new SipConnection(this, callee, info);
+ SipConnection c = new SipConnection(this, callee);
connections.add(c);
c.dial();
setState(Call.State.DIALING);
@@ -464,10 +426,7 @@
void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) {
SipProfile callee = sipAudioCall.getPeerProfile();
- CallerInfo info = findCallerInfo(getUriString(callee));
- if (info == null) info = findCallerInfo(callee.getUserName());
- if (info == null) info = findCallerInfo(callee.getDisplayName());
- SipConnection c = new SipConnection(this, callee, info);
+ SipConnection c = new SipConnection(this, callee);
connections.add(c);
Call.State newState = makeCallWait ? State.WAITING : State.INCOMING;
@@ -703,12 +662,10 @@
}
};
- public SipConnection(SipCall owner, SipProfile callee,
- CallerInfo info) {
+ public SipConnection(SipCall owner, SipProfile callee) {
super(getUriString(callee));
mOwner = owner;
mPeer = callee;
- setUserData(info);
}
void initIncomingCall(SipAudioCall sipAudioCall, Call.State newState) {
diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java
index 050eddc..2514262 100644
--- a/voip/java/com/android/server/sip/SipHelper.java
+++ b/voip/java/com/android/server/sip/SipHelper.java
@@ -238,6 +238,8 @@
ClientTransaction tid = responseEvent.getClientTransaction();
ClientTransaction ct = authenticationHelper.handleChallenge(
responseEvent.getResponse(), tid, mSipProvider, 5);
+ if (DEBUG) Log.d(TAG, "send request with challenge response: "
+ + ct.getRequest());
ct.sendRequest();
return ct;
}
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index db1931b..ee554b5 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -92,6 +92,7 @@
new HashMap<String, ISipSession>();
private ConnectivityReceiver mConnectivityReceiver;
+ private boolean mScreenOn;
/**
* Starts the SIP service. Do nothing if the SIP API is not supported on the
@@ -111,11 +112,27 @@
mConnectivityReceiver = new ConnectivityReceiver();
context.registerReceiver(mConnectivityReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
+ context.registerReceiver(mScreenOnOffReceiver,
+ new IntentFilter(Intent.ACTION_SCREEN_ON));
+ context.registerReceiver(mScreenOnOffReceiver,
+ new IntentFilter(Intent.ACTION_SCREEN_OFF));
mTimer = new WakeupTimer(context);
mWifiOnly = SipManager.isSipWifiOnly(context);
}
+ BroadcastReceiver mScreenOnOffReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+ mScreenOn = true;
+ } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
+ mScreenOn = false;
+ }
+ }
+ };
+
private MyExecutor getExecutor() {
// create mExecutor lazily
if (mExecutor == null) mExecutor = new MyExecutor();
@@ -366,7 +383,10 @@
boolean wifiOff = (isWifi && !connected) || (wasWifi && !sameType);
boolean wifiOn = isWifi && connected;
if (wifiOff) {
- releaseWifiLock();
+ if (mScreenOn) releaseWifiLock();
+ // If the screen is off, we still keep the wifi lock in order
+ // to be able to reassociate with any available AP. Otherwise,
+ // the wifi driver could be stopped after 15 mins of idle time.
} else if (wifiOn) {
if (anyOpened()) grabWifiLock();
}