auto import from //branches/cupcake_rel/...@138607
diff --git a/api/current.xml b/api/current.xml
index 858b1e9..f45b68f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -11018,6 +11018,56 @@
>
</field>
</class>
+<class name="R.integer"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="R.integer"
+ type="android.R.integer"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="config_longAnimTime"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17694722"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="config_mediumAnimTime"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17694721"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="config_shortAnimTime"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17694720"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="R.layout"
extends="java.lang.Object"
abstract="false"
@@ -28374,6 +28424,17 @@
visibility="public"
>
</field>
+<field name="ACTION_SEARCH_LONG_PRESS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.intent.action.SEARCH_LONG_PRESS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_SEND"
type="java.lang.String"
transient="false"
@@ -66360,6 +66421,21 @@
<parameter name="c" type="android.hardware.Camera">
</parameter>
</method>
+<method name="setMaxDuration"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="max_duration_ms" type="int">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
<method name="setOnErrorListener"
return="void"
abstract="false"
@@ -66373,6 +66449,19 @@
<parameter name="l" type="android.media.MediaRecorder.OnErrorListener">
</parameter>
</method>
+<method name="setOnInfoListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.media.MediaRecorder.OnInfoListener">
+</parameter>
+</method>
<method name="setOutputFile"
return="void"
abstract="false"
@@ -66530,6 +66619,28 @@
visibility="public"
>
</field>
+<field name="MEDIA_RECORDER_INFO_MAX_DURATION_REACHED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="800"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MEDIA_RECORDER_INFO_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="MediaRecorder.AudioEncoder"
extends="java.lang.Object"
@@ -66618,6 +66729,31 @@
</parameter>
</method>
</interface>
+<interface name="MediaRecorder.OnInfoListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onInfo"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mr" type="android.media.MediaRecorder">
+</parameter>
+<parameter name="what" type="int">
+</parameter>
+<parameter name="extra" type="int">
+</parameter>
+</method>
+</interface>
<class name="MediaRecorder.OutputFormat"
extends="java.lang.Object"
abstract="false"
@@ -84442,6 +84578,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_APPLICATION_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""com.android.browser.application_id""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="HISTORY_PROJECTION"
type="java.lang.String[]"
transient="false"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 5ef7499..eabf98e 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -130,7 +130,7 @@
/* the full dumpsys is starting to take a long time, so we need
to increase its timeout. we really need to do the timeouts in
dumpsys itself... */
- EXEC_TIMEOUT("dumpsys", 40);
+ EXEC_TIMEOUT("dumpsys", 60);
}
}
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 33127fb..6862e5a 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -19,8 +19,8 @@
#include <time.h>
-// Commands time out after 15 seconds
-#define TIMEOUT 15
+// Commands time out after 60 seconds
+#define TIMEOUT 60
#define PRINT(s) printf("%s\n", s)
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 15e0a4d..64288d2e 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -126,14 +126,6 @@
// support for AutoCompleteTextView suggestions display
private SuggestionsAdapter mSuggestionsAdapter;
- private Handler mHandler = new Handler();
- private Runnable mInstallSuggestionAdapter = new Runnable() {
- public void run() {
- if (mSearchTextField != null) {
- mSearchTextField.setAdapter(mSuggestionsAdapter);
- }
- }
- };
/**
* Constructor - fires it up and makes it look like the search UI.
@@ -261,8 +253,8 @@
mSearchTextField.setAdapter(mSuggestionsAdapter);
mSearchTextField.setText(initialQuery);
} else {
- mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable,
- mHandler, mInstallSuggestionAdapter);
+ mSuggestionsAdapter = new SuggestionsAdapter(getContext(), mSearchable,
+ mSearchTextField);
mSearchTextField.setAdapter(mSuggestionsAdapter);
// finally, load the user's initial text (which may trigger suggestions)
@@ -1305,15 +1297,13 @@
// These private variables are shared by the filter thread and must be protected
private WeakReference<Cursor> mRecentCursor = new WeakReference<Cursor>(null);
private boolean mNonUserQuery = false;
- private Handler mHandler;
- private Runnable mInstallSuggestionAdapter;
+ private AutoCompleteTextView mParentView;
public SuggestionsAdapter(Context context, SearchableInfo searchable,
- Handler handler, Runnable installSuggestionAdapter) {
+ AutoCompleteTextView actv) {
super(context, -1, null, null, null);
mSearchable = searchable;
- mHandler = handler;
- mInstallSuggestionAdapter = installSuggestionAdapter;
+ mParentView = actv;
// set up provider resources (gives us icons, etc.)
Context activityContext = mSearchable.getActivityContext(mContext);
@@ -1426,13 +1416,12 @@
to = ONE_LINE_TO;
}
}
+ // Force the underlying ListView to discard and reload all layouts
+ // (Note, this should be optimized for cases where layout/cursor remain same)
+ mParentView.resetListAndClearViews();
// Now actually set up the cursor, columns, and the list view
changeCursorAndColumns(c, from, to);
setViewResource(layout);
- // Force the underlying ListView to discard and reload all layouts
- // (Note, this could be optimized for cases where layout/cursor remain same)
- mHandler.post(mInstallSuggestionAdapter);
-
} else {
// Provide some help for developers instead of just silently discarding
Log.w(LOG_TAG, "Suggestions cursor discarded due to missing required columns.");
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index e23545b..1dbe0cc 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -67,6 +67,11 @@
/** A headset is currently connected */
public static final int STATE_CONNECTED = 2;
+ /** A SCO audio channel is not established */
+ public static final int AUDIO_STATE_DISCONNECTED = 0;
+ /** A SCO audio channel is established */
+ public static final int AUDIO_STATE_CONNECTED = 1;
+
public static final int RESULT_FAILURE = 0;
public static final int RESULT_SUCCESS = 1;
/** Connection canceled before completetion. */
diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
index b66b06e..9273d0d 100644
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ b/core/java/android/bluetooth/BluetoothIntent.java
@@ -45,6 +45,8 @@
"android.bluetooth.intent.HEADSET_STATE";
public static final String HEADSET_PREVIOUS_STATE =
"android.bluetooth.intent.HEADSET_PREVIOUS_STATE";
+ public static final String HEADSET_AUDIO_STATE =
+ "android.bluetooth.intent.HEADSET_AUDIO_STATE";
public static final String BOND_STATE =
"android.bluetooth.intent.BOND_STATE";
public static final String BOND_PREVIOUS_STATE =
@@ -122,7 +124,18 @@
public static final String BOND_STATE_CHANGED_ACTION =
"android.bluetooth.intent.action.BOND_STATE_CHANGED_ACTION";
+ /**
+ * TODO(API release): Move into BluetoothHeadset
+ */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String HEADSET_STATE_CHANGED_ACTION =
"android.bluetooth.intent.action.HEADSET_STATE_CHANGED";
+
+ /**
+ * TODO(API release): Consider incorporating as new state in
+ * HEADSET_STATE_CHANGED
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String HEADSET_AUDIO_STATE_CHANGED_ACTION =
+ "android.bluetooth.intent.action.HEADSET_ADUIO_STATE_CHANGED";
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index bb80e10..90ff78a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1026,6 +1026,15 @@
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
+
+ /**
+ * Activity Action: Start action associated with long pressing on the
+ * search key.
+ * <p>Input: Nothing.
+ * <p>Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index f58b7ef..7a63c0c 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -16,34 +16,33 @@
package android.inputmethodservice;
-import com.android.internal.R;
-
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
+import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard.Key;
import android.os.Handler;
import android.os.Message;
-import android.os.Vibrator;
-import android.preference.PreferenceManager;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup.LayoutParams;
-import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.TextView;
+import com.android.internal.R;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -221,6 +220,15 @@
private static final int MULTITAP_INTERVAL = 800; // milliseconds
private StringBuilder mPreviewLabel = new StringBuilder(1);
+ /** Whether the keyboard bitmap needs to be redrawn before it's blitted. **/
+ private boolean mDrawPending;
+ /** The dirty region in the keyboard bitmap */
+ private Rect mDirtyRect = new Rect();
+ /** The keyboard bitmap for faster updates */
+ private Bitmap mBuffer;
+ /** The canvas for the above mutable keyboard bitmap */
+ private Canvas mCanvas;
+
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -396,7 +404,10 @@
List<Key> keys = mKeyboard.getKeys();
mKeys = keys.toArray(new Key[keys.size()]);
requestLayout();
- invalidate();
+ // Release buffer, just in case the new keyboard has a different size.
+ // It will be reallocated on the next draw.
+ mBuffer = null;
+ invalidateAll();
computeProximityThreshold(keyboard);
mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
}
@@ -420,7 +431,7 @@
if (mKeyboard != null) {
if (mKeyboard.setShifted(shifted)) {
// The whole keyboard probably needs to be redrawn
- invalidate();
+ invalidateAll();
return true;
}
}
@@ -545,8 +556,30 @@
}
@Override
+ public void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Release the buffer, if any and it will be reallocated on the next draw
+ mBuffer = null;
+ }
+
+ @Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
+ if (mDrawPending || mBuffer == null) {
+ onBufferDraw();
+ }
+ canvas.drawBitmap(mBuffer, 0, 0, null);
+ }
+
+ private void onBufferDraw() {
+ if (mBuffer == null) {
+ mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+ mCanvas = new Canvas(mBuffer);
+ invalidateAll();
+ }
+ final Canvas canvas = mCanvas;
+ canvas.clipRect(mDirtyRect, Op.REPLACE);
+
if (mKeyboard == null) return;
final Paint paint = mPaint;
@@ -557,24 +590,20 @@
final int kbdPaddingTop = mPaddingTop;
final Key[] keys = mKeys;
final Key invalidKey = mInvalidatedKey;
- //canvas.translate(0, mKeyboardPaddingTop);
+
paint.setAlpha(255);
paint.setColor(mKeyTextColor);
boolean drawSingleKey = false;
if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
-// System.out.println("Key bounds = " + (invalidKey.x + mPaddingLeft) + ","
-// + (invalidKey.y + mPaddingTop) + ","
-// + (invalidKey.x + invalidKey.width + mPaddingLeft) + ","
-// + (invalidKey.y + invalidKey.height + mPaddingTop));
-// System.out.println("Clip bounds =" + clipRegion.toShortString());
- // Is clipRegion completely contained within the invalidated key?
- if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
- invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
- invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
- invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
- drawSingleKey = true;
- }
+ // Is clipRegion completely contained within the invalidated key?
+ if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
+ invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
+ invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
+ invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
+ drawSingleKey = true;
+ }
}
+ canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
final int keyCount = keys.length;
for (int i = 0; i < keyCount; i++) {
final Key key = keys[i];
@@ -645,6 +674,9 @@
paint.setColor(0xFF00FF00);
canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint);
}
+
+ mDrawPending = false;
+ mDirtyRect.setEmpty();
}
private int getKeyIndices(int x, int y, int[] allKeys) {
@@ -844,12 +876,21 @@
mPreviewText.setVisibility(VISIBLE);
}
+ private void invalidateAll() {
+ mDirtyRect.union(0, 0, getWidth(), getHeight());
+ mDrawPending = true;
+ invalidate();
+ }
+
private void invalidateKey(int keyIndex) {
if (keyIndex < 0 || keyIndex >= mKeys.length) {
return;
}
final Key key = mKeys[keyIndex];
mInvalidatedKey = key;
+ mDirtyRect.union(key.x + mPaddingLeft, key.y + mPaddingTop,
+ key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
+ onBufferDraw();
invalidate(key.x + mPaddingLeft, key.y + mPaddingTop,
key.x + key.width + mPaddingLeft, key.y + key.height + mPaddingTop);
}
@@ -952,7 +993,7 @@
mPopupKeyboard.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
mMiniKeyboardOnScreen = true;
//mMiniKeyboard.onTouchEvent(getTranslatedEvent(me));
- invalidate();
+ invalidateAll();
return true;
}
return false;
@@ -1066,11 +1107,11 @@
}
showPreview(NOT_A_KEY);
Arrays.fill(mKeyIndices, NOT_A_KEY);
- invalidateKey(keyIndex);
// If we're not on a repeating key (which sends on a DOWN event)
if (mRepeatKeyIndex == NOT_A_KEY && !mMiniKeyboardOnScreen && !mAbortKey) {
detectAndSendKey(touchX, touchY, eventTime);
}
+ invalidateKey(keyIndex);
mRepeatKeyIndex = NOT_A_KEY;
break;
}
@@ -1110,7 +1151,8 @@
mHandler.removeMessages(MSG_SHOW_PREVIEW);
dismissPopupKeyboard();
-
+ mBuffer = null;
+ mCanvas = null;
mMiniKeyboardCache.clear();
}
@@ -1124,10 +1166,10 @@
if (mPopupKeyboard.isShowing()) {
mPopupKeyboard.dismiss();
mMiniKeyboardOnScreen = false;
- invalidate();
+ invalidateAll();
}
}
-
+
public boolean handleBack() {
if (mPopupKeyboard.isShowing()) {
dismissPopupKeyboard();
diff --git a/core/java/android/os/IMountService.aidl b/core/java/android/os/IMountService.aidl
index 88dae85..96d44b6 100644
--- a/core/java/android/os/IMountService.aidl
+++ b/core/java/android/os/IMountService.aidl
@@ -50,7 +50,7 @@
void unmountMedia(String mountPoint);
/**
- * Format external storage given a mount point
+ * Format external storage given a mount point.
*/
void formatMedia(String mountPoint);
@@ -63,4 +63,16 @@
* Sets whether or not media notification sounds are played.
*/
void setPlayNotificationSounds(boolean value);
+
+ /**
+ * Returns true if USB Mass Storage is automatically started
+ * when a UMS host is detected.
+ */
+ boolean getAutoStartUms();
+
+ /**
+ * Sets whether or not USB Mass Storage is automatically started
+ * when a UMS host is detected.
+ */
+ void setAutoStartUms(boolean value);
}
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 6e215dc..20702a1 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -194,13 +194,6 @@
}
private void sample() {
-
- // Only play a preview sample when controlling the ringer stream
- if (mStreamType != AudioManager.STREAM_RING
- && mStreamType != AudioManager.STREAM_NOTIFICATION) {
- return;
- }
-
onSampleStarting(this);
mRingtone.play();
}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 76aa51d..c597b3c 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -43,6 +43,18 @@
*/
public static final String INITIAL_ZOOM_LEVEL = "browser.initialZoomLevel";
+ /**
+ * The name of the extra data when starting the Browser from another
+ * application.
+ * <p>
+ * The value is a unique identification string that will be used to
+ * indentify the calling application. The Browser will attempt to reuse the
+ * same window each time the application launches the Browser with the same
+ * identifier.
+ */
+ public static final String EXTRA_APPLICATION_ID =
+ "com.android.browser.application_id";
+
/* if you change column order you must also change indices
below */
public static final String[] HISTORY_PROJECTION = new String[] {
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index d0bd2a5..2aa77ea 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -182,7 +182,7 @@
* <p>Type: TEXT</P>
*/
public static final String PHONETIC_NAME = "phonetic_name";
-
+
/**
* The display name. If name is not null name, else if number is not null number,
* else if email is not null email.
@@ -191,6 +191,14 @@
public static final String DISPLAY_NAME = "display_name";
/**
+ * The field for sorting list phonetically. The content of this field
+ * may not be human readable but phonetically sortable.
+ * <P>Type: TEXT</p>
+ * @hide Used only in Contacts application for now.
+ */
+ public static final String SORT_STRING = "sort_string";
+
+ /**
* Notes about the person.
* <P>Type: TEXT</P>
*/
@@ -231,7 +239,7 @@
* The server version of the photo
* <P>Type: TEXT (the version number portion of the photo URI)</P>
*/
- public static final String PHOTO_VERSION = "photo_version";
+ public static final String PHOTO_VERSION = "photo_version";
}
/**
diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java
index e271909..9e9ba62 100644
--- a/core/java/android/server/BluetoothDeviceService.java
+++ b/core/java/android/server/BluetoothDeviceService.java
@@ -81,10 +81,13 @@
*/
public synchronized void init() {
initializeNativeDataNative();
- mIsEnabled = (isEnabledNative() == 1);
- if (mIsEnabled) {
- mBondState.loadBondState();
+
+ if (isEnabledNative() == 1) {
+ Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
+ disableNative();
}
+
+ mIsEnabled = false;
mIsDiscovering = false;
mEventLoop = new BluetoothEventLoop(mContext, this);
registerForAirplaneMode();
diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java
index efb88a0e..29c0c76 100644
--- a/core/java/android/text/style/ImageSpan.java
+++ b/core/java/android/text/style/ImageSpan.java
@@ -88,6 +88,7 @@
super(verticalAlignment);
mContext = context;
mContentUri = uri;
+ mSource = uri.toString();
}
public ImageSpan(Context context, int resourceId) {
@@ -117,6 +118,8 @@
mContentUri);
bitmap = BitmapFactory.decodeStream(is);
drawable = new BitmapDrawable(bitmap);
+ drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight());
is.close();
} catch (Exception e) {
Log.e("sms", "Failed to loaded content " + mContentUri, e);
diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java
index f458611..d29bfb6 100644
--- a/core/java/android/text/style/URLSpan.java
+++ b/core/java/android/text/style/URLSpan.java
@@ -16,9 +16,11 @@
package android.text.style;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Parcel;
+import android.provider.Browser;
import android.text.ParcelableSpan;
import android.text.TextUtils;
import android.view.View;
@@ -54,8 +56,9 @@
@Override
public void onClick(View widget) {
Uri uri = Uri.parse(getURL());
+ Context context = widget.getContext();
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.addCategory(Intent.CATEGORY_BROWSABLE);
- widget.getContext().startActivity(intent);
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+ context.startActivity(intent);
}
}
diff --git a/core/java/android/text/util/Regex.java b/core/java/android/text/util/Regex.java
index 4c128ad..a349b82 100644
--- a/core/java/android/text/util/Regex.java
+++ b/core/java/android/text/util/Regex.java
@@ -66,9 +66,9 @@
public static final Pattern WEB_URL_PATTERN
= Pattern.compile(
"((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
- + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
- + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2}))+)?\\@)?)?"
- + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+" // named host
+ + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+ + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+" // named host
+ "(?:" // plus top level domain
+ "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ "|(?:biz|b[abdefghijmnorstvwyz])"
@@ -122,12 +122,12 @@
public static final Pattern EMAIL_ADDRESS_PATTERN
= Pattern.compile(
- "[a-zA-Z0-9\\+\\.\\_\\%\\-]+" +
+ "[a-zA-Z0-9\\+\\.\\_\\%\\-]{1,256}" +
"\\@" +
- "[a-zA-Z0-9][a-zA-Z0-9\\-]*" +
+ "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}" +
"(" +
"\\." +
- "[a-zA-Z0-9][a-zA-Z0-9\\-]*" +
+ "[a-zA-Z0-9][a-zA-Z0-9\\-]{0,25}" +
")+"
);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 0a043bd..6ea7a82 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -663,7 +663,7 @@
public Object[] pre() {
final DisplayMetrics metrics = view.getResources().getDisplayMetrics();
final Bitmap bitmap = Bitmap.createBitmap(metrics.widthPixels,
- metrics.heightPixels, Bitmap.Config.ARGB_8888);
+ metrics.heightPixels, Bitmap.Config.RGB_565);
final Canvas canvas = new Canvas(bitmap);
return new Object[] { bitmap, canvas };
}
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 9b13d38..dd2b154 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -219,7 +219,7 @@
mVisRect = new Rect();
mVisPoint = new Point();
mWinFrame = new Rect();
- mWindow = new W(this);
+ mWindow = new W(this, context);
mInputMethodCallback = new InputMethodCallback(this);
mViewVisibility = View.GONE;
mTransparentRegion = new Region();
@@ -2453,11 +2453,71 @@
}
}
+ static class EventCompletion extends Handler {
+ final IWindow mWindow;
+ final KeyEvent mKeyEvent;
+ final boolean mIsPointer;
+ final MotionEvent mMotionEvent;
+
+ EventCompletion(Looper looper, IWindow window, KeyEvent key,
+ boolean isPointer, MotionEvent motion) {
+ super(looper);
+ mWindow = window;
+ mKeyEvent = key;
+ mIsPointer = isPointer;
+ mMotionEvent = motion;
+ sendEmptyMessage(0);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mKeyEvent != null) {
+ try {
+ sWindowSession.finishKey(mWindow);
+ } catch (RemoteException e) {
+ }
+ } else if (mIsPointer) {
+ boolean didFinish;
+ MotionEvent event = mMotionEvent;
+ if (event == null) {
+ try {
+ event = sWindowSession.getPendingPointerMove(mWindow);
+ } catch (RemoteException e) {
+ }
+ didFinish = true;
+ } else {
+ didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
+ }
+ if (!didFinish) {
+ try {
+ sWindowSession.finishKey(mWindow);
+ } catch (RemoteException e) {
+ }
+ }
+ } else {
+ MotionEvent event = mMotionEvent;
+ if (event == null) {
+ try {
+ event = sWindowSession.getPendingTrackballMove(mWindow);
+ } catch (RemoteException e) {
+ }
+ } else {
+ try {
+ sWindowSession.finishKey(mWindow);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ }
+
static class W extends IWindow.Stub {
- private WeakReference<ViewRoot> mViewRoot;
+ private final WeakReference<ViewRoot> mViewRoot;
+ private final Looper mMainLooper;
- public W(ViewRoot viewRoot) {
+ public W(ViewRoot viewRoot, Context context) {
mViewRoot = new WeakReference<ViewRoot>(viewRoot);
+ mMainLooper = context.getMainLooper();
}
public void resized(int w, int h, Rect coveredInsets,
@@ -2475,6 +2535,7 @@
viewRoot.dispatchKey(event);
} else {
Log.w("ViewRoot.W", "Key event " + event + " but no ViewRoot available!");
+ new EventCompletion(mMainLooper, this, event, false, null);
}
}
@@ -2482,6 +2543,8 @@
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
viewRoot.dispatchPointer(event, eventTime);
+ } else {
+ new EventCompletion(mMainLooper, this, null, true, event);
}
}
@@ -2489,6 +2552,8 @@
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
viewRoot.dispatchTrackball(event, eventTime);
+ } else {
+ new EventCompletion(mMainLooper, this, null, false, event);
}
}
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 5877932..f1f5f70 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -34,24 +34,12 @@
private static final String TAG = "WindowOrientationListener";
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
- private int mOrientation = ORIENTATION_UNKNOWN;
private SensorManager mSensorManager;
private boolean mEnabled = false;
private int mRate;
private Sensor mSensor;
private SensorEventListener mSensorEventListener;
-
- /**
- * Returned from onOrientationChanged when the device orientation cannot be determined
- * (typically when the device is in a close to flat position).
- *
- * @see #onOrientationChanged
- */
- public static final int ORIENTATION_UNKNOWN = -1;
- /*
- * Returned when the device is almost lying flat on a surface
- */
- public static final int ORIENTATION_FLAT = -2;
+ private int mSensorRotation = -1;
/**
* Creates a new WindowOrientationListener.
@@ -116,24 +104,47 @@
private static final int _DATA_X = 0;
private static final int _DATA_Y = 1;
private static final int _DATA_Z = 2;
+ // Angle around x-axis thats considered almost perfect vertical to hold
+ // the device
+ private static final int PIVOT = 30;
+ // Angle around x-asis that's considered almost too vertical. Beyond
+ // this angle will not result in any orientation changes. f phone faces uses,
+ // the device is leaning backward.
+ private static final int PIVOT_UPPER = 65;
+ // Angle about x-axis that's considered negative vertical. Beyond this
+ // angle will not result in any orientation changes. If phone faces uses,
+ // the device is leaning forward.
+ private static final int PIVOT_LOWER = 0;
+ // Upper threshold limit for switching from portrait to landscape
+ private static final int PL_UPPER = 280;
+ // Lower threshold limit for switching from landscape to portrait
+ private static final int LP_LOWER = 320;
+ // Lower threshold limt for switching from portrait to landscape
+ private static final int PL_LOWER = 240;
+ // Upper threshold limit for switching from landscape to portrait
+ private static final int LP_UPPER = 360;
+
+ // Internal value used for calculating linear variant
+ private static final float PL_LINEAR_FACTOR =
+ ((float)(PL_UPPER-PL_LOWER))/((float)(PIVOT_UPPER-PIVOT_LOWER));
+ // Internal value used for calculating linear variant
+ private static final float LP_LINEAR_FACTOR =
+ ((float)(LP_UPPER - LP_LOWER))/((float)(PIVOT_UPPER-PIVOT_LOWER));
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
- int orientation = ORIENTATION_UNKNOWN;
float X = values[_DATA_X];
float Y = values[_DATA_Y];
float Z = values[_DATA_Z];
float OneEightyOverPi = 57.29577957855f;
float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z);
float zyangle = Math.abs((float)Math.asin(Z/gravity)*OneEightyOverPi);
- // The device is considered flat if the angle is more than 75
- // if the angle is less than 40, its considered too flat to switch
- // orientation. if the angle is between 40 - 75, the orientation is unknown
- if (zyangle < 40) {
+ int rotation = mSensorRotation;
+ if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {
// Check orientation only if the phone is flat enough
// Don't trust the angle if the magnitude is small compared to the y value
float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi;
- orientation = 90 - (int)Math.round(angle);
+ int orientation = 90 - (int)Math.round(angle);
// normalize to 0 - 359 range
while (orientation >= 360) {
orientation -= 360;
@@ -141,13 +152,24 @@
while (orientation < 0) {
orientation += 360;
}
- } else if (zyangle >= 75){
- orientation = ORIENTATION_FLAT;
+
+ float delta = (float)Math.abs(zyangle - PIVOT);
+ if (((orientation >= 0) && (orientation <= LP_UPPER)) ||
+ (orientation >= PL_LOWER)) {
+ float threshold;
+ if (mSensorRotation == Surface.ROTATION_90) {
+ threshold = LP_LOWER + (LP_LINEAR_FACTOR * delta) ;
+ } else {
+ threshold = PL_UPPER - (PL_LINEAR_FACTOR * delta);
+ }
+ rotation = (orientation >= PL_LOWER &&
+ orientation <= threshold) ? Surface.ROTATION_90 : Surface.ROTATION_0;
+ }
+
}
-
- if (orientation != mOrientation) {
- mOrientation = orientation;
- onOrientationChanged(orientation);
+ if (rotation != mSensorRotation) {
+ mSensorRotation = rotation;
+ onOrientationChanged(mSensorRotation);
}
}
@@ -164,17 +186,11 @@
}
/**
- * Called when the orientation of the device has changed.
- * orientation parameter is in degrees, ranging from 0 to 359.
- * orientation is 0 degrees when the device is oriented in its natural position,
- * 90 degrees when its left side is at the top, 180 degrees when it is upside down,
- * and 270 degrees when its right side is to the top.
- * {@link #ORIENTATION_UNKNOWN} is returned when the device is close to flat
- * and the orientation cannot be determined.
- *
- * @param orientation The new orientation of the device.
+ * Called when the rotation view of the device has changed.
+ * Can be either Surface.ROTATION_90 or Surface.ROTATION_0.
+ * @param rotation The new orientation of the device.
*
* @see #ORIENTATION_UNKNOWN
*/
- abstract public void onOrientationChanged(int orientation);
+ abstract public void onOrientationChanged(int rotation);
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index d12940d..dcf68cd 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -52,6 +52,7 @@
private static final String NO_STORE = "no-store";
private static final String NO_CACHE = "no-cache";
+ private static final String PRIVATE = "private";
private static final String MAX_AGE = "max-age";
private static long CACHE_THRESHOLD = 6 * 1024 * 1024;
@@ -612,7 +613,7 @@
// must be re-validated on every load. It does not mean that
// the content can not be cached. set to expire 0 means it
// can only be used in CACHE_MODE_CACHE_ONLY case
- if (NO_CACHE.equals(controls[i])) {
+ if (NO_CACHE.equals(controls[i]) || PRIVATE.equals(controls[i])) {
ret.expires = 0;
} else if (controls[i].startsWith(MAX_AGE)) {
int separator = controls[i].indexOf('=');
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 84aeb83..0f9f29c 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -29,6 +29,7 @@
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
+import android.provider.Browser;
import android.util.Config;
import android.util.Log;
import android.view.KeyEvent;
@@ -175,6 +176,11 @@
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(overrideUrl));
intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ // If another application is running a WebView and launches the
+ // Browser through this Intent, we want to reuse the same window if
+ // possible.
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID,
+ mContext.getPackageName());
try {
mContext.startActivity(intent);
override = true;
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 07c1a5d..d90a2fd 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -743,11 +743,16 @@
* Note: in the case of "foo=bluh, bar=bluh;path=/", we interpret
* it as one cookie instead of two cookies.
*/
+ int semicolonIndex = cookieString.indexOf(SEMICOLON, index);
int equalIndex = cookieString.indexOf(EQUAL, index);
if (equalIndex == -1) {
// bad format, force return
break;
}
+ if (semicolonIndex > -1 && semicolonIndex < equalIndex) {
+ // empty cookie, like "; path=/", return
+ break;
+ }
cookie = new Cookie(host, path);
cookie.name = cookieString.substring(index, equalIndex);
if (cookieString.charAt(equalIndex + 1) == QUOTATION) {
@@ -757,7 +762,7 @@
break;
}
}
- int semicolonIndex = cookieString.indexOf(SEMICOLON, index);
+ semicolonIndex = cookieString.indexOf(SEMICOLON, index);
if (semicolonIndex == -1) {
semicolonIndex = length;
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f61ce40..753267f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -180,9 +180,6 @@
*/
VelocityTracker mVelocityTracker;
- private static boolean mShowZoomTutorial = true;
- private static final int ZOOM_TUTORIAL_DURATION = 3000;
-
/**
* Touch mode
*/
@@ -223,16 +220,12 @@
*/
// pre-computed square of ViewConfiguration.getScaledTouchSlop()
private int mTouchSlopSquare;
- // pre-computed square of the density adjusted double tap slop
- private int mDoubleTapSlopSquare;
// pre-computed density adjusted navigation slop
private int mNavSlop;
// This should be ViewConfiguration.getTapTimeout()
// But system time out is 100ms, which is too short for the browser.
// In the browser, if it switches out of tap too soon, jump tap won't work.
private static final int TAP_TIMEOUT = 200;
- // The duration in milliseconds we will wait to see if it is a double tap.
- private static final int DOUBLE_TAP_TIMEOUT = 250;
// This should be ViewConfiguration.getLongPressTimeout()
// But system time out is 500ms, which is too short for the browser.
// With a short timeout, it's difficult to treat trigger a short press.
@@ -258,11 +251,6 @@
private int mContentWidth; // cache of value from WebViewCore
private int mContentHeight; // cache of value from WebViewCore
- static int MAX_FLOAT_CONTENT_WIDTH = 480;
- // the calculated minimum content width for calculating the minimum scale.
- // If it is 0, it means don't use it.
- private int mMinContentWidth;
-
// Need to have the separate control for horizontal and vertical scrollbar
// style than the View's single scrollbar style
private boolean mOverlayHorizontalScrollbar = true;
@@ -288,11 +276,9 @@
private static final int NEVER_REMEMBER_PASSWORD = 2;
private static final int SWITCH_TO_SHORTPRESS = 3;
private static final int SWITCH_TO_LONGPRESS = 4;
- private static final int RELEASE_SINGLE_TAP = 5;
private static final int UPDATE_TEXT_ENTRY_ADAPTER = 6;
private static final int SWITCH_TO_ENTER = 7;
private static final int RESUME_WEBCORE_UPDATE = 8;
- private static final int DISMISS_ZOOM_TUTORIAL = 9;
//! arg1=x, arg2=y
static final int SCROLL_TO_MSG_ID = 10;
@@ -321,7 +307,7 @@
"NEVER_REMEMBER_PASSWORD", // = 2;
"SWITCH_TO_SHORTPRESS", // = 3;
"SWITCH_TO_LONGPRESS", // = 4;
- "RELEASE_SINGLE_TAP", // = 5;
+ "5",
"UPDATE_TEXT_ENTRY_ADAPTER", // = 6;
"SWITCH_TO_ENTER", // = 7;
"RESUME_WEBCORE_UPDATE", // = 8;
@@ -346,13 +332,14 @@
};
// width which view is considered to be fully zoomed out
- static final int ZOOM_OUT_WIDTH = 1024;
+ static final int ZOOM_OUT_WIDTH = 1008;
- private static final float DEFAULT_MAX_ZOOM_SCALE = 2;
- private static final float DEFAULT_MIN_ZOOM_SCALE = (float) 1/3;
+ private static final float DEFAULT_MAX_ZOOM_SCALE = 4.0f;
+ private static final float DEFAULT_MIN_ZOOM_SCALE = 0.25f;
// scale limit, which can be set through viewport meta tag in the web page
private float mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
private float mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ private boolean mMinZoomScaleFixed = false;
// initial scale in percent. 0 means using default.
private int mInitialScale = 0;
@@ -562,8 +549,8 @@
private void initZoomController(Context context) {
// Create the buttons controller
- mZoomButtonsController = new ZoomButtonsController(context, this);
- mZoomButtonsController.setCallback(mZoomListener);
+ mZoomButtonsController = new ZoomButtonsController(this);
+ mZoomButtonsController.setOnZoomListener(mZoomListener);
// Create the accessory buttons
LayoutInflater inflater =
@@ -611,12 +598,6 @@
final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
mTouchSlopSquare = slop * slop;
mMinLockSnapReverseDistance = slop;
- // use twice the line height, 32 based on our current default font, for
- // the double tap slop as the ViewConfiguration's double tap slop, 100,
- // is too big for the Browser
- final int doubleTapslop = (int) (32 * getContext().getResources()
- .getDisplayMetrics().density);
- mDoubleTapSlopSquare = doubleTapslop * doubleTapslop;
// use one line height, 16 based on our current default font, for how
// far we allow a touch be away from the edge of a link
mNavSlop = (int) (16 * getContext().getResources()
@@ -1646,8 +1627,7 @@
* @return true if new values were sent
*/
private boolean sendViewSizeZoom() {
- int viewWidth = getViewWidth();
- int newWidth = Math.round(viewWidth * mInvActualScale);
+ int newWidth = Math.round(getViewWidth() * mInvActualScale);
int newHeight = Math.round(getViewHeight() * mInvActualScale);
/*
* Because the native side may have already done a layout before the
@@ -1663,7 +1643,7 @@
// Avoid sending another message if the dimensions have not changed.
if (newWidth != mLastWidthSent || newHeight != mLastHeightSent) {
mWebViewCore.sendMessage(EventHub.VIEW_SIZE_CHANGED,
- newWidth, newHeight, new Integer(viewWidth));
+ newWidth, newHeight, new Float(mActualScale));
mLastWidthSent = newWidth;
mLastHeightSent = newHeight;
return true;
@@ -3341,19 +3321,10 @@
mZoomCenterX = getViewWidth() * .5f;
mZoomCenterY = getViewHeight() * .5f;
- // update mMinZoomScale
- if (mMinContentWidth > MAX_FLOAT_CONTENT_WIDTH) {
- boolean atMin = Math.abs(mActualScale - mMinZoomScale) < 0.01f;
- mMinZoomScale = (float) getViewWidth() / mContentWidth;
- if (atMin) {
- // if the WebView was at the minimum zoom scale, keep it. e,g.,
- // the WebView was at the minimum zoom scale at the portrait
- // mode, rotate it to the landscape modifying the scale to the
- // new minimum zoom scale, when rotating back, we would like to
- // keep the minimum zoom scale instead of keeping the same scale
- // as normally we do.
- mActualScale = mMinZoomScale;
- }
+ // update mMinZoomScale if the minimum zoom scale is not fixed
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = (float) getViewWidth()
+ / Math.max(ZOOM_OUT_WIDTH, mContentWidth);
}
// we always force, in case our height changed, in which case we still
@@ -3411,15 +3382,6 @@
return false;
}
- if (mShowZoomTutorial && getSettings().supportZoom()
- && (mMaxZoomScale != mMinZoomScale)) {
- ZoomButtonsController.showZoomTutorialOnce(mContext);
- mShowZoomTutorial = false;
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(DISMISS_ZOOM_TUTORIAL),
- ZOOM_TUTORIAL_DURATION);
- }
-
if (LOGV_ENABLED) {
Log.v(LOGTAG, ev + " at " + ev.getEventTime() + " mTouchMode="
+ mTouchMode);
@@ -3482,29 +3444,6 @@
nativeMoveSelection(viewToContent(mSelectX)
, viewToContent(mSelectY), false);
mTouchSelection = mExtendSelection = true;
- } else if (!ZoomButtonsController.useOldZoom(mContext)
- && mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
- mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
- if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
- // Found doubletap, invoke the zoom controller
- int contentX = viewToContent((int) mLastTouchX
- + mScrollX);
- int contentY = viewToContent((int) mLastTouchY
- + mScrollY);
- if (inEditingMode()) {
- mTextEntry.updateCachedTextfield();
- }
- nativeClearFocus(contentX, contentY);
- if (mLogEvent) {
- EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
- (eventTime - mLastTouchUpTime), eventTime);
- }
- return mZoomButtonsController.handleDoubleTapEvent(ev);
- } else {
- // commit the short press action
- doShortPress();
- // continue, mTouchMode should be still TOUCH_INIT_MODE
- }
} else {
mTouchMode = TOUCH_INIT_MODE;
mPreventDrag = mForwardTouchEvents;
@@ -3588,6 +3527,12 @@
mWebViewCore
.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0);
}
+ if (getSettings().supportZoom()
+ && !mZoomButtonsController.isVisible()
+ && (canZoomScrollOut() ||
+ mMinZoomScale < mMaxZoomScale)) {
+ mZoomButtonsController.setVisible(true);
+ }
}
// do pan
@@ -3660,16 +3605,12 @@
mLastTouchUpTime = eventTime;
switch (mTouchMode) {
case TOUCH_INIT_MODE: // tap
+ case TOUCH_SHORTPRESS_START_MODE:
+ case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
- if (getSettings().supportZoom()) {
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP),
- DOUBLE_TAP_TIMEOUT);
- } else {
- // do short press now
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- }
+ mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
+ mTouchMode = TOUCH_DONE_MODE;
+ doShortPress();
break;
case TOUCH_SELECT_MODE:
commitCopy();
@@ -3697,28 +3638,6 @@
invalidate();
}
break;
- case TOUCH_SHORTPRESS_START_MODE:
- case TOUCH_SHORTPRESS_MODE: {
- mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- if (eventTime - mLastTouchTime < TAP_TIMEOUT
- && getSettings().supportZoom()) {
- // Note: window manager will not release ACTION_UP
- // until all the previous action events are
- // returned. If GC happens, it can cause
- // SWITCH_TO_SHORTPRESS message fired before
- // ACTION_UP sent even time stamp of ACTION_UP is
- // less than the tap time out. We need to treat this
- // as tap instead of short press.
- mTouchMode = TOUCH_INIT_MODE;
- mPrivateHandler.sendMessageDelayed(mPrivateHandler
- .obtainMessage(RELEASE_SINGLE_TAP),
- DOUBLE_TAP_TIMEOUT);
- } else {
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- }
- break;
- }
case TOUCH_DRAG_MODE:
// if the user waits a while w/o moving before the
// up, we don't want to do a fling
@@ -3759,7 +3678,6 @@
}
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
- mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
mTouchMode = TOUCH_DONE_MODE;
int contentX = viewToContent((int) mLastTouchX + mScrollX);
int contentY = viewToContent((int) mLastTouchY + mScrollY);
@@ -4132,31 +4050,7 @@
}
}
- /**
- * An InvisibleView is an invisible, zero-sized View for backwards
- * compatibility
- */
- private final class InvisibleView extends View {
-
- private InvisibleView(Context context) {
- super(context);
- setVisibility(GONE);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(0, 0);
- }
-
- @Override
- public void draw(Canvas canvas) {
- }
-
- @Override
- protected void dispatchDraw(Canvas canvas) {
- }
- }
-
+ // TODO: deprecate
/**
* Returns a view containing zoom controls i.e. +/- buttons. The caller is
* in charge of installing this view to the view hierarchy. This view will
@@ -4167,7 +4061,19 @@
* an invisible dummy view for backwards compatibility.
*/
public View getZoomControls() {
- return new InvisibleView(mContext);
+ return mZoomButtonsController.getDummyZoomControls();
+ }
+
+ /**
+ * Gets the {@link ZoomButtonsController} which can be used to add
+ * additional buttons to the zoom controls window.
+ *
+ * @return The instance of {@link ZoomButtonsController} used by this class,
+ * or null if it is unavailable.
+ * @hide pending API council
+ */
+ public ZoomButtonsController getZoomButtonsController() {
+ return mZoomButtonsController;
}
/**
@@ -4447,11 +4353,6 @@
updateTextEntry();
break;
}
- case RELEASE_SINGLE_TAP: {
- mTouchMode = TOUCH_DONE_MODE;
- doShortPress();
- break;
- }
case SWITCH_TO_ENTER:
if (LOGV_ENABLED) Log.v(LOGTAG, "SWITCH_TO_ENTER");
mTouchMode = TOUCH_DONE_MODE;
@@ -4498,10 +4399,9 @@
0, 0);
}
}
- mMinContentWidth = msg.arg1;
- if (mMinContentWidth > MAX_FLOAT_CONTENT_WIDTH) {
+ if (!mMinZoomScaleFixed) {
mMinZoomScale = (float) getViewWidth()
- / draw.mWidthHeight.x;
+ / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x);
}
// We update the layout (i.e. request a layout from the
// view system) if the last view size that we sent to
@@ -4561,8 +4461,10 @@
int minScale = (Integer) scaleLimit.get("minScale");
if (minScale == 0) {
mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
+ mMinZoomScaleFixed = false;
} else {
mMinZoomScale = (float) (minScale / 100.0);
+ mMinZoomScaleFixed = true;
}
int maxScale = (Integer) scaleLimit.get("maxScale");
if (maxScale == 0) {
@@ -4690,10 +4592,6 @@
}
break;
- case DISMISS_ZOOM_TUTORIAL:
- mZoomButtonsController.finishZoomTutorial();
- break;
-
default:
super.handleMessage(msg);
break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index e10ffa1..3e4daf7 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -725,7 +725,7 @@
case VIEW_SIZE_CHANGED:
viewSizeChanged(msg.arg1, msg.arg2,
- ((Integer) msg.obj).intValue());
+ ((Float) msg.obj).floatValue());
break;
case SET_SCROLL_OFFSET:
@@ -1181,23 +1181,16 @@
private int mCurrentViewWidth = 0;
private int mCurrentViewHeight = 0;
- // Define a minimum screen width so that we won't wrap the paragraph to one
- // word per line during zoom-in.
- private static final int MIN_SCREEN_WIDTH = 160;
-
// notify webkit that our virtual view size changed size (after inv-zoom)
- private void viewSizeChanged(int w, int h, int viewWidth) {
+ private void viewSizeChanged(int w, int h, float scale) {
if (LOGV_ENABLED) Log.v(LOGTAG, "CORE onSizeChanged");
if (w == 0) {
Log.w(LOGTAG, "skip viewSizeChanged as w is 0");
return;
}
- // negative scale indicate that WebCore should reuse the current scale
- float scale = (float) viewWidth / w;
if (mSettings.getUseWideViewPort()
&& (w < mViewportWidth || mViewportWidth == -1)) {
int width = mViewportWidth;
- int screenWidth = Math.max(w, MIN_SCREEN_WIDTH);
if (mViewportWidth == -1) {
if (mSettings.getLayoutAlgorithm() ==
WebSettings.LayoutAlgorithm.NORMAL) {
@@ -1215,19 +1208,11 @@
* In the worse case, the native width will be adjusted when
* next zoom or screen orientation change happens.
*/
- int minContentWidth = nativeGetContentMinPrefWidth();
- if (minContentWidth > WebView.MAX_FLOAT_CONTENT_WIDTH) {
- // keep the same width and screen width so that there is
- // no reflow when zoom-out
- width = minContentWidth;
- screenWidth = Math.min(screenWidth, Math.abs(viewWidth));
- } else {
- width = Math.max(w, minContentWidth);
- }
+ width = Math.max(w, nativeGetContentMinPrefWidth());
}
}
- nativeSetSize(width, Math.round((float) width * h / w),
- screenWidth, scale, w, h);
+ nativeSetSize(width, Math.round((float) width * h / w), w, scale,
+ w, h);
} else {
nativeSetSize(w, h, w, scale, w, h);
}
@@ -1289,10 +1274,7 @@
draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
Message.obtain(mWebView.mPrivateHandler,
- WebView.NEW_PICTURE_MSG_ID,
- mViewportMinimumScale == 0 ? nativeGetContentMinPrefWidth()
- : 0,
- 0, draw).sendToTarget();
+ WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
if (mWebkitScrollX != 0 || mWebkitScrollY != 0) {
// as we have the new picture, try to sync the scroll position
Message.obtain(mWebView.mPrivateHandler,
@@ -1533,11 +1515,11 @@
// white space in the GMail which uses WebView for message view.
if (mWebView != null && mWebView.mHeightCanMeasure) {
mWebView.mLastHeightSent = 0;
- // Send a negative screen width to indicate that WebCore should
- // reuse the current scale
+ // Send a negative scale to indicate that WebCore should reuse the
+ // current scale
mEventHub.sendMessage(Message.obtain(null,
EventHub.VIEW_SIZE_CHANGED, mWebView.mLastWidthSent,
- mWebView.mLastHeightSent, -mWebView.mLastWidthSent));
+ mWebView.mLastHeightSent, -1.0f));
}
mBrowserFrame.didFirstLayout();
diff --git a/core/java/android/webkit/gears/DesktopAndroid.java b/core/java/android/webkit/gears/DesktopAndroid.java
index ee8ca49..a7a144b 100644
--- a/core/java/android/webkit/gears/DesktopAndroid.java
+++ b/core/java/android/webkit/gears/DesktopAndroid.java
@@ -31,6 +31,7 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.provider.Browser;
import android.util.Log;
import android.webkit.WebView;
@@ -78,7 +79,10 @@
Intent viewWebPage = new Intent(Intent.ACTION_VIEW);
viewWebPage.setData(Uri.parse(url));
- viewWebPage.addCategory(Intent.CATEGORY_BROWSABLE);
+ long urlHash = url.hashCode();
+ long uniqueId = (urlHash << 32) | viewWebPage.hashCode();
+ viewWebPage.putExtra(Browser.EXTRA_APPLICATION_ID,
+ Long.toString(uniqueId));
Intent intent = new Intent(ACTION_INSTALL_SHORTCUT);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, viewWebPage);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 7fc96fc..bd4bba8f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -982,6 +982,18 @@
mSelectorRect.setEmpty();
invalidate();
}
+
+ /**
+ * The list is empty and we need to change the layout, so *really* clear everything out.
+ * @hide - for AutoCompleteTextView & SearchDialog only
+ */
+ /* package */ void resetListAndClearViews() {
+ rememberSyncState();
+ removeAllViewsInLayout();
+ mRecycler.clear();
+ mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
+ requestLayout();
+ }
@Override
protected int computeVerticalScrollExtent() {
@@ -1422,7 +1434,10 @@
final View v = getChildAt(mSelectedPosition - mFirstPosition);
- if (v != null) v.setPressed(true);
+ if (v != null) {
+ if (v.hasFocusable()) return;
+ v.setPressed(true);
+ }
setPressed(true);
final boolean longClickable = isLongClickable();
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 7b9670b..e613541 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -630,6 +630,16 @@
}
/**
+ * We're changing the adapter and its views so really, really clear everything out
+ * @hide - for SearchDialog only
+ */
+ public void resetListAndClearViews() {
+ if (mDropDownList != null) {
+ mDropDownList.resetListAndClearViews();
+ }
+ }
+
+ /**
* <p>Starts filtering the content of the drop down list. The filtering
* pattern is the content of the edit box. Subclasses should override this
* method to filter with a different pattern, for instance a substring of
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index f646ab5..441414a 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -763,7 +763,7 @@
@Override
public void invalidateDrawable(Drawable dr) {
if (!mInDrawing) {
- if (dr == mProgressDrawable || dr == mIndeterminateDrawable) {
+ if (verifyDrawable(dr)) {
final Rect dirty = dr.getBounds();
final int scrollX = mScrollX + mPaddingLeft;
final int scrollY = mScrollY + mPaddingTop;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 426d711..7b62b50 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6208,7 +6208,7 @@
return superResult;
}
- if (mMovement != null && mText instanceof Spannable && mLayout != null) {
+ if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable && mLayout != null) {
if (action == MotionEvent.ACTION_DOWN) {
mScrolled = false;
@@ -6219,7 +6219,9 @@
int oldSelStart = Selection.getSelectionStart(mText);
int oldSelEnd = Selection.getSelectionEnd(mText);
- handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
+ if (mMovement != null) {
+ handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
+ }
if (mText instanceof Editable && onCheckIsTextEditor()) {
if (action == MotionEvent.ACTION_UP && isFocused() && !mScrolled) {
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 6729fd1..4daa419 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -24,12 +24,15 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
+import android.util.Log;
+import android.view.GestureDetector;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -37,31 +40,51 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewRoot;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
-// TODO: make sure no px values exist, only dip (scale if necessary from Viewconfiguration)
-
+/*
+ * Implementation notes:
+ * - The zoom controls are displayed in their own window.
+ * (Easier for the client and better performance)
+ * - This window is not touchable, and by default is not focusable.
+ * - To make the buttons clickable, it attaches a OnTouchListener to the owner
+ * view and does the hit detection locally.
+ * - When it is focusable, it forwards uninteresting events to the owner view's
+ * view hierarchy.
+ */
/**
- * TODO: Docs
- *
+ * The {@link ZoomButtonsController} handles showing and hiding the zoom
+ * controls relative to an owner view. It also gives the client access to the
+ * zoom controls container, allowing for additional accessory buttons to be
+ * shown in the zoom controls window.
+ * <p>
+ * Typical usage involves the client using the {@link GestureDetector} to
+ * forward events from
+ * {@link GestureDetector.OnDoubleTapListener#onDoubleTapEvent(MotionEvent)} to
+ * {@link #handleDoubleTapEvent(MotionEvent)}. Also, whenever the owner cannot
+ * be zoomed further, the client should update
+ * {@link #setZoomInEnabled(boolean)} and {@link #setZoomOutEnabled(boolean)}.
+ * <p>
* If you are using this with a custom View, please call
* {@link #setVisible(boolean) setVisible(false)} from the
* {@link View#onDetachedFromWindow}.
- *
+ *
* @hide
*/
-public class ZoomButtonsController implements View.OnTouchListener, View.OnKeyListener {
+public class ZoomButtonsController implements View.OnTouchListener {
private static final String TAG = "ZoomButtonsController";
private static final int ZOOM_CONTROLS_TIMEOUT =
(int) ViewConfiguration.getZoomControlsTimeout();
- // TODO: scaled to density
private static final int ZOOM_CONTROLS_TOUCH_PADDING = 20;
+ private int mTouchPaddingScaledSq;
private Context mContext;
private WindowManager mWindowManager;
@@ -72,17 +95,17 @@
private View mOwnerView;
/**
- * The bounds of the owner view in global coordinates. This is recalculated
+ * The location of the owner view on the screen. This is recalculated
* each time the zoom controller is shown.
*/
- private Rect mOwnerViewBounds = new Rect();
+ private int[] mOwnerViewRawLocation = new int[2];
/**
* The container that is added as a window.
*/
private FrameLayout mContainer;
private LayoutParams mContainerLayoutParams;
- private int[] mContainerLocation = new int[2];
+ private int[] mContainerRawLocation = new int[2];
private ZoomControls mControls;
@@ -94,7 +117,7 @@
/**
* The {@link #mTouchTargetView}'s location in window, set on touch down.
*/
- private int[] mTouchTargetLocationInWindow = new int[2];
+ private int[] mTouchTargetWindowLocation = new int[2];
/**
* If the zoom controller is dismissed but the user is still in a touch
* interaction, we set this to true. This will ignore all touch events until
@@ -102,15 +125,28 @@
*/
private boolean mReleaseTouchListenerOnUp;
+ /**
+ * Whether we are currently in the double-tap gesture, with the second tap
+ * still being performed (i.e., we're waiting for the second tap's touch up).
+ */
private boolean mIsSecondTapDown;
+ /** Whether the container has been added to the window manager. */
private boolean mIsVisible;
private Rect mTempRect = new Rect();
-
+ private int[] mTempIntArray = new int[2];
+
private OnZoomListener mCallback;
/**
+ * In 1.0, the ZoomControls were to be added to the UI by the client of
+ * WebView, MapView, etc. We didn't want apps to break, so we return a dummy
+ * view in place now.
+ */
+ private InvisibleView mDummyZoomControls;
+
+ /**
* When showing the zoom, we add the view as a new window. However, there is
* logic that needs to know the size of the zoom which is determined after
* it's laid out. Therefore, we must post this logic onto the UI thread so
@@ -121,6 +157,9 @@
private IntentFilter mConfigurationChangedFilter =
new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
+ /**
+ * Needed to reposition the zoom controls after configuration changes.
+ */
private BroadcastReceiver mConfigurationChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -161,41 +200,68 @@
case MSG_POST_SET_VISIBLE:
if (mOwnerView.getWindowToken() == null) {
- // Doh, it is still null, throw an exception
- throw new IllegalArgumentException(
+ // Doh, it is still null, just ignore the set visible call
+ Log.e(TAG,
"Cannot make the zoom controller visible if the owner view is " +
"not attached to a window.");
+ } else {
+ setVisible(true);
}
- setVisible(true);
break;
}
}
};
- public ZoomButtonsController(Context context, View ownerView) {
- mContext = context;
- mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ /**
+ * Constructor for the {@link ZoomButtonsController}.
+ *
+ * @param ownerView The view that is being zoomed by the zoom controls. The
+ * zoom controls will be displayed aligned with this view.
+ */
+ public ZoomButtonsController(View ownerView) {
+ mContext = ownerView.getContext();
+ mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mOwnerView = ownerView;
+ mTouchPaddingScaledSq = (int)
+ (ZOOM_CONTROLS_TOUCH_PADDING * mContext.getResources().getDisplayMetrics().density);
+ mTouchPaddingScaledSq *= mTouchPaddingScaledSq;
+
mContainer = createContainer();
}
+ /**
+ * Whether to enable the zoom in control.
+ *
+ * @param enabled Whether to enable the zoom in control.
+ */
public void setZoomInEnabled(boolean enabled) {
mControls.setIsZoomInEnabled(enabled);
}
+ /**
+ * Whether to enable the zoom out control.
+ *
+ * @param enabled Whether to enable the zoom out control.
+ */
public void setZoomOutEnabled(boolean enabled) {
mControls.setIsZoomOutEnabled(enabled);
}
+ /**
+ * Sets the delay between zoom callbacks as the user holds a zoom button.
+ *
+ * @param speed The delay in milliseconds between zoom callbacks.
+ */
public void setZoomSpeed(long speed) {
mControls.setZoomSpeed(speed);
}
private FrameLayout createContainer() {
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- lp.gravity = Gravity.BOTTOM | Gravity.CENTER;
+ // Controls are positioned BOTTOM | CENTER with respect to the owner view.
+ lp.gravity = Gravity.TOP | Gravity.LEFT;
lp.flags = LayoutParams.FLAG_NOT_TOUCHABLE |
LayoutParams.FLAG_NOT_FOCUSABLE |
LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -206,10 +272,9 @@
lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons;
mContainerLayoutParams = lp;
- FrameLayout container = new FrameLayout(mContext);
+ FrameLayout container = new Container(mContext);
container.setLayoutParams(lp);
container.setMeasureAllChildren(true);
- container.setOnKeyListener(this);
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -232,30 +297,51 @@
return container;
}
- public void setCallback(OnZoomListener callback) {
- mCallback = callback;
+ /**
+ * Sets the {@link OnZoomListener} listener that receives callbacks to zoom.
+ *
+ * @param listener The listener that will be told to zoom.
+ */
+ public void setOnZoomListener(OnZoomListener listener) {
+ mCallback = listener;
}
+ /**
+ * Sets whether the zoom controls should be focusable. If the controls are
+ * focusable, then trackball and arrow key interactions are possible.
+ * Otherwise, only touch interactions are possible.
+ *
+ * @param focusable Whether the zoom controls should be focusable.
+ */
public void setFocusable(boolean focusable) {
+ int oldFlags = mContainerLayoutParams.flags;
if (focusable) {
mContainerLayoutParams.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
} else {
mContainerLayoutParams.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
}
- if (mIsVisible) {
+ if ((mContainerLayoutParams.flags != oldFlags) && mIsVisible) {
mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
}
}
+ /**
+ * Whether the zoom controls are visible to the user.
+ *
+ * @return Whether the zoom controls are visible to the user.
+ */
public boolean isVisible() {
return mIsVisible;
}
+ /**
+ * Sets whether the zoom controls should be visible to the user.
+ *
+ * @param visible Whether the zoom controls should be visible to the user.
+ */
public void setVisible(boolean visible) {
- if (!useThisZoom(mContext)) return;
-
if (visible) {
if (mOwnerView.getWindowToken() == null) {
/*
@@ -329,12 +415,13 @@
}
/**
- * TODO: docs
- *
- * Notes:
- * - Please ensure you set your View to INVISIBLE not GONE when hiding it.
- *
- * @return TODO
+ * Gets the container that is the parent of the zoom controls.
+ * <p>
+ * The client can add other views to this container to link them with the
+ * zoom controls.
+ *
+ * @return The container of the zoom controls. It will be a layout that
+ * respects the gravity of a child's layout parameters.
*/
public ViewGroup getContainer() {
return mContainer;
@@ -347,14 +434,12 @@
/**
* Should be called by the client for each event belonging to the second tap
- * (the down, move, up, and cancel events).
+ * (the down, move, up, and/or cancel events).
*
* @param event The event belonging to the second tap.
* @return Whether the event was consumed.
*/
public boolean handleDoubleTapEvent(MotionEvent event) {
- if (!useThisZoom(mContext)) return false;
-
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
@@ -382,9 +467,28 @@
}
private void refreshPositioningVariables() {
+ // Position the zoom controls on the bottom of the owner view.
+ int ownerHeight = mOwnerView.getHeight();
+ int ownerWidth = mOwnerView.getWidth();
+ // The gap between the top of the owner and the top of the container
+ int containerOwnerYOffset = ownerHeight - mContainer.getHeight();
+
// Calculate the owner view's bounds
- mOwnerView.getGlobalVisibleRect(mOwnerViewBounds);
- mContainer.getLocationOnScreen(mContainerLocation);
+ mOwnerView.getLocationOnScreen(mOwnerViewRawLocation);
+ mContainerRawLocation[0] = mOwnerViewRawLocation[0];
+ mContainerRawLocation[1] = mOwnerViewRawLocation[1] + containerOwnerYOffset;
+
+ int[] ownerViewWindowLoc = mTempIntArray;
+ mOwnerView.getLocationInWindow(ownerViewWindowLoc);
+
+ // lp.x and lp.y should be relative to the owner's window top-left
+ mContainerLayoutParams.x = ownerViewWindowLoc[0];
+ mContainerLayoutParams.width = ownerWidth;
+ mContainerLayoutParams.y = ownerViewWindowLoc[1] + containerOwnerYOffset;
+ if (mIsVisible) {
+ mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams);
+ }
+
}
/**
@@ -396,11 +500,65 @@
}
}
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
- return false;
+ /* This will only be called when the container has focus. */
+ private boolean onContainerKey(KeyEvent event) {
+ int keyCode = event.getKeyCode();
+ if (isInterestingKey(keyCode)) {
+
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ setVisible(false);
+ } else {
+ dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
+ }
+
+ // Let the container handle the key
+ return false;
+
+ } else {
+
+ ViewRoot viewRoot = getOwnerViewRoot();
+ if (viewRoot != null) {
+ viewRoot.dispatchKey(event);
+ }
+
+ // We gave the key to the owner, don't let the container handle this key
+ return true;
+ }
}
+ private boolean isInterestingKey(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_BACK:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private ViewRoot getOwnerViewRoot() {
+ View rootViewOfOwner = mOwnerView.getRootView();
+ if (rootViewOfOwner == null) {
+ return null;
+ }
+
+ ViewParent parentOfRootView = rootViewOfOwner.getParent();
+ if (parentOfRootView instanceof ViewRoot) {
+ return (ViewRoot) parentOfRootView;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @hide The ZoomButtonsController implements the OnTouchListener, but this
+ * does not need to be shown in its public API.
+ */
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
@@ -423,14 +581,13 @@
return true;
}
- // TODO: optimize this (it ends up removing message and queuing another)
dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT);
View targetView = mTouchTargetView;
switch (action) {
case MotionEvent.ACTION_DOWN:
- targetView = getViewForTouch((int) event.getRawX(), (int) event.getRawY());
+ targetView = findViewForTouch((int) event.getRawX(), (int) event.getRawY());
setTouchTargetView(targetView);
break;
@@ -442,14 +599,22 @@
if (targetView != null) {
// The upperleft corner of the target view in raw coordinates
- int targetViewRawX = mContainerLocation[0] + mTouchTargetLocationInWindow[0];
- int targetViewRawY = mContainerLocation[1] + mTouchTargetLocationInWindow[1];
+ int targetViewRawX = mContainerRawLocation[0] + mTouchTargetWindowLocation[0];
+ int targetViewRawY = mContainerRawLocation[1] + mTouchTargetWindowLocation[1];
MotionEvent containerEvent = MotionEvent.obtain(event);
// Convert the motion event into the target view's coordinates (from
// owner view's coordinates)
- containerEvent.offsetLocation(mOwnerViewBounds.left - targetViewRawX,
- mOwnerViewBounds.top - targetViewRawY);
+ containerEvent.offsetLocation(mOwnerViewRawLocation[0] - targetViewRawX,
+ mOwnerViewRawLocation[1] - targetViewRawY);
+ /* Disallow negative coordinates (which can occur due to
+ * ZOOM_CONTROLS_TOUCH_PADDING) */
+ if (containerEvent.getX() < 0) {
+ containerEvent.offsetLocation(-containerEvent.getX(), 0);
+ }
+ if (containerEvent.getY() < 0) {
+ containerEvent.offsetLocation(0, -containerEvent.getY());
+ }
boolean retValue = targetView.dispatchTouchEvent(containerEvent);
containerEvent.recycle();
return retValue || consumeEvent;
@@ -462,7 +627,7 @@
private void setTouchTargetView(View view) {
mTouchTargetView = view;
if (view != null) {
- view.getLocationInWindow(mTouchTargetLocationInWindow);
+ view.getLocationInWindow(mTouchTargetWindowLocation);
}
}
@@ -473,11 +638,15 @@
* @param rawY The raw Y.
* @return The view that should receive the touches, or null if there is not one.
*/
- private View getViewForTouch(int rawX, int rawY) {
+ private View findViewForTouch(int rawX, int rawY) {
// Reverse order so the child drawn on top gets first dibs.
- int containerCoordsX = rawX - mContainerLocation[0];
- int containerCoordsY = rawY - mContainerLocation[1];
+ int containerCoordsX = rawX - mContainerRawLocation[0];
+ int containerCoordsY = rawY - mContainerRawLocation[1];
Rect frame = mTempRect;
+
+ View closestChild = null;
+ int closestChildDistanceSq = Integer.MAX_VALUE;
+
for (int i = mContainer.getChildCount() - 1; i >= 0; i--) {
View child = mContainer.getChildAt(i);
if (child.getVisibility() != View.VISIBLE) {
@@ -485,14 +654,24 @@
}
child.getHitRect(frame);
- // Expand the touch region
- frame.top -= ZOOM_CONTROLS_TOUCH_PADDING;
if (frame.contains(containerCoordsX, containerCoordsY)) {
return child;
}
+
+ int distanceX = Math.min(Math.abs(frame.left - containerCoordsX),
+ Math.abs(containerCoordsX - frame.right));
+ int distanceY = Math.min(Math.abs(frame.top - containerCoordsY),
+ Math.abs(containerCoordsY - frame.bottom));
+ int distanceSq = distanceX * distanceX + distanceY * distanceY;
+
+ if ((distanceSq < mTouchPaddingScaledSq) &&
+ (distanceSq < closestChildDistanceSq)) {
+ closestChild = child;
+ closestChildDistanceSq = distanceSq;
+ }
}
- return null;
+ return closestChild;
}
private void onPostConfigurationChanged() {
@@ -518,6 +697,10 @@
* gallery
*/
public static void showZoomTutorialOnce(Context context) {
+
+ // TODO: remove this code, but to hit the weekend build, just never show
+ if (true) return;
+
ContentResolver cr = context.getContentResolver();
if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TUTORIAL, 0) == 1) {
return;
@@ -583,22 +766,83 @@
finishZoomTutorial(mContext, true);
}
- // Temporary methods for different zoom types
- static int getZoomType(Context context) {
- return Settings.System.getInt(context.getContentResolver(), "zoom", 2);
+ /** @hide Should only be used only be WebView and MapView */
+ public View getDummyZoomControls() {
+ if (mDummyZoomControls == null) {
+ mDummyZoomControls = new InvisibleView(mContext);
+ }
+ return mDummyZoomControls;
}
-
- public static boolean useOldZoom(Context context) {
- return getZoomType(context) == 0;
- }
-
- public static boolean useThisZoom(Context context) {
- return getZoomType(context) == 2;
- }
-
+
+ /**
+ * Interface that will be called when the user performs an interaction that
+ * triggers some action, for example zooming.
+ */
public interface OnZoomListener {
+ /**
+ * Called when the given point should be centered. The point will be in
+ * owner view coordinates.
+ *
+ * @param x The x of the point.
+ * @param y The y of the point.
+ */
void onCenter(int x, int y);
+
+ /**
+ * Called when the zoom controls' visibility changes.
+ *
+ * @param visible Whether the zoom controls are visible.
+ */
void onVisibilityChanged(boolean visible);
+
+ /**
+ * Called when the owner view needs to be zoomed.
+ *
+ * @param zoomIn The direction of the zoom: true to zoom in, false to zoom out.
+ */
void onZoom(boolean zoomIn);
}
+
+ private class Container extends FrameLayout {
+ public Container(Context context) {
+ super(context);
+ }
+
+ /*
+ * Need to override this to intercept the key events. Otherwise, we
+ * would attach a key listener to the container but its superclass
+ * ViewGroup gives it to the focused View instead of calling the key
+ * listener, and so we wouldn't get the events.
+ */
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ return onContainerKey(event) ? true : super.dispatchKeyEvent(event);
+ }
+ }
+
+ /**
+ * An InvisibleView is an invisible, zero-sized View for backwards
+ * compatibility
+ */
+ private final class InvisibleView extends View {
+
+ private InvisibleView(Context context) {
+ super(context);
+ setVisibility(GONE);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(0, 0);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ }
+ }
+
}
diff --git a/core/java/android/widget/ZoomControls.java b/core/java/android/widget/ZoomControls.java
index e978db8..84d8f0e 100644
--- a/core/java/android/widget/ZoomControls.java
+++ b/core/java/android/widget/ZoomControls.java
@@ -29,8 +29,12 @@
/**
* The {@code ZoomControls} class displays a simple set of controls used for zooming and
- * provides callbacks to register for events.
- */
+ * provides callbacks to register for events. */
+// TODO: pending API council
+// * <p>
+// * Instead of using this directly, consider using the {@link ZoomButtonsController} which
+// * handles displaying the zoom controls.
+// */
@Widget
public class ZoomControls extends LinearLayout {
@@ -81,9 +85,7 @@
}
public void show() {
- if (ZoomButtonsController.useOldZoom(mContext)) {
- fade(View.VISIBLE, 0.0f, 1.0f);
- }
+ fade(View.VISIBLE, 0.0f, 1.0f);
}
public void hide() {
diff --git a/core/java/com/android/internal/widget/EditStyledText.java b/core/java/com/android/internal/widget/EditStyledText.java
index 48b4780..8a4675a 100644
--- a/core/java/com/android/internal/widget/EditStyledText.java
+++ b/core/java/com/android/internal/widget/EditStyledText.java
@@ -16,20 +16,26 @@
package com.android.internal.widget;
+import android.app.AlertDialog.Builder;
import android.content.Context;
+import android.content.DialogInterface;
+import android.net.Uri;
+import android.os.Bundle;
import android.text.Editable;
+import android.text.Html;
import android.text.Spannable;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.ForegroundColorSpan;
+import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.EditText;
/**
- * EditStyledText extends EditText for managing the flow and status
- * to edit the styled text. This manages the states and flows of editing,
- * supports inserting image, import/export HTML.
+ * EditStyledText extends EditText for managing the flow and status to edit
+ * the styled text. This manages the states and flows of editing, supports
+ * inserting image, import/export HTML.
*/
public class EditStyledText extends EditText {
@@ -61,7 +67,7 @@
public static final int STATE_SELECT_ON = 1;
/** The state that selection is done, but not fixed. */
public static final int STATE_SELECTED = 2;
- /** The state that selection is done and not fixed.*/
+ /** The state that selection is done and not fixed. */
public static final int STATE_SELECT_FIX = 3;
/**
@@ -73,26 +79,28 @@
public static final int HINT_MSG_SELECT_END = 3;
public static final int HINT_MSG_PUSH_COMPETE = 4;
-
/**
- * EditStyledTextInterface provides functions for notifying messages
- * to calling class.
+ * EditStyledTextInterface provides functions for notifying messages to
+ * calling class.
*/
- public interface EditStyledTextInterface {
- public void notifyHintMsg(int msg_id);
+ public interface EditStyledTextNotifier {
+ public void notifyHintMsg(int msgId);
}
- private EditStyledTextInterface mESTInterface;
+
+ private EditStyledTextNotifier mESTInterface;
/**
- * EditStyledTextEditorManager manages the flow and status of
- * each function for editing styled text.
+ * EditStyledTextEditorManager manages the flow and status of each
+ * function for editing styled text.
*/
- private EditStyledTextEditorManager mManager;
+ private EditorManager mManager;
+ private StyledTextConverter mConverter;
+ private StyledTextToast mToast;
/**
- * EditStyledText extends EditText for managing flow of each editing
- * action.
- */
+ * EditStyledText extends EditText for managing flow of each editing
+ * action.
+ */
public EditStyledText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
@@ -109,11 +117,54 @@
}
/**
- * Set View objects used in EditStyledText.
- * @param helptext The view shows help messages.
+ * Set Notifier.
*/
- public void setParts(EditStyledTextInterface est_interface) {
- mESTInterface = est_interface;
+ public void setNotifier(EditStyledTextNotifier estInterface) {
+ mESTInterface = estInterface;
+ }
+
+ /**
+ * Set Builder for AlertDialog.
+ *
+ * @param builder
+ * Builder for opening Alert Dialog.
+ */
+ public void setBuilder(Builder builder) {
+ mToast.setBuilder(builder);
+ }
+
+ /**
+ * Set Parameters for ColorAlertDialog.
+ *
+ * @param colortitle
+ * Title for Alert Dialog.
+ * @param colornames
+ * List of name of selecting color.
+ * @param colorints
+ * List of int of color.
+ */
+ public void setColorAlertParams(CharSequence colortitle,
+ CharSequence[] colornames, CharSequence[] colorints) {
+ mToast.setColorAlertParams(colortitle, colornames, colorints);
+ }
+
+ /**
+ * Set Parameters for SizeAlertDialog.
+ *
+ * @param sizetitle
+ * Title for Alert Dialog.
+ * @param sizenames
+ * List of name of selecting size.
+ * @param sizedisplayints
+ * List of int of size displayed in TextView.
+ * @param sizesendints
+ * List of int of size exported to HTML.
+ */
+ public void setSizeAlertParams(CharSequence sizetitle,
+ CharSequence[] sizenames, CharSequence[] sizedisplayints,
+ CharSequence[] sizesendints) {
+ mToast.setSizeAlertParams(sizetitle, sizenames, sizedisplayints,
+ sizesendints);
}
@Override
@@ -129,8 +180,8 @@
}
/**
- * Start editing. This function have to be called before other
- * editing actions.
+ * Start editing. This function have to be called before other editing
+ * actions.
*/
public void onStartEdit() {
mManager.onStartEdit();
@@ -186,6 +237,26 @@
}
/**
+ * InsertImage to TextView by using URI
+ *
+ * @param uri
+ * URI of the iamge inserted to TextView.
+ */
+ public void onInsertImage(Uri uri) {
+ mManager.onInsertImage(uri);
+ }
+
+ /**
+ * InsertImage to TextView by using resource ID
+ *
+ * @param resId
+ * Resource ID of the iamge inserted to TextView.
+ */
+ public void onInsertImage(int resId) {
+ mManager.onInsertImage(resId);
+ }
+
+ /**
* Fix Selected Item.
*/
public void fixSelectedItem() {
@@ -194,7 +265,9 @@
/**
* Set Size of the Item.
- * @param size The size of the Item.
+ *
+ * @param size
+ * The size of the Item.
*/
public void setItemSize(int size) {
mManager.setItemSize(size);
@@ -202,14 +275,25 @@
/**
* Set Color of the Item.
- * @param color The color of the Item.
+ *
+ * @param color
+ * The color of the Item.
*/
public void setItemColor(int color) {
mManager.setItemColor(color);
}
+ public void onShowColorAlert() {
+ mToast.onShowColorAlertDialog();
+ }
+
+ public void onShowSizeAlert() {
+ mToast.onShowSizeAlertDialog();
+ }
+
/**
* Check editing is started.
+ *
* @return Whether editing is started or not.
*/
public boolean isEditting() {
@@ -218,6 +302,7 @@
/**
* Get the mode of the action.
+ *
* @return The mode of the action.
*/
public int getEditMode() {
@@ -226,12 +311,17 @@
/**
* Get the state of the selection.
+ *
* @return The state of the selection.
*/
public int getSelectState() {
return mManager.getSelectState();
}
+ public String getBody() {
+ return mConverter.getConvertedBody();
+ }
+
/**
* Initialize members.
*/
@@ -240,23 +330,36 @@
Log.d(LOG_TAG, "--- init");
requestFocus();
}
- mManager = new EditStyledTextEditorManager(this);
+ mManager = new EditorManager(this);
+ mConverter = new StyledTextConverter(this);
+ mToast = new StyledTextToast(this);
}
/**
* Notify hint messages what action is expected to calling class.
- * @param msg
+ *
+ * @param msgId
+ * Id of the hint message.
*/
- private void setHintMessage(int msg_id) {
+ private void setHintMessage(int msgId) {
if (mESTInterface != null) {
- mESTInterface.notifyHintMsg(msg_id);
+ mESTInterface.notifyHintMsg(msgId);
}
}
+ @Override
+ public Bundle getInputExtras(boolean create) {
+ Bundle bundle = super.getInputExtras(create);
+ if (bundle != null) {
+ bundle.putBoolean("allowEmoji", true);
+ }
+ return bundle;
+ }
+
/**
* Object which manages the flow and status of editing actions.
*/
- private class EditStyledTextEditorManager {
+ private class EditorManager {
private boolean mEditFlag = false;
private int mMode = 0;
private int mState = 0;
@@ -266,7 +369,7 @@
private Editable mTextSelectBuffer;
private CharSequence mTextCopyBufer;
- EditStyledTextEditorManager(EditStyledText est) {
+ EditorManager(EditStyledText est) {
mEST = est;
}
@@ -368,6 +471,28 @@
handleComplete();
}
+ public void onInsertImage(Uri uri) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onInsertImage by URI: " + uri.getPath()
+ + "," + uri.toString());
+ }
+
+ mEST.getText().append("a");
+ mEST.getText().setSpan(new ImageSpan(mEST.getContext(), uri),
+ mEST.getText().length() - 1, mEST.getText().length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ public void onInsertImage(int resID) {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onInsertImage by resID");
+ }
+ mEST.getText().append("b");
+ mEST.getText().setSpan(new ImageSpan(mEST.getContext(), resID),
+ mEST.getText().length() - 1, mEST.getText().length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
public boolean isEditting() {
return mEditFlag;
}
@@ -404,6 +529,12 @@
case MODE_COPY:
handleCopy();
break;
+ case MODE_COLOR:
+ handleColor();
+ break;
+ case MODE_SIZE:
+ handleSize();
+ break;
default:
break;
}
@@ -455,12 +586,14 @@
Log.d(LOG_TAG, "--- handleSize: " + mMode + "," + mState);
}
if (!mEditFlag) {
+ Log.e(LOG_TAG, "--- Editing is not started for handlesize.");
return;
}
if (mMode == MODE_NOTHING || mMode == MODE_SELECT) {
mMode = MODE_SIZE;
if (mState == STATE_SELECTED) {
mState = STATE_SELECT_FIX;
+ handleSize();
} else {
handleSelect();
}
@@ -468,22 +601,29 @@
handleCancel();
mMode = MODE_SIZE;
handleSize();
- } else if (mState == STATE_SELECT_FIX) {
- mEST.setHintMessage(HINT_MSG_NULL);
+ } else {
+ if (mState == STATE_SELECT_FIX) {
+ mEST.setHintMessage(HINT_MSG_NULL);
+ mEST.onShowSizeAlert();
+ } else {
+ Log.d(LOG_TAG, "--- handlesize: do nothing");
+ }
}
}
private void handleColor() {
if (DBG) {
- Log.d(LOG_TAG, "--- handleColor");
+ Log.d(LOG_TAG, "--- handleSize: " + mMode + "," + mState);
}
if (!mEditFlag) {
+ Log.e(LOG_TAG, "--- Editing is not started for handlecolor.");
return;
}
if (mMode == MODE_NOTHING || mMode == MODE_SELECT) {
mMode = MODE_COLOR;
if (mState == STATE_SELECTED) {
mState = STATE_SELECT_FIX;
+ handleColor();
} else {
handleSelect();
}
@@ -491,35 +631,39 @@
handleCancel();
mMode = MODE_COLOR;
handleSize();
- } else if (mState == STATE_SELECT_FIX) {
- mEST.setHintMessage(HINT_MSG_NULL);
+ } else {
+ if (mState == STATE_SELECT_FIX) {
+ mEST.setHintMessage(HINT_MSG_NULL);
+ mEST.onShowColorAlert();
+ } else {
+ Log.d(LOG_TAG, "--- handlecolor: do nothing");
+ }
}
}
private void handleSelect() {
if (DBG) {
- Log.d(LOG_TAG, "--- handleSelect" + mEditFlag + "," + mState);
+ Log.d(LOG_TAG, "--- handleSelect:" + mEditFlag + "," + mState);
}
if (!mEditFlag) {
return;
}
if (mState == STATE_SELECT_OFF) {
if (isTextSelected()) {
- Log.e(LOG_TAG, "Selection state is off, but selected");
+ Log.e(LOG_TAG, "Selection is off, but selected");
}
setSelectStartPos();
mEST.setHintMessage(HINT_MSG_SELECT_END);
} else if (mState == STATE_SELECT_ON) {
if (isTextSelected()) {
- Log.e(LOG_TAG, "Selection state now start, but selected");
+ Log.e(LOG_TAG, "Selection now start, but selected");
}
setSelectEndPos();
mEST.setHintMessage(HINT_MSG_PUSH_COMPETE);
doNextHandle();
} else if (mState == STATE_SELECTED) {
if (!isTextSelected()) {
- Log.e(LOG_TAG,
- "Selection state is done, but not selected");
+ Log.e(LOG_TAG, "Selection is done, but not selected");
}
setSelectEndPos();
doNextHandle();
@@ -537,6 +681,9 @@
}
private void doNextHandle() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- doNextHandle: " + mMode + "," + mState);
+ }
switch (mMode) {
case MODE_COPY:
handleCopy();
@@ -556,6 +703,9 @@
}
private void handleResetEdit() {
+ if (DBG) {
+ Log.d(LOG_TAG, "Reset Editor");
+ }
handleCancel();
mEditFlag = true;
mEST.setHintMessage(HINT_MSG_SELECT_START);
@@ -564,7 +714,7 @@
// Methods of selection
private void onSelect() {
if (DBG) {
- Log.d(LOG_TAG, "--- onSelect");
+ Log.d(LOG_TAG, "--- onSelect:" + mCurStart + "," + mCurEnd);
}
if (mCurStart >= 0 && mCurStart <= mEST.getText().length()
&& mCurEnd >= 0 && mCurEnd <= mEST.getText().length()) {
@@ -650,4 +800,132 @@
}
}
+ private class StyledTextConverter {
+ private EditStyledText mEST;
+
+ public StyledTextConverter(EditStyledText est) {
+ mEST = est;
+ }
+
+ public String getConvertedBody() {
+ String htmlBody = Html.toHtml(mEST.getText());
+ return htmlBody;
+ }
+ }
+
+ private class StyledTextToast {
+ Builder mBuilder;
+ CharSequence mColorTitle;
+ CharSequence mSizeTitle;
+ CharSequence[] mColorNames;
+ CharSequence[] mColorInts;
+ CharSequence[] mSizeNames;
+ CharSequence[] mSizeDisplayInts;
+ CharSequence[] mSizeSendInts;
+ EditStyledText mEST;
+
+ public StyledTextToast(EditStyledText est) {
+ mEST = est;
+ }
+
+ public void setBuilder(Builder builder) {
+ mBuilder = builder;
+ }
+
+ public void setColorAlertParams(CharSequence colortitle,
+ CharSequence[] colornames, CharSequence[] colorints) {
+ mColorTitle = colortitle;
+ mColorNames = colornames;
+ mColorInts = colorints;
+ }
+
+ public void setSizeAlertParams(CharSequence sizetitle,
+ CharSequence[] sizenames, CharSequence[] sizedisplayints,
+ CharSequence[] sizesendints) {
+ mSizeTitle = sizetitle;
+ mSizeNames = sizenames;
+ mSizeDisplayInts = sizedisplayints;
+ mSizeSendInts = sizesendints;
+ }
+
+ public boolean checkColorAlertParams() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- checkParams");
+ }
+ if (mBuilder == null) {
+ Log.e(LOG_TAG, "--- builder is null.");
+ return false;
+ } else if (mColorTitle == null || mColorNames == null
+ || mColorInts == null) {
+ Log.e(LOG_TAG, "--- color alert params are null.");
+ return false;
+ } else if (mColorNames.length != mColorInts.length) {
+ Log.e(LOG_TAG, "--- the length of color alert params are "
+ + "different.");
+ return false;
+ }
+ return true;
+ }
+
+ public boolean checkSizeAlertParams() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- checkParams");
+ }
+ if (mBuilder == null) {
+ Log.e(LOG_TAG, "--- builder is null.");
+ } else if (mSizeTitle == null || mSizeNames == null
+ || mSizeDisplayInts == null || mSizeSendInts == null) {
+ Log.e(LOG_TAG, "--- size alert params are null.");
+ } else if (mSizeNames.length != mSizeDisplayInts.length
+ && mSizeSendInts.length != mSizeDisplayInts.length) {
+ Log.e(LOG_TAG, "--- the length of size alert params are "
+ + "different.");
+ }
+ return true;
+ }
+
+ private void onShowColorAlertDialog() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onShowAlertDialog");
+ }
+ if (!checkColorAlertParams()) {
+ return;
+ }
+ mBuilder.setTitle(mColorTitle);
+ mBuilder.setIcon(0);
+ mBuilder.
+ setItems(mColorNames,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d("EETVM", "mBuilder.onclick:" + which);
+ int color = Integer.parseInt(
+ (String) mColorInts[which], 16) - 0x01000000;
+ mEST.setItemColor(color);
+ }
+ });
+ mBuilder.show();
+ }
+
+ private void onShowSizeAlertDialog() {
+ if (DBG) {
+ Log.d(LOG_TAG, "--- onShowAlertDialog");
+ }
+ if (!checkColorAlertParams()) {
+ return;
+ }
+ mBuilder.setTitle(mSizeTitle);
+ mBuilder.setIcon(0);
+ mBuilder.
+ setItems(mSizeNames,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d("EETVM", "mBuilder.onclick:" + which);
+ int size = Integer
+ .parseInt((String) mSizeDisplayInts[which]);
+ mEST.setItemSize(size);
+ }
+ });
+ mBuilder.show();
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index c8b3ad4..f0b311c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -78,6 +78,7 @@
private final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
private final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
+ private final static String PATTERN_EVER_CHOSEN = "lockscreen.patterneverchosen";
private final ContentResolver mContentResolver;
@@ -139,6 +140,16 @@
}
/**
+ * Return true if the user has ever chosen a pattern. This is true even if the pattern is
+ * currently cleared.
+ *
+ * @return True if the user has ever chosen a pattern.
+ */
+ public boolean isPatternEverChosen() {
+ return getBoolean(PATTERN_EVER_CHOSEN);
+ }
+
+ /**
* Save a lock pattern.
* @param pattern The new pattern to save.
*/
@@ -155,6 +166,7 @@
raf.write(hash, 0, hash.length);
}
raf.close();
+ setBoolean(PATTERN_EVER_CHOSEN, true);
} catch (FileNotFoundException fnfe) {
// Cant do much, unless we want to fail over to using the settings provider
Log.e(TAG, "Unable to save lock pattern to " + sLockPatternFilename);
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index 1429f58..971f87c 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+//#define LOG_NDEBUG 0
+
#include "JNIHelp.h"
#include <fcntl.h>
@@ -45,6 +47,11 @@
jfieldID mFileDescriptor;
} gSocketImplOffsets;
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jfieldID mFileDescriptor;
+} gParcelFileDescriptorOffsets;
static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
jobject clazz, jobject object)
@@ -60,10 +67,21 @@
return fileDescriptorClone;
}
+static jint getFd(JNIEnv* env, jobject clazz)
+{
+ jobject descriptor = env->GetObjectField(clazz, gParcelFileDescriptorOffsets.mFileDescriptor);
+ if (descriptor == NULL) return -1;
+ return env->GetIntField(descriptor, gFileDescriptorOffsets.mDescriptor);
+}
+
static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
jobject clazz)
{
- jint fd = env->GetIntField(clazz, gFileDescriptorOffsets.mDescriptor);
+ jint fd = getFd(env, clazz);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
+ return -1;
+ }
struct stat st;
if (fstat(fd, &st) != 0) {
@@ -80,7 +98,12 @@
static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
jobject clazz, jlong pos)
{
- jint fd = env->GetIntField(clazz, gFileDescriptorOffsets.mDescriptor);
+ jint fd = getFd(env, clazz);
+ if (fd < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
+ return -1;
+ }
+
return lseek(fd, pos, SEEK_SET);
}
@@ -121,6 +144,10 @@
clazz = env->FindClass(kParcelFileDescriptorPathName);
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+ gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gParcelFileDescriptorOffsets.mFileDescriptor = env->GetFieldID(clazz, "mFileDescriptor", "Ljava/io/FileDescriptor;");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mFileDescriptor == NULL,
+ "Unable to find mFileDescriptor field in android.os.ParcelFileDescriptor");
return AndroidRuntime::registerNativeMethods(
env, kParcelFileDescriptorPathName,
diff --git a/core/res/res/anim/app_starting_exit.xml b/core/res/res/anim/app_starting_exit.xml
index c6f94b0..0675575 100644
--- a/core/res/res/anim/app_starting_exit.xml
+++ b/core/res/res/anim/app_starting_exit.xml
@@ -19,6 +19,6 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dialog_enter.xml b/core/res/res/anim/dialog_enter.xml
index f48dd37..cc409e8 100644
--- a/core/res/res/anim/dialog_enter.xml
+++ b/core/res/res/anim/dialog_enter.xml
@@ -23,7 +23,7 @@
<scale android:fromXScale="0.9" android:toXScale="1.0"
android:fromYScale="0.9" android:toYScale="1.0"
android:pivotX="50%" android:pivotY="50%"
- android:duration="75" />
+ android:duration="@android:integer/config_shortAnimTime" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="75" />
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/dialog_exit.xml b/core/res/res/anim/dialog_exit.xml
index 24de6e7..8bf8082 100644
--- a/core/res/res/anim/dialog_exit.xml
+++ b/core/res/res/anim/dialog_exit.xml
@@ -22,7 +22,7 @@
<scale android:fromXScale="1.0" android:toXScale="0.9"
android:fromYScale="1.0" android:toYScale="0.9"
android:pivotX="50%" android:pivotY="50%"
- android:duration="75" />
+ android:duration="@android:integer/config_shortAnimTime" />
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="75"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/fade_in.xml b/core/res/res/anim/fade_in.xml
index 32eea01..57310d9 100644
--- a/core/res/res/anim/fade_in.xml
+++ b/core/res/res/anim/fade_in.xml
@@ -18,4 +18,7 @@
*/
-->
-<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
+<alpha xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
diff --git a/core/res/res/anim/fade_out.xml b/core/res/res/anim/fade_out.xml
index e8ae9c1..dc76276 100644
--- a/core/res/res/anim/fade_out.xml
+++ b/core/res/res/anim/fade_out.xml
@@ -21,5 +21,5 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator"
android:fromAlpha="1.0"
android:toAlpha="0.0"
- android:duration="300"
+ android:duration="@android:integer/config_mediumAnimTime"
/>
diff --git a/core/res/res/anim/grow_fade_in.xml b/core/res/res/anim/grow_fade_in.xml
index 0969857..5dc41cb 100644
--- a/core/res/res/anim/grow_fade_in.xml
+++ b/core/res/res/anim/grow_fade_in.xml
@@ -21,6 +21,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="0.3" android:toYScale="1.0"
- android:pivotX="0%" android:pivotY="0%" android:duration="125" />
- <alpha android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ android:pivotX="0%" android:pivotY="0%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/grow_fade_in_center.xml b/core/res/res/anim/grow_fade_in_center.xml
index 01d7a77..c07a82e 100644
--- a/core/res/res/anim/grow_fade_in_center.xml
+++ b/core/res/res/anim/grow_fade_in_center.xml
@@ -21,6 +21,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="0.6" android:toXScale="1.0"
android:fromYScale="0.6" android:toYScale="1.0"
- android:pivotX="50%" android:pivotY="50%" android:duration="125" />
- <alpha android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/grow_fade_in_from_bottom.xml b/core/res/res/anim/grow_fade_in_from_bottom.xml
index d3e468d..848c677 100644
--- a/core/res/res/anim/grow_fade_in_from_bottom.xml
+++ b/core/res/res/anim/grow_fade_in_from_bottom.xml
@@ -21,6 +21,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="0.5" android:toXScale="1.0"
android:fromYScale="0.5" android:toYScale="1.0"
- android:pivotX="0%" android:pivotY="100%" android:duration="125" />
- <alpha android:interpolator="@anim/decelerate_interpolator" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ android:pivotX="0%" android:pivotY="100%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/decelerate_interpolator"
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/input_method_enter.xml b/core/res/res/anim/input_method_enter.xml
index 6263c37649..3858651 100644
--- a/core/res/res/anim/input_method_enter.xml
+++ b/core/res/res/anim/input_method_enter.xml
@@ -20,7 +20,8 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="20%" android:toYDelta="0" android:duration="100"/>
+ <translate android:fromYDelta="20%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="0.5" android:toAlpha="1.0"
- android:duration="100" />
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml
index af9382c..25369ab 100644
--- a/core/res/res/anim/input_method_exit.xml
+++ b/core/res/res/anim/input_method_exit.xml
@@ -19,7 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/accelerate_interpolator">
- <translate android:fromYDelta="0" android:toYDelta="20%" android:duration="100"/>
+ <translate android:fromYDelta="0" android:toYDelta="20%"
+ android:duration="@android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:duration="100"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/input_method_fancy_enter.xml b/core/res/res/anim/input_method_fancy_enter.xml
index 15f5ad7..c6949b3 100644
--- a/core/res/res/anim/input_method_fancy_enter.xml
+++ b/core/res/res/anim/input_method_fancy_enter.xml
@@ -23,6 +23,7 @@
<scale android:fromXScale="2.0" android:toXScale="1.0"
android:fromYScale="2.0" android:toYScale="1.0"
android:pivotX="50%" android:pivotY="50%"
- android:duration="100" />
- <translate android:fromYDelta="100%" android:toYDelta="0" android:duration="100"/>
+ android:duration="@android:integer/config_shortAnimTime" />
+ <translate android:fromYDelta="100%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/input_method_fancy_exit.xml b/core/res/res/anim/input_method_fancy_exit.xml
index ecc5de3..7333cca 100644
--- a/core/res/res/anim/input_method_fancy_exit.xml
+++ b/core/res/res/anim/input_method_fancy_exit.xml
@@ -22,6 +22,7 @@
<scale android:fromXScale="1.0" android:toXScale="2.0"
android:fromYScale="1.0" android:toYScale="2.0"
android:pivotX="50%" android:pivotY="50%"
- android:duration="100" />
- <translate android:fromYDelta="0" android:toYDelta="100%" android:duration="100"/>
+ android:duration="@android:integer/config_shortAnimTime" />
+ <translate android:fromYDelta="0" android:toYDelta="100%"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/lock_screen_exit.xml b/core/res/res/anim/lock_screen_exit.xml
index 54d8e93..55c5ec9 100644
--- a/core/res/res/anim/lock_screen_exit.xml
+++ b/core/res/res/anim/lock_screen_exit.xml
@@ -19,5 +19,6 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/options_panel_enter.xml b/core/res/res/anim/options_panel_enter.xml
index 9614014..d81866b 100644
--- a/core/res/res/anim/options_panel_enter.xml
+++ b/core/res/res/anim/options_panel_enter.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ <translate android:fromYDelta="25%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/options_panel_exit.xml b/core/res/res/anim/options_panel_exit.xml
index c9bee1d..4e7af7a 100644
--- a/core/res/res/anim/options_panel_exit.xml
+++ b/core/res/res/anim/options_panel_exit.xml
@@ -19,7 +19,9 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
- <translate android:fromYDelta="0" android:toYDelta="50%" android:duration="50"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+ <translate android:fromYDelta="0" android:toYDelta="50%"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/push_down_in.xml b/core/res/res/anim/push_down_in.xml
index 1cb1597..6ab9a04 100644
--- a/core/res/res/anim/push_down_in.xml
+++ b/core/res/res/anim/push_down_in.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="-100%p" android:toYDelta="0" android:duration="300"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
+ <translate android:fromYDelta="-100%p" android:toYDelta="0"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/push_down_out.xml b/core/res/res/anim/push_down_out.xml
index 1ad49b0..ce36458 100644
--- a/core/res/res/anim/push_down_out.xml
+++ b/core/res/res/anim/push_down_out.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="100%p" android:duration="300"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />
+ <translate android:fromYDelta="0" android:toYDelta="100%p"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/push_up_in.xml b/core/res/res/anim/push_up_in.xml
index a2f47e9..6ef582c 100644
--- a/core/res/res/anim/push_up_in.xml
+++ b/core/res/res/anim/push_up_in.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="300"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
+ <translate android:fromYDelta="100%p" android:toYDelta="0"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/push_up_out.xml b/core/res/res/anim/push_up_out.xml
index 2803435..2b267d5 100644
--- a/core/res/res/anim/push_up_out.xml
+++ b/core/res/res/anim/push_up_out.xml
@@ -15,6 +15,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="-100%p" android:duration="300"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />
+ <translate android:fromYDelta="0" android:toYDelta="-100%p"
+ android:duration="@android:integer/config_longAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime" />
</set>
diff --git a/core/res/res/anim/search_bar_enter.xml b/core/res/res/anim/search_bar_enter.xml
index ecb86c1..c85caaa 100644
--- a/core/res/res/anim/search_bar_enter.xml
+++ b/core/res/res/anim/search_bar_enter.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="-25%" android:toYDelta="0" android:duration="75"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+ <translate android:fromYDelta="-25%" android:toYDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/search_bar_exit.xml b/core/res/res/anim/search_bar_exit.xml
index db7142e..1609a12 100644
--- a/core/res/res/anim/search_bar_exit.xml
+++ b/core/res/res/anim/search_bar_exit.xml
@@ -19,7 +19,9 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
- <translate android:fromYDelta="0" android:toYDelta="-50%" android:duration="50"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+ <translate android:fromYDelta="0" android:toYDelta="-50%"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/shrink_fade_out.xml b/core/res/res/anim/shrink_fade_out.xml
index ae15ff9..4000c23 100644
--- a/core/res/res/anim/shrink_fade_out.xml
+++ b/core/res/res/anim/shrink_fade_out.xml
@@ -20,6 +20,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="1.0" android:toYScale="0.3"
- android:pivotX="0%" android:pivotY="0%" android:duration="125" />
- <alpha android:interpolator="@anim/accelerate_interpolator" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="75"/>
+ android:pivotX="0%" android:pivotY="0%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/accelerate_interpolator"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/shrink_fade_out_center.xml b/core/res/res/anim/shrink_fade_out_center.xml
index 7b0be34..a41731e 100644
--- a/core/res/res/anim/shrink_fade_out_center.xml
+++ b/core/res/res/anim/shrink_fade_out_center.xml
@@ -20,6 +20,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="0.5"
android:fromYScale="1.0" android:toYScale="0.5"
- android:pivotX="50%" android:pivotY="50%" android:duration="125" />
- <alpha android:interpolator="@anim/accelerate_interpolator" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="75"/>
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/accelerate_interpolator"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/shrink_fade_out_from_bottom.xml b/core/res/res/anim/shrink_fade_out_from_bottom.xml
index 61f29d5..345a2e061 100644
--- a/core/res/res/anim/shrink_fade_out_from_bottom.xml
+++ b/core/res/res/anim/shrink_fade_out_from_bottom.xml
@@ -20,6 +20,9 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="1.0" android:toYScale="0.3"
- android:pivotX="0%" android:pivotY="100%" android:duration="125" />
- <alpha android:interpolator="@anim/accelerate_interpolator" android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="75"/>
+ android:pivotX="0%" android:pivotY="100%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:interpolator="@anim/accelerate_interpolator"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/slide_in_bottom.xml b/core/res/res/anim/slide_in_bottom.xml
index 569d974..d111854 100644
--- a/core/res/res/anim/slide_in_bottom.xml
+++ b/core/res/res/anim/slide_in_bottom.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="50%p" android:toYDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromYDelta="50%p" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_child_bottom.xml b/core/res/res/anim/slide_in_child_bottom.xml
index ce51c36..2ab0f66 100644
--- a/core/res/res/anim/slide_in_child_bottom.xml
+++ b/core/res/res/anim/slide_in_child_bottom.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromYDelta="100%" android:toYDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromYDelta="100%" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_left.xml b/core/res/res/anim/slide_in_left.xml
index 033bfe2..9a585f5 100644
--- a/core/res/res/anim/slide_in_left.xml
+++ b/core/res/res/anim/slide_in_left.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="-50%p" android:toXDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromXDelta="-50%p" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_right.xml b/core/res/res/anim/slide_in_right.xml
index 76b336c..125060e 100644
--- a/core/res/res/anim/slide_in_right.xml
+++ b/core/res/res/anim/slide_in_right.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="50%p" android:toXDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromXDelta="50%p" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_in_top.xml b/core/res/res/anim/slide_in_top.xml
index 15df913..f4810ab 100644
--- a/core/res/res/anim/slide_in_top.xml
+++ b/core/res/res/anim/slide_in_top.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="-50%p" android:toYDelta="0" android:duration="200"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="200" />
+ <translate android:fromYDelta="-50%p" android:toYDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_bottom.xml b/core/res/res/anim/slide_out_bottom.xml
index 8f6e8b0..8ddcd59 100644
--- a/core/res/res/anim/slide_out_bottom.xml
+++ b/core/res/res/anim/slide_out_bottom.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromYDelta="0" android:toYDelta="50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_left.xml b/core/res/res/anim/slide_out_left.xml
index 979d10a..73337d4 100644
--- a/core/res/res/anim/slide_out_left.xml
+++ b/core/res/res/anim/slide_out_left.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="-50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromXDelta="0" android:toXDelta="-50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_right.xml b/core/res/res/anim/slide_out_right.xml
index b5f9bb9..de8c512 100644
--- a/core/res/res/anim/slide_out_right.xml
+++ b/core/res/res/anim/slide_out_right.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromXDelta="0" android:toXDelta="50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/slide_out_top.xml b/core/res/res/anim/slide_out_top.xml
index b15323e..3134a57 100644
--- a/core/res/res/anim/slide_out_top.xml
+++ b/core/res/res/anim/slide_out_top.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromYDelta="0" android:toYDelta="-50%p" android:duration="200"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="200" />
+ <translate android:fromYDelta="0" android:toYDelta="-50%p"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/status_bar_enter.xml b/core/res/res/anim/status_bar_enter.xml
index b57d8e7..d308ad5 100644
--- a/core/res/res/anim/status_bar_enter.xml
+++ b/core/res/res/anim/status_bar_enter.xml
@@ -20,7 +20,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
<translate android:fromYDelta="-75%" android:toYDelta="0"
- android:duration="200"/>
+ android:duration="@android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="200" />
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/status_bar_exit.xml b/core/res/res/anim/status_bar_exit.xml
index 8c6dc1c..43a1b9a 100644
--- a/core/res/res/anim/status_bar_exit.xml
+++ b/core/res/res/anim/status_bar_exit.xml
@@ -20,7 +20,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/accelerate_interpolator">
<translate android:fromYDelta="0" android:toYDelta="-75%"
- android:startOffset="100" android:duration="200"/>
+ android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:startOffset="100" android:duration="200" />
+ android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/submenu_enter.xml b/core/res/res/anim/submenu_enter.xml
index 32a8054..5a94971 100644
--- a/core/res/res/anim/submenu_enter.xml
+++ b/core/res/res/anim/submenu_enter.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromXDelta="-25%" android:toXDelta="0" android:duration="100"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="100" />
+ <translate android:fromXDelta="-25%" android:toXDelta="0"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/submenu_exit.xml b/core/res/res/anim/submenu_exit.xml
index 9283751..20fbefc 100644
--- a/core/res/res/anim/submenu_exit.xml
+++ b/core/res/res/anim/submenu_exit.xml
@@ -19,6 +19,8 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
- <translate android:fromXDelta="0" android:toXDelta="25%" android:duration="50"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+ <translate android:fromXDelta="0" android:toXDelta="25%"
+ android:duration="@android:integer/config_shortAnimTime"/>
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index 6bef7a4..c289869 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -21,5 +21,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
- <translate android:fromXDelta="-100%" android:toXDelta="0" android:duration="200"/>
+ <translate android:fromXDelta="-100%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index 48dc31a..96fff94 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -20,5 +20,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromXDelta="0%" android:toXDelta="33%" android:duration="200"/>
+ <translate android:fromXDelta="0%" android:toXDelta="33%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index e498c9d..8e7d049 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -20,5 +20,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <translate android:fromXDelta="33%" android:toXDelta="0" android:duration="200"/>
+ <translate android:fromXDelta="33%" android:toXDelta="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 8ef4006..5e5c66d 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -21,5 +21,6 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
- <translate android:fromXDelta="0%" android:toXDelta="-100%" android:duration="200"/>
+ <translate android:fromXDelta="0%" android:toXDelta="-100%"
+ android:duration="@android:integer/config_mediumAnimTime"/>
</set>
diff --git a/core/res/res/anim/toast_enter.xml b/core/res/res/anim/toast_enter.xml
index 83cb1fe..57310d9 100644
--- a/core/res/res/anim/toast_enter.xml
+++ b/core/res/res/anim/toast_enter.xml
@@ -20,4 +20,5 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
- android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="400" />
+ android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime" />
diff --git a/core/res/res/anim/toast_exit.xml b/core/res/res/anim/toast_exit.xml
index f922085..b7c5fa0 100644
--- a/core/res/res/anim/toast_exit.xml
+++ b/core/res/res/anim/toast_exit.xml
@@ -20,5 +20,6 @@
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/accelerate_interpolator"
- android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="400"
+ android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_longAnimTime"
/>
diff --git a/core/res/res/drawable-land/statusbar_background.png b/core/res/res/drawable-land/statusbar_background.png
index bafa5c5..2a351a5 100644
--- a/core/res/res/drawable-land/statusbar_background.png
+++ b/core/res/res/drawable-land/statusbar_background.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_horizontal.9.png b/core/res/res/drawable/scrollbar_handle_horizontal.9.png
index 324b4bd..8584d1f 100755
--- a/core/res/res/drawable/scrollbar_handle_horizontal.9.png
+++ b/core/res/res/drawable/scrollbar_handle_horizontal.9.png
Binary files differ
diff --git a/core/res/res/drawable/scrollbar_handle_vertical.9.png b/core/res/res/drawable/scrollbar_handle_vertical.9.png
index 3519d68..331a05d 100755
--- a/core/res/res/drawable/scrollbar_handle_vertical.9.png
+++ b/core/res/res/drawable/scrollbar_handle_vertical.9.png
Binary files differ
diff --git a/core/res/res/drawable/statusbar_background.png b/core/res/res/drawable/statusbar_background.png
index 25a2344..2d8aa7a 100644
--- a/core/res/res/drawable/statusbar_background.png
+++ b/core/res/res/drawable/statusbar_background.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
index 19305c5..881652b 100644
--- a/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_sim_pin_landscape.xml
@@ -20,7 +20,7 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="#A0000000"
+ android:background="@android:color/background_dark"
>
<!-- displays dots as user enters pin -->
@@ -49,7 +49,6 @@
/>
<ImageButton android:id="@+id/backspace"
- style="@android:style/Widget.Button.Inset"
android:src="@android:drawable/ic_input_delete"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
diff --git a/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml b/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
index 6a05488..fc82e3f 100644
--- a/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_sim_pin_portrait.xml
@@ -16,231 +16,251 @@
** limitations under the License.
*/
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="#A0000000"
+ android:background="@android:color/background_dark"
>
- <!-- header text ('Enter Pin Code') -->
- <TextView android:id="@+id/headerText"
+ <LinearLayout android:id="@+id/topDisplayGroup"
android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:textSize="26sp"
- />
+ android:layout_height="115dip"
+ android:layout_alignParentTop="true"
+ android:orientation="vertical"
+ >
- <!-- displays dots as user enters pin -->
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:addStatesFromChildren="true"
- android:gravity="center_vertical"
- android:baselineAligned="false"
- android:paddingRight="0dip"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="5dip"
- android:layout_marginLeft="5dip"
- android:background="@android:drawable/edit_text"
- >
+ <!-- header text ('Enter Pin Code') -->
+ <TextView android:id="@+id/headerText"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="9dip"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ />
- <EditText android:id="@+id/pinDisplay"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="fill_parent"
- android:maxLines="1"
- android:background="@null"
- android:inputType="textPassword"
- />
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="18dip"
+ android:layout_marginRight="6dip"
+ android:layout_marginLeft="6dip"
+ android:background="@android:drawable/edit_text"
+ >
- <ImageButton android:id="@+id/backspace"
- style="@android:style/Widget.Button.Inset"
- android:src="@android:drawable/ic_input_delete"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_marginTop="2dip"
- android:layout_marginRight="2dip"
- android:layout_marginBottom="2dip"
- android:gravity="center"
- />
+ <!-- displays dots as user enters pin -->
+ <TextView android:id="@+id/pinDisplay"
+ android:layout_width="wrap_content"
+ android:layout_height="64dip"
+ android:layout_centerInParent="true"
+ android:maxLines="1"
+ android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textStyle="bold"
+ android:inputType="textPassword"
+ />
+
+ <ImageButton android:id="@+id/backspace"
+ android:src="@android:drawable/ic_input_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="1dip"
+ />
+ </RelativeLayout>
+
</LinearLayout>
<!-- Keypad section -->
- <LinearLayout
+ <LinearLayout android:id="@+id/keyPad"
android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
+ android:layout_height="wrap_content"
+ android:layout_below="@id/topDisplayGroup"
+ android:orientation="vertical"
+ >
- <Button android:id="@+id/one"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
- <Button android:id="@+id/two"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/one"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <Button android:id="@+id/three"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
- </LinearLayout>
+ <Button android:id="@+id/two"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
+ <Button android:id="@+id/three"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
+ </LinearLayout>
- <Button android:id="@+id/four"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
- <Button android:id="@+id/five"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/four"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <Button android:id="@+id/six"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
- </LinearLayout>
+ <Button android:id="@+id/five"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
+ <Button android:id="@+id/six"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
+ </LinearLayout>
- <Button android:id="@+id/seven"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
- <Button android:id="@+id/eight"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/seven"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <Button android:id="@+id/nine"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
- </LinearLayout>
+ <Button android:id="@+id/eight"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="0sp"
- android:layout_weight="1"
- android:layout_marginLeft="5dip"
- android:layout_marginRight="4dip"
- android:orientation="horizontal"
- >
+ <Button android:id="@+id/nine"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
+ </LinearLayout>
- <Button android:id="@+id/ok"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="18sp"
- android:text="@android:string/ok"
- />
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="64dip"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:orientation="horizontal"
+ >
- <Button android:id="@+id/zero"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="22sp"
- />
+ <Button android:id="@+id/ok"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:text="@android:string/ok"
+ />
- <Button android:id="@+id/cancel"
- android:layout_width="0sp"
- android:layout_height="fill_parent"
- android:layout_weight="1"
- android:paddingLeft="4dip"
- style="?android:attr/buttonStyleSmall"
- android:textSize="18sp"
- android:text="@android:string/cancel"
- />
+ <Button android:id="@+id/zero"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textStyle="bold"
+ />
+
+ <Button android:id="@+id/cancel"
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:layout_marginLeft="2dip"
+ android:layout_marginRight="2dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="bold"
+ android:text="@android:string/cancel"
+ />
+ </LinearLayout>
+
+ <!-- end keypad -->
</LinearLayout>
<!-- emergency call button -->
- <RelativeLayout
+ <Button
+ android:id="@+id/emergencyCall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_alignParentBottom="true"
+ android:drawableLeft="@android:drawable/ic_emergency"
+ android:drawablePadding="3dip"
+ android:text="@android:string/lockscreen_emergency_call"
+ />
+
+ <!-- spacer below keypad -->
+ <View
+ android:id="@+id/spacerBottom"
android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- >
+ android:layout_height="1dip"
+ android:layout_marginBottom="6dip"
+ android:layout_above="@id/emergencyCall"
+ android:background="@android:drawable/divider_horizontal_dark"/>
- <Button
- android:id="@+id/emergencyCall"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:drawableLeft="@drawable/ic_emergency"
- android:drawablePadding="3dip"
- android:paddingTop="4dip"
- android:paddingBottom="4dip"
- android:text="@android:string/lockscreen_emergency_call"
- />
- </RelativeLayout>
-
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/select_dialog_singlechoice.xml b/core/res/res/layout/select_dialog_singlechoice.xml
index ec97d7b..3e07f23 100644
--- a/core/res/res/layout/select_dialog_singlechoice.xml
+++ b/core/res/res/layout/select_dialog_singlechoice.xml
@@ -19,7 +19,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
- android:textAppearance="?android:attr/textAppearanceLargeInverse"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textColor="@android:color/bright_foreground_light"
android:gravity="center_vertical"
android:paddingLeft="12dip"
android:paddingRight="7dip"
diff --git a/core/res/res/layout/zoom_container.xml b/core/res/res/layout/zoom_container.xml
index fc5cf3d..52bc635 100644
--- a/core/res/res/layout/zoom_container.xml
+++ b/core/res/res/layout/zoom_container.xml
@@ -19,10 +19,11 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ZoomControls android:id="@+id/zoomControls"
- android:layout_gravity="bottom|center_horizontal"
+ android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/ZoomControls"
+ android:gravity="center_horizontal"
android:background="@null"
/>
</merge>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 3fb7e86..8150067 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -19,7 +19,7 @@
-->
<resources>
<drawable name="screen_background_light">#ffffffff</drawable>
- <drawable name="screen_background_dark">#ff262626</drawable>
+ <drawable name="screen_background_dark">#ff1a1a1a</drawable>
<drawable name="status_bar_closed_default_background">#ff000000</drawable>
<drawable name="status_bar_opened_default_background">#ff000000</drawable>
<drawable name="search_bar_default_color">#ff000000</drawable>
@@ -28,7 +28,7 @@
<color name="white">#ffffffff</color>
<color name="black">#ff000000</color>
<color name="transparent">#00000000</color>
- <color name="background_dark">#ff262626</color>
+ <color name="background_dark">#ff1a1a1a</color>
<color name="bright_foreground_dark">#ffffffff</color>
<color name="bright_foreground_dark_disabled">#80ffffff</color>
<color name="bright_foreground_dark_inverse">#ff000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f370151..83ac8e2 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -25,4 +25,13 @@
manager will disable alpha trasformation in animations where not
strictly needed. -->
<bool name="config_sf_limitedAlpha">false</bool>
+
+ <!-- The duration (in milliseconds) of a short animation. -->
+ <integer name="config_shortAnimTime">100</integer>
+
+ <!-- The duration (in milliseconds) of a medium-length animation. -->
+ <integer name="config_mediumAnimTime">150</integer>
+
+ <!-- The duration (in milliseconds) of a long animation. -->
+ <integer name="config_longAnimTime">300</integer>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0603fa3..88c7b35 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1095,4 +1095,8 @@
<!-- Drawable to use as a background for a taller version of the titlebar -->
<public type="drawable" name="title_bar_tall" id="0x010800b7" />
+
+ <public type="integer" name="config_shortAnimTime" id="0x010e0000" />
+ <public type="integer" name="config_mediumAnimTime" id="0x010e0001" />
+ <public type="integer" name="config_longAnimTime" id="0x010e0002" />
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index ff8f8c2..a152410 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -176,7 +176,7 @@
<item name="android:focusable">true</item>
<item name="android:clickable">true</item>
<item name="android:textAppearance">?android:attr/textAppearanceSmallInverse</item>
- <item name="android:textColor">@android:color/primary_text_light_nodisable</item>
+ <item name="android:textColor">@android:color/primary_text_light</item>
<item name="android:gravity">center_vertical|center_horizontal</item>
</style>
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index eace996..64d3a40 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -42,6 +42,7 @@
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
+ virtual status_t setParameters(const String8& params) = 0;
virtual status_t setListener(const sp<IMediaPlayerClient>& listener) = 0;
virtual status_t prepare() = 0;
virtual status_t getMaxAmplitude(int* max) = 0;
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index 3315c59..0c71932 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -45,6 +45,7 @@
status_t setPreviewSurface(const sp<ISurface>& surface);
status_t setOutputFile(const char *path);
status_t setOutputFile(int fd, int64_t offset, int64_t length);
+ status_t setParameters(const String8& params);
status_t setListener(const sp<IMediaPlayerClient>& listener);
status_t prepare();
status_t start();
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 8991f08..78d7621 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -89,14 +89,24 @@
};
// The "msg" code passed to the listener in notify.
-enum {
- MEDIA_RECORDER_EVENT_ERROR = 1
+enum media_recorder_event_type {
+ MEDIA_RECORDER_EVENT_ERROR = 1,
+ MEDIA_RECORDER_EVENT_INFO = 2
};
-enum {
+enum media_recorder_error_type {
MEDIA_RECORDER_ERROR_UNKNOWN = 1
};
+// The codes are distributed as follow:
+// 0xx: Reserved
+// 8xx: General info/warning
+//
+enum media_recorder_info_type {
+ MEDIA_RECORDER_INFO_UNKNOWN = 1,
+ MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800
+};
+
// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class MediaRecorderListener: virtual public RefBase
@@ -123,6 +133,7 @@
status_t setOutputFile(int fd, int64_t offset, int64_t length);
status_t setVideoSize(int width, int height);
status_t setVideoFrameRate(int frames_per_second);
+ status_t setParameters(const String8& params);
status_t setListener(const sp<MediaRecorderListener>& listener);
status_t prepare();
status_t getMaxAmplitude(int* max);
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 57a53bd..5652b28 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -837,12 +837,12 @@
}
#ifdef WITH_A2DP
-void AudioFlinger::handleStreamDisablesA2dp(int command)
+// handleStreamDisablesA2dp_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::handleStreamDisablesA2dp_l(int command)
{
switch(command) {
case ACTIVE_TRACK_ADDED:
{
- AutoMutex lock(mHardwareLock);
if (mA2dpDisableCount++ == 0) {
if (mA2dpEnabled) {
setA2dpEnabled_l(false);
@@ -854,8 +854,7 @@
break;
case ACTIVE_TRACK_REMOVED:
{
- AutoMutex lock(mHardwareLock);
- if (mA2dpDisableCount > 0){
+ if (mA2dpDisableCount > 0) {
if (--mA2dpDisableCount == 0) {
if (mA2dpSuppressed) {
setA2dpEnabled_l(true);
@@ -1502,8 +1501,10 @@
mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_ADDED);
}
#ifdef WITH_A2DP
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
if (streamDisablesA2dp(track->type())) {
- mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_ADDED);
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
}
#endif
}
@@ -1524,8 +1525,10 @@
mAudioFlinger->handleForcedSpeakerRoute(ACTIVE_TRACK_REMOVED);
}
#ifdef WITH_A2DP
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
if (streamDisablesA2dp(track->type())) {
- mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_REMOVED);
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
}
#endif
}
@@ -2476,8 +2479,15 @@
mRecordTrack = recordTrack;
#ifdef WITH_A2DP
- if (streamDisablesA2dp(recordTrack->type())) {
- mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_ADDED);
+ { // scope for lock2
+
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+ AutoMutex lock2(&mAudioFlinger->mLock);
+
+ // Currently there is no way to detect if we are recording over SCO,
+ // so we disable A2DP during any recording.
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_ADDED);
}
#endif
@@ -2494,8 +2504,15 @@
AutoMutex lock(&mLock);
if (mActive && (recordTrack == mRecordTrack.get())) {
#ifdef WITH_A2DP
- if (streamDisablesA2dp(recordTrack->type())) {
- mAudioFlinger->handleStreamDisablesA2dp(ACTIVE_TRACK_REMOVED);
+ { // scope for lock2
+
+ // AudioFlinger::mLock must be locked before calling
+ // handleStreamDisablesA2dp_l because it calls setA2dpEnabled_l().
+ AutoMutex lock2(&mAudioFlinger->mLock);
+
+ // Currently there is no way to detect if we are recording over SCO,
+ // so we disable A2DP during any recording.
+ mAudioFlinger->handleStreamDisablesA2dp_l(ACTIVE_TRACK_REMOVED);
}
#endif
mActive = false;
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 596e7f3..ab15947f 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -176,7 +176,7 @@
};
void handleForcedSpeakerRoute(int command);
#ifdef WITH_A2DP
- void handleStreamDisablesA2dp(int command);
+ void handleStreamDisablesA2dp_l(int command);
#endif
// Internal dump utilites.
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 4906cbb..1c08cba 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -71,6 +71,7 @@
private FileDescriptor mFd;
private EventHandler mEventHandler;
private OnErrorListener mOnErrorListener;
+ private OnInfoListener mOnInfoListener;
/**
* Default constructor.
@@ -256,6 +257,15 @@
public native void setVideoFrameRate(int rate) throws IllegalStateException;
/**
+ * Sets the maximum duration (in ms) of the recording session.
+ * Call this after setOutFormat() but before prepare().
+ *
+ * @param max_duration_ms the maximum duration in ms (if zero or negative, disables the duration limit)
+ *
+ */
+ public native void setMaxDuration(int max_duration_ms) throws IllegalArgumentException;
+
+ /**
* Sets the audio encoder to be used for recording. If this method is not
* called, the output file will not contain an audio track. Call this after
* setOutputFormat() but before prepare().
@@ -420,6 +430,48 @@
mOnErrorListener = l;
}
+ /* Do not change these values without updating their counterparts
+ * in include/media/mediarecorder.h!
+ */
+ /** Unspecified media recorder error.
+ * @see android.media.MediaRecorder.OnInfoListener
+ */
+ public static final int MEDIA_RECORDER_INFO_UNKNOWN = 1;
+ /** A maximum duration had been setup and has now been reached.
+ * @see android.media.MediaRecorder.OnInfoListener
+ */
+ public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800;
+
+ /**
+ * Interface definition for a callback to be invoked when an error
+ * occurs while recording.
+ */
+ public interface OnInfoListener
+ {
+ /**
+ * Called when an error occurs while recording.
+ *
+ * @param mr the MediaRecorder that encountered the error
+ * @param what the type of error that has occurred:
+ * <ul>
+ * <li>{@link #MEDIA_RECORDER_INFO_UNKNOWN}
+ * </ul>
+ * @param extra an extra code, specific to the error type
+ */
+ void onInfo(MediaRecorder mr, int what, int extra);
+ }
+
+ /**
+ * Register a callback to be invoked when an informational event occurs while
+ * recording.
+ *
+ * @param listener the callback that will be run
+ */
+ public void setOnInfoListener(OnInfoListener listener)
+ {
+ mOnInfoListener = listener;
+ }
+
private class EventHandler extends Handler
{
private MediaRecorder mMediaRecorder;
@@ -429,10 +481,11 @@
mMediaRecorder = mr;
}
- /* Do not change this value without updating its counterpart
+ /* Do not change these values without updating their counterparts
* in include/media/mediarecorder.h!
*/
private static final int MEDIA_RECORDER_EVENT_ERROR = 1;
+ private static final int MEDIA_RECORDER_EVENT_INFO = 2;
@Override
public void handleMessage(Message msg) {
@@ -447,6 +500,12 @@
return;
+ case MEDIA_RECORDER_EVENT_INFO:
+ if (mOnInfoListener != null)
+ mOnInfoListener.onInfo(mMediaRecorder, msg.arg1, msg.arg2);
+
+ return;
+
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 5f6f754..1e508d2 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -256,6 +256,18 @@
}
static void
+android_media_MediaRecorder_setMaxDuration(JNIEnv *env, jobject thiz, jint max_duration_ms)
+{
+ LOGV("setMaxDuration(%d)", max_duration_ms);
+ sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
+
+ char params[64];
+ sprintf(params, "max-duration=%d", max_duration_ms);
+
+ process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxDuration failed.");
+}
+
+static void
android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
{
LOGV("prepare");
@@ -357,6 +369,7 @@
{"_setOutputFile", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaRecorder_setOutputFileFD},
{"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize},
{"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate},
+ {"setMaxDuration", "(I)V", (void *)android_media_MediaRecorder_setMaxDuration},
{"_prepare", "()V", (void *)android_media_MediaRecorder_prepare},
{"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude},
{"start", "()V", (void *)android_media_MediaRecorder_start},
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index f187bf5..84d08c4 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -44,6 +44,7 @@
SET_OUTPUT_FILE_FD,
SET_VIDEO_SIZE,
SET_VIDEO_FRAMERATE,
+ SET_PARAMETERS,
SET_PREVIEW_SURFACE,
SET_CAMERA,
SET_LISTENER
@@ -178,6 +179,16 @@
return reply.readInt32();
}
+ status_t setParameters(const String8& params)
+ {
+ LOGV("setParameter(%s)", params.string());
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeString8(params);
+ remote()->transact(SET_PARAMETERS, data, &reply);
+ return reply.readInt32();
+ }
+
status_t setListener(const sp<IMediaPlayerClient>& listener)
{
LOGV("setListener(%p)", listener.get());
@@ -385,6 +396,12 @@
reply->writeInt32(setVideoFrameRate(frames_per_second));
return NO_ERROR;
} break;
+ case SET_PARAMETERS: {
+ LOGV("SET_PARAMETER");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(setParameters(data.readString8()));
+ return NO_ERROR;
+ } break;
case SET_LISTENER: {
LOGV("SET_LISTENER");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 572b1e7..23b3b9d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -21,6 +21,7 @@
#include <ui/Surface.h>
#include <media/mediarecorder.h>
#include <utils/IServiceManager.h>
+#include <utils/String8.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
@@ -356,6 +357,23 @@
return ret;
}
+status_t MediaRecorder::setParameters(const String8& params) {
+ LOGV("setParameters(%s)", params.string());
+ if(mMediaRecorder == NULL) {
+ LOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->setParameters(params);
+ if (OK != ret) {
+ LOGE("setParameters(%s) failed: %d", params.string(), ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
+ return ret;
+}
+
status_t MediaRecorder::prepare()
{
LOGV("prepare");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 4b45acb..5d1887d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -154,6 +154,16 @@
return mRecorder->setVideoFrameRate(frames_per_second);
}
+status_t MediaRecorderClient::setParameters(const String8& params) {
+ LOGV("setParameters(%s)", params.string());
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ LOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setParameters(params);
+}
+
status_t MediaRecorderClient::prepare()
{
LOGV("prepare");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 93fd802..6a1c2d5 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -39,6 +39,7 @@
virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
+ virtual status_t setParameters(const String8& params);
virtual status_t setListener(const sp<IMediaPlayerClient>& listener);
virtual status_t prepare();
virtual status_t getMaxAmplitude(int* max);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
index 24edb65..05ac408 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaAudioTrackTest.java
@@ -22,7 +22,6 @@
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
-import android.content.Context;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import android.test.suitebuilder.annotation.LargeTest;
@@ -595,12 +594,12 @@
//-------- tear down --------------
track.release();
}
-/*
- //Test case 7: setPlaybackRate() clips values over twice the output sample rate
+
+ //Test case 7: setPlaybackRate() and retrieve value, should be the same for half the content SR
@LargeTest
- public void testSetPlaybackRateClip() throws Exception {
+ public void testSetGetPlaybackRate() throws Exception {
// constants for test
- final String TEST_NAME = "testSetPlaybackRateClip";
+ final String TEST_NAME = "testSetGetPlaybackRate";
final int TEST_SR = 22050;
final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
@@ -612,18 +611,17 @@
AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
minBuffSize, TEST_MODE);
byte data[] = new byte[minBuffSize/2];
- int outputSR = AudioTrack.getNativeOutputSampleRate(TEST_STREAM_TYPE);
//-------- test --------------
track.write(data, 0, data.length);
track.write(data, 0, data.length);
assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
track.play();
- track.setPlaybackRate(3*outputSR);
- assertTrue(TEST_NAME, track.getSampleRate() == 2*outputSR);
+ track.setPlaybackRate((int)(TEST_SR/2));
+ assertTrue(TEST_NAME, track.getPlaybackRate() == (int)(TEST_SR/2));
//-------- tear down --------------
track.release();
}
-*/
+
//Test case 8: setPlaybackRate() invalid operation if track not initialized
@LargeTest
public void testSetPlaybackRateUninit() throws Exception {
@@ -641,7 +639,8 @@
minBuffSize, TEST_MODE);
//-------- test --------------
assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
- assertTrue(TEST_NAME, track.setPlaybackRate(TEST_SR/2) == AudioTrack.ERROR_INVALID_OPERATION);
+ assertTrue(TEST_NAME,
+ track.setPlaybackRate(TEST_SR/2) == AudioTrack.ERROR_INVALID_OPERATION);
//-------- tear down --------------
track.release();
}
@@ -863,8 +862,7 @@
//-------- tear down --------------
track.release();
}
-/*
- //Test case 7: setLoopPoints() fails with start beyond what can be written for the track
+ //Test case 8: setLoopPoints() fails with start beyond what can be written for the track
@LargeTest
public void testSetLoopPointsStartTooFar() throws Exception {
// constants for test
@@ -891,7 +889,327 @@
//-------- tear down --------------
track.release();
}
-*/
+
+ //Test case 9: setLoopPoints() fails with end beyond what can be written for the track
+ @LargeTest
+ public void testSetLoopPointsEndTooFar() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testSetLoopPointsEndTooFar";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STATIC;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ int dataSizeInFrames = minBuffSize/2;//16bit data
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_NO_STATIC_DATA);
+ track.write(data, 0, data.length);
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.setLoopPoints(dataSizeInFrames-10, dataSizeInFrames+50, 2)
+ == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+
+ //-----------------------------------------------------------------
+ // Audio data supply
+ //----------------------------------
+
+ //Test case 1: write() fails when supplying less data (bytes) than declared
+ @LargeTest
+ public void testWriteByteOffsetTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteOffsetTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 10, data.length) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 2: write() fails when supplying less data (shorts) than declared
+ @LargeTest
+ public void testWriteShortOffsetTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortOffsetTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 10, data.length) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 3: write() fails when supplying less data (bytes) than declared
+ @LargeTest
+ public void testWriteByteSizeTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteSizeTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length + 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 4: write() fails when supplying less data (shorts) than declared
+ @LargeTest
+ public void testWriteShortSizeTooBig() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortSizeTooBig";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length + 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 5: write() fails with negative offset
+ @LargeTest
+ public void testWriteByteNegativeOffset() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteNegativeOffset";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, -10, data.length - 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 6: write() fails with negative offset
+ @LargeTest
+ public void testWriteShortNegativeOffset() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortNegativeOffset";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, -10, data.length - 10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 7: write() fails with negative size
+ @LargeTest
+ public void testWriteByteNegativeSize() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByteNegativeSize";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, -10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 8: write() fails with negative size
+ @LargeTest
+ public void testWriteShortNegativeSize() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShortNegativeSize";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, -10) == AudioTrack.ERROR_BAD_VALUE);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 9: write() succeeds and returns the size that was written for 16bit
+ @LargeTest
+ public void testWriteByte() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByte";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 10: write() succeeds and returns the size that was written for 16bit
+ @LargeTest
+ public void testWriteShort() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShort";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 11: write() succeeds and returns the size that was written for 8bit
+ @LargeTest
+ public void testWriteByte8bit() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteByte8bit";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ byte data[] = new byte[minBuffSize];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
+
+ //Test case 12: write() succeeds and returns the size that was written for 8bit
+ @LargeTest
+ public void testWriteShort8bit() throws Exception {
+ // constants for test
+ final String TEST_NAME = "testWriteShort8bit";
+ final int TEST_SR = 22050;
+ final int TEST_CONF = AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ final int TEST_FORMAT = AudioFormat.ENCODING_PCM_8BIT;
+ final int TEST_MODE = AudioTrack.MODE_STREAM;
+ final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
+
+ //-------- initialization --------------
+ int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
+ AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
+ 2*minBuffSize, TEST_MODE);
+ short data[] = new short[minBuffSize/2];
+ //-------- test --------------
+ assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
+ assertTrue(TEST_NAME,
+ track.write(data, 0, data.length) == data.length);
+ //-------- tear down --------------
+ track.release();
+ }
}
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 72d88e2..275ff3a 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -26,7 +26,7 @@
<bool name="def_accelerometer_rotation">true</bool>
<!-- Default screen brightness, from 0 to 255. 102 is 40%. -->
<integer name="def_screen_brightness">102</integer>
- <fraction name="def_window_animation_scale">0%</fraction>
+ <fraction name="def_window_animation_scale">100%</fraction>
<fraction name="def_window_transition_scale">0%</fraction>
<bool name="def_bluetooth_on">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 2f32ab7..d39934b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -334,7 +334,8 @@
if (upgradeVersion == 31) {
/*
- * Animations are now turned off by default.
+ * Animations are now managed in preferences, and may be
+ * enabled or disabled based on product resources.
*/
db.beginTransaction();
try {
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 8814e48..f81c519 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -82,6 +82,8 @@
private boolean mMounted;
+ private boolean mAutoStartUms;
+
/**
* Constructs a new MountService instance
*
@@ -100,6 +102,8 @@
mShowSafeUnmountNotificationWhenUnmounted = false;
mPlaySounds = SystemProperties.get("persist.service.mount.playsnd", "1").equals("1");
+
+ mAutoStartUms = SystemProperties.get("persist.service.mount.umsauto", "0").equals("1");
}
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -198,6 +202,26 @@
}
/**
+ * Returns true if we auto-start UMS on cable insertion.
+ */
+ public boolean getAutoStartUms() {
+ return mAutoStartUms;
+ }
+
+ /**
+ * Set whether or not we're playing media notification sounds.
+ */
+ public void setAutoStartUms(boolean enabled) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires WRITE_SETTINGS permission");
+ }
+ mAutoStartUms = enabled;
+ SystemProperties.set("persist.service.mount.umsauto", (enabled ? "1" : "0"));
+ }
+
+ /**
* Update the state of the USB mass storage notification
*/
void updateUsbMassStorageNotification(boolean suppressIfConnected, boolean sound) {
@@ -239,7 +263,14 @@
!storageState.equals(Environment.MEDIA_BAD_REMOVAL) &&
!storageState.equals(Environment.MEDIA_CHECKING)) {
- updateUsbMassStorageNotification(false, true);
+ if (mAutoStartUms) {
+ try {
+ setMassStorageEnabled(true);
+ } catch (RemoteException e) {
+ }
+ } else {
+ updateUsbMassStorageNotification(false, true);
+ }
}
Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index fec3608..9f428e9 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -5460,6 +5460,12 @@
// has to delete the one installed in the data partition in order to pick up the
// new system package.
return p;
+ } else if ((p.pkg != null) && (p.pkg.applicationInfo != null) &&
+ ((p.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0)) {
+ // Check for non-system apps
+ reportSettingsProblem(Log.WARN,
+ "Package " + name + " codePath changed from " + p.codePath
+ + " to " + codePath + "; Retaining data and using new code");
} else {
reportSettingsProblem(Log.WARN,
"Package " + name + " codePath changed from " + p.codePath
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 5e5fb93..a74915c 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -28,6 +28,7 @@
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.Log;
import java.util.ArrayList;
import java.io.FileDescriptor;
@@ -187,6 +188,9 @@
}
public void notifyCallState(int state, String incomingNumber) {
+ if (!checkPhoneStatePermission("notifyCallState()")) {
+ return;
+ }
synchronized (mRecords) {
mCallState = state;
mCallIncomingNumber = incomingNumber;
@@ -206,6 +210,9 @@
}
public void notifyServiceState(ServiceState state) {
+ if (!checkPhoneStatePermission("notifyServiceState()")) {
+ return;
+ }
synchronized (mRecords) {
mServiceState = state;
final int N = mRecords.size();
@@ -220,6 +227,9 @@
}
public void notifySignalStrength(int signalStrengthASU) {
+ if (!checkPhoneStatePermission("notifySignalStrength()")) {
+ return;
+ }
synchronized (mRecords) {
mSignalStrength = signalStrengthASU;
final int N = mRecords.size();
@@ -238,6 +248,9 @@
}
public void notifyMessageWaitingChanged(boolean mwi) {
+ if (!checkPhoneStatePermission("notifyMessageWaitingChanged()")) {
+ return;
+ }
synchronized (mRecords) {
mMessageWaiting = mwi;
final int N = mRecords.size();
@@ -255,6 +268,9 @@
}
public void notifyCallForwardingChanged(boolean cfi) {
+ if (!checkPhoneStatePermission("notifyCallForwardingChanged()")) {
+ return;
+ }
synchronized (mRecords) {
mCallForwarding = cfi;
final int N = mRecords.size();
@@ -272,6 +288,9 @@
}
public void notifyDataActivity(int state) {
+ if (!checkPhoneStatePermission("notifyDataActivity()")) {
+ return;
+ }
synchronized (mRecords) {
mDataActivity = state;
final int N = mRecords.size();
@@ -290,6 +309,9 @@
public void notifyDataConnection(int state, boolean isDataConnectivityPissible,
String reason, String apn, String interfaceName) {
+ if (!checkPhoneStatePermission("notifyDataConnection()")) {
+ return;
+ }
synchronized (mRecords) {
mDataConnectionState = state;
mDataConnectionPossible = isDataConnectivityPissible;
@@ -313,6 +335,9 @@
}
public void notifyDataConnectionFailed(String reason) {
+ if (!checkPhoneStatePermission("notifyDataConnectionFailed()")) {
+ return;
+ }
/*
* This is commented out because there is on onDataConnectionFailed callback
* on PhoneStateListener. There should be.
@@ -331,6 +356,9 @@
}
public void notifyCellLocation(Bundle cellLocation) {
+ if (!checkPhoneStatePermission("notifyCellLocation()")) {
+ return;
+ }
synchronized (mRecords) {
mCellLocation = cellLocation;
final int N = mRecords.size();
@@ -459,4 +487,16 @@
intent.putExtra(Phone.FAILURE_REASON_KEY, reason);
mContext.sendStickyBroadcast(intent);
}
+
+ private boolean checkPhoneStatePermission(String method) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ String msg = "Modify Phone State Permission Denial: " + method + " from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid();
+ Log.w(TAG, msg);
+ return false;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index adc8bc1..05e61f2 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -140,6 +140,7 @@
static final String REASON_VOICE_CALL_STARTED = "2GVoiceCallStarted";
static final String REASON_PS_RESTRICT_ENABLED = "psRestrictEnabled";
static final String REASON_PS_RESTRICT_DISABLED = "psRestrictDisabled";
+ static final String REASON_SIM_LOADED = "simLoaded";
// Used for band mode selection methods
static final int BM_UNSPECIFIED = 0; // selected by baseband automatically
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
index 66fa943..2b70162 100644
--- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -16,11 +16,12 @@
package com.android.internal.telephony;
+import android.content.Context;
import android.content.Intent;
+import android.os.PowerManager;
import android.provider.Telephony.Sms.Intents;
import android.util.Config;
import android.util.Log;
-import com.android.internal.telephony.gsm.GSMPhone;
import com.android.internal.telephony.gsm.SimUtils;
@@ -32,12 +33,19 @@
public class WapPushOverSms {
private static final String LOG_TAG = "WAP PUSH";
- private final GSMPhone mPhone;
+ private final Context mContext;
private WspTypeDecoder pduDecoder;
+ private PowerManager.WakeLock mWakeLock;
+ /**
+ * Hold the wake lock for 5 seconds, which should be enough time for
+ * any receiver(s) to grab its own wake lock.
+ */
+ private final int WAKE_LOCK_TIMEOUT = 5000;
- public WapPushOverSms(GSMPhone phone) {
- mPhone = phone;
+ public WapPushOverSms(Phone phone) {
+ mContext = phone.getContext();
+ createWakelock();
}
/**
@@ -163,8 +171,6 @@
}
}
-
-
private void dispatchWapPdu_default(
byte[] pdu, int transactionId, int pduType, String mimeType, int dataIndex) {
byte[] data;
@@ -178,8 +184,7 @@
intent.putExtra("pduType", pduType);
intent.putExtra("data", data);
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_WAP_PUSH");
+ sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
}
private void dispatchWapPdu_PushCO(byte[] pdu, int transactionId, int pduType) {
@@ -189,8 +194,7 @@
intent.putExtra("pduType", pduType);
intent.putExtra("data", pdu);
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_WAP_PUSH");
+ sendBroadcast(intent, "android.permission.RECEIVE_WAP_PUSH");
}
private void dispatchWapPdu_MMS(byte[] pdu, int transactionId, int pduType, int dataIndex) {
@@ -205,7 +209,19 @@
intent.putExtra("pduType", pduType);
intent.putExtra("data", data);
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_MMS");
+ sendBroadcast(intent, "android.permission.RECEIVE_MMS");
+ }
+
+ private void createWakelock() {
+ PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WapPushOverSms");
+ mWakeLock.setReferenceCounted(true);
+ }
+
+ private void sendBroadcast(Intent intent, String permission) {
+ // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
+ // receivers time to take their own wake locks.
+ mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
+ mContext.sendBroadcast(intent, permission);
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
index e664bc7..30b1be8 100644
--- a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
@@ -199,9 +199,9 @@
private static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
/** Default ping deadline, in seconds. */
- private final int DEFAULT_PING_DEADLINE = 5;
+ private static final int DEFAULT_PING_DEADLINE = 5;
/** Default max failure count before attempting to network re-registration. */
- private final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
+ private static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
/**
* After detecting a potential connection problem, this is the max number
@@ -677,8 +677,7 @@
if ((state == State.IDLE || state == State.SCANNING)
&& (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
&& phone.mSIMRecords.getRecordsLoaded()
- && ( phone.mSST.isConcurrentVoiceAndData() ||
- phone.getState() == Phone.State.IDLE )
+ && phone.getState() == Phone.State.IDLE
&& isDataAllowed()
&& !mIsPsRestricted ) {
@@ -1351,7 +1350,7 @@
if (state == State.FAILED) {
cleanUpConnection(false, null);
}
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+ sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
break;
case EVENT_ENABLE_NEW_APN:
@@ -1362,6 +1361,10 @@
break;
case EVENT_TRY_SETUP_DATA:
+ if (msg.obj instanceof String) {
+ reason = (String)msg.obj;
+ }
+
trySetupData(reason);
break;
@@ -1500,7 +1503,10 @@
} else {
// we still have more apns to try
setState(State.SCANNING);
- trySetupData(reason);
+ // Wait a bit before trying the next APN, so that
+ // we're not tying up the RIL command channel
+ sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
+ RECONNECT_DELAY_INITIAL_MILLIS);
}
} else {
startDelayedRetry(cause, reason);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
index 877b734..5585524 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
@@ -32,6 +32,7 @@
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.os.PowerManager;
import android.provider.Telephony;
import android.provider.Settings;
import android.provider.Telephony.Sms.Intents;
@@ -122,6 +123,15 @@
private SmsTracker mSTracker;
+ /** Wake lock to ensure device stays awake while dispatching the SMS intent. */
+ private PowerManager.WakeLock mWakeLock;
+
+ /**
+ * Hold the wake lock for 5 seconds, which should be enough time for
+ * any receiver(s) to grab its own wake lock.
+ */
+ private final int WAKE_LOCK_TIMEOUT = 5000;
+
/**
* Implement the per-application based SMS control, which only allows
* a limit on the number of SMS/MMS messages an app can send in checking
@@ -186,6 +196,8 @@
mCm = phone.mCM;
mSTracker = null;
+ createWakelock();
+
int check_period = Settings.Gservices.getInt(mResolver,
Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS,
DEFAULT_SMS_CHECK_PERIOD);
@@ -286,6 +298,19 @@
}
}
+ private void createWakelock() {
+ PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher");
+ mWakeLock.setReferenceCounted(true);
+ }
+
+ private void sendBroadcast(Intent intent, String permission) {
+ // Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
+ // receivers time to take their own wake locks.
+ mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
+ mContext.sendBroadcast(intent, permission);
+ }
+
/**
* Called when SIM_FULL message is received from the RIL. Notifies interested
* parties that SIM storage for SMS messages is full.
@@ -293,7 +318,7 @@
private void handleSimFull() {
// broadcast SIM_FULL intent
Intent intent = new Intent(Intents.SIM_FULL_ACTION);
- mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS");
+ sendBroadcast(intent, "android.permission.RECEIVE_SMS");
}
/**
@@ -633,8 +658,7 @@
private void dispatchPdus(byte[][] pdus) {
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
intent.putExtra("pdus", pdus);
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_SMS");
+ sendBroadcast(intent, "android.permission.RECEIVE_SMS");
}
/**
@@ -647,8 +671,7 @@
Uri uri = Uri.parse("sms://localhost:" + port);
Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);
intent.putExtra("pdus", pdus);
- mPhone.getContext().sendBroadcast(
- intent, "android.permission.RECEIVE_SMS");
+ sendBroadcast(intent, "android.permission.RECEIVE_SMS");
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
index 7152f76..89ce506 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
@@ -1511,7 +1511,7 @@
+ (c.getTimeInMillis() - System.currentTimeMillis())
+ " from " + nitz);
- SystemClock.setCurrentTimeMillis(c.getTimeInMillis());
+ setAndBroadcastNetworkSetTime(c.getTimeInMillis());
Log.i(LOG_TAG, "NITZ: after Setting time of day");
}
SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
diff --git a/tests/CoreTests/android/webkit/CookieTest.java b/tests/CoreTests/android/webkit/CookieTest.java
index 1c3d671..ea4422f 100644
--- a/tests/CoreTests/android/webkit/CookieTest.java
+++ b/tests/CoreTests/android/webkit/CookieTest.java
@@ -55,6 +55,11 @@
mCookieManager.setCookie(url, "c=\"d;\"");
cookie = mCookieManager.getCookie(url);
assertTrue(cookie.equals("a=b; c=\"d;\""));
+
+ // empty
+ mCookieManager.setCookie(url, "; path=/");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=b; c=\"d;\""));
}
public void testDomain() {
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
index 8e06cc8..17c44ad 100644
--- a/tests/DumpRenderTree/AndroidManifest.xml
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -23,7 +23,7 @@
<category android:name="android.intent.category.TEST" />
</intent-filter>
</activity>
- <activity android:name="HTMLHostActivity">
+ <activity android:name="TestShellActivity" android:launchMode="singleTop">
</activity>
</application>
diff --git a/tests/DumpRenderTree/compare_layout_results.py b/tests/DumpRenderTree/compare_layout_results.py
deleted file mode 100644
index c4285f1..0000000
--- a/tests/DumpRenderTree/compare_layout_results.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/python
-"""
-Compares results of two webkit layout test runs and writes
-results to a file.
-"""
-
-import optparse
-import os
-import sys
-
-def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
- """ Given two result files, generate diff and
- write to diff_results file. All arguments are absolute paths
- to files.
- """
- old_file = open(old_results, "r")
- new_file = open(new_results, "r")
- diff_file = open(diff_results, "a")
-
- # Read lines from each file
- ndict = new_file.readlines()
- cdict = old_file.readlines()
-
- # Write marker to diff file
- diff_file.writelines(marker + "\n")
- diff_file.writelines("###############\n")
-
- # Strip reason from result lines
- if strip_reason is True:
- for i in range(0, len(ndict)):
- ndict[i] = ndict[i].split(' ')[0] + "\n"
- for i in range(0, len(cdict)):
- cdict[i] = cdict[i].split(' ')[0] + "\n"
-
- # Find results in new_results missing in old_results
- new_count=0
- for line in ndict:
- if line not in cdict:
- diff_file.writelines("+ " + line)
- new_count += 1
-
- # Find results in old_results missing in new_results
- missing_count=0
- for line in cdict:
- if line not in ndict:
- diff_file.writelines("- " + line)
- missing_count += 1
-
- print marker + " >>> added " + str(new_count) + " tests, removed " + str(missing_count) + " tests"
-
- diff_file.writelines("\n\n")
-
- old_file.close()
- new_file.close()
- diff_file.close()
- return
-
-def main(options, args):
- results_dir = os.path.abspath(options.results_directory)
- ref_dir = options.ref_directory
-
- # if ref_dir is null, cannonify ref_dir to the script dir.
- if not ref_dir:
- script_self = sys.argv[0]
- script_dir = os.path.dirname(script_self)
- ref_dir = os.path.join(script_dir, "results")
-
- ref_dir = os.path.abspath(ref_dir)
-
- diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
- if os.path.exists(diff_result):
- os.remove(diff_result)
-
- files=["passed", "failed", "nontext", "crashed"]
- for f in files:
- result_file_name = "layout_tests_" + f + ".txt"
- DiffResults(f, os.path.join(results_dir, result_file_name),
- os.path.join(ref_dir, result_file_name), diff_result,
- f == "failed")
-
-if '__main__' == __name__:
- option_parser = optparse.OptionParser()
- option_parser.add_option("", "--ref-directory",
- default=None,
- dest="ref_directory",
- help="directory name under which results are stored.")
-
- option_parser.add_option("", "--results-directory",
- default="layout-test-results/",
- dest="results_directory",
- help="directory name under which results are stored.")
- options, args = option_parser.parse_args()
- main(options, args)
diff --git a/tests/DumpRenderTree/run_layout_tests.py b/tests/DumpRenderTree/run_layout_tests.py
index 433271e..5409a0c 100755
--- a/tests/DumpRenderTree/run_layout_tests.py
+++ b/tests/DumpRenderTree/run_layout_tests.py
@@ -22,6 +22,7 @@
use --refresh-test-list option *once* to re-generate test list on the card.
Some other options are:
+ --rebaseline generates expected layout tests results under /sdcard/android/expected_result/
--time-out-ms (default is 8000 millis) for each test
--adb-options="-e" passes option string to adb
--results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
@@ -55,8 +56,8 @@
output: adb_cmd string
"""
- # pull /sdcard/running_test.txt, if the content is "#DONE", it's done
- shell_cmd_str = adb_cmd + " shell cat /sdcard/running_test.txt"
+ # pull /sdcard/android/running_test.txt, if the content is "#DONE", it's done
+ shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
return adb_output.strip() == "#DONE"
@@ -145,7 +146,7 @@
# Include all tests if none are specified.
if not args:
- path = 'fast';
+ path = '/';
else:
path = ' '.join(args);
@@ -156,8 +157,8 @@
# Re-generate the test list if --refresh-test-list is on
if options.refresh_test_list:
logging.info("Generating test list.");
- shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#generateTestList -e path fast -w com.android.dumprendertree/.LayoutTestsAutoRunner"
- adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ generate_test_list_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#generateTestList -e path \"" + path + "\" -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+ adb_output = subprocess.Popen(generate_test_list_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
if adb_output.find('Process crashed') != -1:
logging.info("Aborting because cannot generate test list.\n" + adb_output)
@@ -169,20 +170,28 @@
# Count crashed tests.
crashed_tests = []
- timeout_ms = '8000'
+ timeout_ms = '5000'
if options.time_out_ms:
timeout_ms = options.time_out_ms
# Run test until it's done
+ run_layout_test_cmd_prefix = adb_cmd + " shell am instrument"
+
+ run_layout_test_cmd_postfix = " -e path \"" + path + "\" -e timeout " + timeout_ms
+ if options.rebaseline:
+ run_layout_test_cmd_postfix += " -e rebaseline true"
+ run_layout_test_cmd_postfix += " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+
# Call LayoutTestsAutoTest::startLayoutTests.
- shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#startLayoutTests -e path \"" + path + "\" -e timeout " + timeout_ms + " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
- adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ run_layout_test_cmd = run_layout_test_cmd_prefix + " -e class com.android.dumprendertree.LayoutTestsAutoTest#startLayoutTests" + run_layout_test_cmd_postfix
+
+ adb_output = subprocess.Popen(run_layout_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
while not DumpRenderTreeFinished(adb_cmd):
# Get the running_test.txt
logging.error("DumpRenderTree crashed, output:\n" + adb_output)
- shell_cmd_str = adb_cmd + " shell cat /sdcard/running_test.txt"
+ shell_cmd_str = adb_cmd + " shell cat /sdcard/android/running_test.txt"
crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
logging.info(crashed_test + " CRASHED");
@@ -190,9 +199,9 @@
logging.info("Resuming layout test runner...");
# Call LayoutTestsAutoTest::resumeLayoutTests
- shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#resumeLayoutTests -e path \"" + path + "\" -e timeout " + timeout_ms + " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+ run_layout_test_cmd = run_layout_test_cmd_prefix + " -e class com.android.dumprendertree.LayoutTestsAutoTest#resumeLayoutTests" + run_layout_test_cmd_postfix
- adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ adb_output = subprocess.Popen(run_layout_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
if adb_output.find('INSTRUMENTATION_FAILED') != -1:
logging.error("Error happened : " + adb_output)
@@ -219,7 +228,7 @@
# Create the crash list.
fp = open(results_dir + "/layout_tests_crashed.txt", "w");
- fp.writelines(crashed_tests)
+ fp.writelines('\n'.join(crashed_tests))
fp.close()
# Count the number of tests in each category.
@@ -250,6 +259,9 @@
if '__main__' == __name__:
option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--rebaseline", action="store_true",
+ default=False,
+ help="generate expected results for those tests not having one")
option_parser.add_option("", "--time-out-ms",
default=None,
help="set the timeout for each test")
diff --git a/tests/DumpRenderTree/run_page_cycler.py b/tests/DumpRenderTree/run_page_cycler.py
new file mode 100755
index 0000000..9a099b5
--- /dev/null
+++ b/tests/DumpRenderTree/run_page_cycler.py
@@ -0,0 +1,101 @@
+#!/usr/bin/python
+
+"""Run page cycler tests using Android instrumentation.
+
+ First, you need to get an SD card or sdcard image that has page cycler tests.
+
+ Usage:
+ Run a single page cycler test:
+ run_page_cycler.py "file:///sdcard/android/page_cycler/moz/start.html?auto=1\&iterations=10"
+"""
+
+import logging
+import optparse
+import os
+import subprocess
+import sys
+import time
+
+
+
+def main(options, args):
+ """Run the tests. Will call sys.exit when complete.
+
+ """
+
+ # Set up logging format.
+ log_level = logging.INFO
+ if options.verbose:
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level,
+ format='%(message)s')
+
+ # Include all tests if none are specified.
+ if not args:
+ print "need a URL, e.g. file:///sdcard/android/page_cycler/moz/start.html"
+ sys.exit(1)
+ else:
+ path = ' '.join(args);
+
+ adb_cmd = "adb ";
+ if options.adb_options:
+ adb_cmd += options.adb_options
+
+ logging.info("Running the test ...")
+
+ # Count crashed tests.
+ crashed_tests = []
+
+ timeout_ms = '0'
+ if options.time_out_ms:
+ timeout_ms = options.time_out_ms
+
+ # Run test until it's done
+
+ run_load_test_cmd_prefix = adb_cmd + " shell am instrument"
+ run_load_test_cmd_postfix = " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+
+ # Call LoadTestsAutoTest::runTest.
+ run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix
+
+ (adb_output, adb_error) = subprocess.Popen(run_load_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ if adb_output.find('INSTRUMENTATION_FAILED') != -1:
+ logging.error("Error happened : " + adb_output)
+ sys.exit(1)
+
+ logging.info(adb_output);
+ logging.info(adb_error);
+ logging.info("Done\n");
+
+ # Pull results from /sdcard/load_test_result.txt
+ results_dir = options.results_directory
+ if not os.path.exists(results_dir):
+ os.makedirs(results_dir)
+ if not os.path.isdir(results_dir):
+ logging.error("Cannot create results dir: " + results_dir)
+ sys.exit(1)
+
+ result_file = "/sdcard/load_test_result.txt"
+ shell_cmd_str = adb_cmd + " pull " + result_file + " " + results_dir
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ logging.info(adb_output)
+
+ logging.info("Results are stored under: " + results_dir + "/load_test_result.txt\n")
+
+if '__main__' == __name__:
+ option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--time-out-ms",
+ default=None,
+ help="set the timeout for each test")
+ option_parser.add_option("", "--verbose", action="store_true",
+ default=False,
+ help="include debug-level logging")
+ option_parser.add_option("", "--adb-options",
+ default=None,
+ help="pass options to adb, such as -d -e, etc");
+ option_parser.add_option("", "--results-directory",
+ default="layout-test-results",
+ help="directory which results are stored.")
+
+ options, args = option_parser.parse_args();
+ main(options, args)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 9be33db..4f162b3 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -75,31 +75,14 @@
".", // ignore hidden directories and files
"resources", // ignore resource directories
"AppleScript", // AppleScript not supported
- "xpath", // xpath requires libxml2, not supported
- "xsl", //xsl requires libxml2 & libxslt, not sup.
- "kde", // don't run kde tests.
".svn", // don't run anything under .svn folder
- "gradients", // known crash
- "profiler" // profiler is not supported
+ "profiler", // profiler is not supported
+ "svg", // svg is not supported
+ "platform", // platform specific
+ "http" // requires local http(s) server
};
static final String [] ignoreTestList = {
- "toString-stack-overflow.html", // Crashes #606688
- "frame-limit.html", // generates too many GREFs
- "css-insert-import-rule.html", // Crashes, #717414
- "input-text-enter.html", // Crashes. #735088
- "text-shadow-extreme-value.html", // Crashes #571671
- "reflection-masks.html",
- "frame-creation-removal.html",
- "large-expressions.html",
- "null-page-show-modal-dialog-crash.html",
- "font-face-implicit-local-font.html",
- "font-face-locally-installed.html",
- "beforeSelectorOnCodeElement.html",
- "cssTarget-crash.html",
- "searchfield-heights.html", // Bug 1570692
- "tabindex-focus-blur-all.html",
- "search-rtl.html" // fast/forms/search-rtl.html
};
static void fillIgnoreResultSet() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
index d685f5d..0218317 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
@@ -17,6 +17,7 @@
package com.android.dumprendertree;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -84,7 +85,8 @@
return myData;
}
String[] files = f.list();
-
+ Arrays.sort(files);
+
for (int i = 0; i < files.length; i++) {
StringBuilder sb = new StringBuilder(mPath);
sb.append(File.separatorChar);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
deleted file mode 100644
index 86bfad7..0000000
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
+++ /dev/null
@@ -1,726 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.dumprendertree;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.BufferedOutputStream;
-import java.io.FileInputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.List;
-import java.util.Vector;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.ViewGroup;
-import android.webkit.JsPromptResult;
-import android.webkit.JsResult;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.widget.LinearLayout;
-import android.os.*;
-
-// TestRecorder creates two files, one for passing tests
-// and another for failing tests and writes the paths to
-// layout tests one line at a time. TestRecorder does not
-// have ability to clear the results.
-class TestRecorder {
- public void passed(String layout_file) {
- try {
- mBufferedOutputPassedStream.write(layout_file.getBytes());
- mBufferedOutputPassedStream.write('\n');
- mBufferedOutputPassedStream.flush();
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
-
- public void failed(String layout_file, String reason) {
- try {
- mBufferedOutputFailedStream.write(layout_file.getBytes());
- mBufferedOutputFailedStream.write(" : ".getBytes());
- mBufferedOutputFailedStream.write(reason.getBytes());
- mBufferedOutputFailedStream.write('\n');
- mBufferedOutputFailedStream.flush();
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
-
- public void nontext(String layout_file, boolean has_results) {
- try {
- mBufferedOutputNontextStream.write(layout_file.getBytes());
- if (has_results) {
- mBufferedOutputNontextStream.write(" : has expected results".getBytes());
- }
- mBufferedOutputNontextStream.write('\n');
- mBufferedOutputNontextStream.flush();
- } catch(Exception e) {
- e.printStackTrace();
- }
- }
-
- public TestRecorder(boolean resume) {
- try {
- File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
- File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
- File resultsNontextFile = new File("/sdcard/layout_tests_nontext.txt");
-
- mBufferedOutputPassedStream =
- new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
- mBufferedOutputFailedStream =
- new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume));
- mBufferedOutputNontextStream =
- new BufferedOutputStream(new FileOutputStream(resultsNontextFile, resume));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public void close() {
- try {
- mBufferedOutputPassedStream.close();
- mBufferedOutputFailedStream.close();
- mBufferedOutputNontextStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private BufferedOutputStream mBufferedOutputPassedStream;
- private BufferedOutputStream mBufferedOutputFailedStream;
- private BufferedOutputStream mBufferedOutputNontextStream;
-}
-
-public class HTMLHostActivity extends Activity
- implements LayoutTestController {
-
- public class AsyncHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == MSG_TIMEOUT) {
- mTimedOut = true;
- requestWebKitData();
- return;
- } else if (msg.what == MSG_WEBKIT_DATA) {
- HTMLHostActivity.this.dump(mTimedOut, (String)msg.obj);
- return;
- }
-
- super.handleMessage(msg);
- }
- }
-
- public void requestWebKitData() {
- Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
-
- if (mRequestedWebKitData)
- throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
-
- mRequestedWebKitData = true;
- if (mDumpAsText) {
- mWebView.documentAsText(callback);
- } else {
- mWebView.externalRepresentation(callback);
- }
- }
- // Activity methods
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- LinearLayout contentView = new LinearLayout(this);
- contentView.setOrientation(LinearLayout.VERTICAL);
- setContentView(contentView);
-
- mWebView = new WebView(this);
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.setWebChromeClient(mChromeClient);
- mEventSender = new WebViewEventSender(mWebView);
- mCallbackProxy = new CallbackProxy(mEventSender, this);
- mFinishedRunning = false;
-
- mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
- mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
- contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
-
- mHandler = new AsyncHandler();
- }
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState) {
- super.onRestoreInstanceState(savedInstanceState);
- }
-
- private void getTestList() {
- // Read test list.
- try {
- BufferedReader inReader = new BufferedReader(new FileReader(LAYOUT_TESTS_LIST_FILE));
- String line = inReader.readLine();
- while (line != null) {
- if (line.startsWith(mTestPathPrefix))
- mTestList.add(line);
- line = inReader.readLine();
- }
- inReader.close();
- Log.v(LOGTAG, "Test list has " + mTestList.size() + " test(s).");
- } catch (Exception e) {
- Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
- }
- }
-
- private void resumeTestList() {
- // read out the test name it stoped last time.
- try {
- BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE));
- String line = inReader.readLine();
- for (int i = 0; i < mTestList.size(); i++) {
- if (mTestList.elementAt(i).equals(line)) {
- mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size()));
- break;
- }
- }
- inReader.close();
- } catch (Exception e) {
- Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
- }
- }
-
- private void clearTestStatus() {
- // Delete TEST_STATUS_FILE
- try {
- File f = new File(TEST_STATUS_FILE);
- if (f.delete())
- Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
- else
- Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
- } catch (Exception e) {
- Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
- }
- }
-
- private void updateTestStatus(String s) {
- // Write TEST_STATUS_FILE
- try {
- BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE));
- bos.write(s.getBytes());
- bos.close();
- } catch (Exception e) {
- Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE);
- }
- }
-
- protected void onResume() {
- super.onResume();
- if (mTestList == null)
- mTestList = new Vector<String>();
-
- if (mTestList.isEmpty()) {
- // Read settings
- Intent intent = getIntent();
- mTestPathPrefix = intent.getStringExtra(TEST_PATH_PREFIX);
- mSingleTestMode = intent.getBooleanExtra(SINGLE_TEST_MODE, false);
- boolean resume = intent.getBooleanExtra(RESUME_FROM_CRASH, false);
- mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 8000);
-
- mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
-
- if (mTestPathPrefix == null)
- throw new AssertionError("mTestPathPrefix cannot be null");
-
- Log.v(LOGTAG, "Run tests with prefix: " + mTestPathPrefix);
-
- mResultRecorder = new TestRecorder(resume);
-
- if (!resume)
- clearTestStatus();
-
- if (!mSingleTestMode) {
- getTestList();
- if (resume)
- resumeTestList();
- } else {
- mTestList.add(mTestPathPrefix);
- }
-
- if (!mTestList.isEmpty())
- runTestAtIndex(0);
- else
- mWebView.loadUrl("about:");
- }
- }
-
- protected void onStop() {
- super.onStop();
- mWebView.stopLoading();
- }
-
- protected void onDestroy() {
- super.onDestroy();
- mResultRecorder.close();
- mWebView.destroy();
- mWebView = null;
- }
-
- public void onLowMemory() {
- super.onLowMemory();
- // Simulate a crash
- Log.e(LOGTAG, "Low memory, killing self");
- System.exit(1);
- }
-
- public boolean dispatchKeyEvent(KeyEvent event) {
- // Log key strokes as they don't seem to be matched
- //Log.e(LOGTAG, "Event: "+event);
- return super.dispatchKeyEvent(event);
- }
-
- // Run a test at specified index in the test list.
- // Stops activity if run out of tests.
- protected void runTestAtIndex(int testIndex) {
- mTestIndex = testIndex;
-
- resetTestStatus();
-
- if (testIndex == mTestList.size()) {
- if (!mSingleTestMode) {
- updateTestStatus("#DONE");
- }
- finished();
- return;
- }
- String s = mTestList.elementAt(testIndex);
- if (!mSingleTestMode)
- updateTestStatus(s);
-
- Log.v(LOGTAG, " Running test: "+s);
- mWebView.loadUrl("file://"+s);
-
- if (!mSingleTestMode) {
- // Create a timeout timer
- Message m = mHandler.obtainMessage(MSG_TIMEOUT);
- mHandler.sendMessageDelayed(m, mTimeoutInMillis);
- }
- }
-
- // Dump the page
- public void dump(boolean timeout, String webkitData) {
- String currentTest = mTestList.elementAt(mTestIndex);
- String resultFile = currentTest.substring(0, currentTest.lastIndexOf('.'));
-
- // dumpAsText version can be directly compared to expected results
- if (mDumpAsText) {
- resultFile += "-results.txt";
- } else {
- resultFile += "-android-results.txt";
- }
-
- try {
- FileOutputStream os = new FileOutputStream(resultFile);
- if (timeout) {
- Log.w("Layout test: Timeout", resultFile);
- os.write(TIMEOUT_STR.getBytes());
- os.write('\n');
- }
- if (mDumpTitleChanges)
- os.write(mTitleChanges.toString().getBytes());
- if (mDialogStrings != null)
- os.write(mDialogStrings.toString().getBytes());
- mDialogStrings = null;
- os.write(webkitData.getBytes());
- os.flush();
- os.close();
- } catch (FileNotFoundException ex) {
- ex.printStackTrace();
- } catch (IOException ex) {
- ex.printStackTrace();
- }
-
- processResult(timeout, currentTest);
- runTestAtIndex(mTestIndex + 1);
- }
-
- // Wrap up
- public void failedCase(String file, String reason) {
- Log.w("Layout test: ", file + " failed " + reason);
- mResultRecorder.failed(file, reason);
-
- String bugNumber = FileFilter.isKnownBug(file);
- if (bugNumber != null) {
- System.out.println("FAIL known:"+bugNumber+ " "+file+reason);
- return;
- }
- if (FileFilter.ignoreResults(file)) {
- return;
- }
- System.out.println("FAIL: "+file+reason);
- }
-
- public void passedCase(String file) {
- Log.v("Layout test:", file + " passed");
- mResultRecorder.passed(file);
-
- String bugNumber = FileFilter.isKnownBug(file);
- if (bugNumber != null) {
- System.out.println("Bug Fixed: "+bugNumber+ " "+file);
- return;
- }
-
- if (FileFilter.ignoreResults(file)) {
- System.out.println("Ignored test passed: "+file);
- return;
- }
- }
-
- public void nontextCase(String file, boolean has_expected_results) {
- Log.v("Layout test:", file + " nontext");
- mResultRecorder.nontext(file, has_expected_results);
- }
-
- public void setCallback(HTMLHostCallbackInterface callback) {
- mCallback = callback;
- }
-
- public void processResult(boolean timeout, String test_path) {
- Log.v(LOGTAG, " Processing result: " + test_path);
- // remove the extension
- String short_file = test_path.substring(0, test_path.lastIndexOf('.'));
- if (timeout) {
- failedCase(test_path, "TIMEDOUT");
- return;
- }
- // Only check results that we can check, ie dumpAsText results
- String dumpFile = short_file + "-results.txt";
- File f = new File(dumpFile);
- if (f.exists()) {
- try {
- FileInputStream fr = new FileInputStream(short_file+"-results.txt");
- FileInputStream fe = new FileInputStream(short_file+"-expected.txt");
-
- // If the length is different then they are different
- int diff = fe.available() - fr.available();
- if (diff > 1 || diff < 0) {
- failedCase(test_path, " different length");
- fr.close();
- fe.close();
- return;
- }
- byte[] br = new byte[fr.available()];
- byte[] be = new byte[fe.available()];
- fr.read(br);
- fe.read(be);
- boolean fail = false;
- for (int i = 0; i < br.length; i++) {
- if (br[i] != be[i]) {
- failedCase(test_path, " @offset: "+i);
- fr.close();
- fe.close();
- return;
- }
- }
- if (br.length != be.length && be[be.length-1] == '\n') {
- Log.d(LOGTAG, "Extra new line being ignore:" + test_path);
- }
- fr.close();
- fe.close();
- passedCase(test_path);
- } catch (FileNotFoundException ex) {
- // TODO do something here
- } catch (IOException ex) {
- // Failed on available() or read()
- }
-
- return;
- }
-
- File nontext_result = new File(short_file + "-android-results.txt");
- if (nontext_result.exists()) {
- // Check if the test has expected results.
- File expected = new File(short_file + "-expected.txt");
- nontextCase(test_path, expected.exists());
- }
- }
-
- public void finished() {
- if (mCallback != null) {
- mCallback.waitForFinish();
- }
-
- mFinishedRunning = true;
- finish();
- }
-
- // LayoutTestController Functions
- public void dumpAsText() {
- mDumpAsText = true;
- if (mWebView != null) {
- String url = mWebView.getUrl();
- Log.v(LOGTAG, "dumpAsText called: "+url);
- }
- }
-
- public void waitUntilDone() {
- mWaitUntilDone = true;
- String url = mWebView.getUrl();
- Log.v(LOGTAG, "waitUntilDone called: " + url);
- }
- public void notifyDone() {
- String url = mWebView.getUrl();
- Log.v(LOGTAG, "notifyDone called: " + url);
- if (mWaitUntilDone) {
- mWaitUntilDone = false;
- mChromeClient.onProgressChanged(mWebView, 100);
- }
- }
-
- public void display() {
- mWebView.invalidate();
- }
-
- public void clearBackForwardList() {
- mWebView.clearHistory();
-
- }
-
- public void dumpBackForwardList() {
- //printf("\n============== Back Forward List ==============\n");
- // mWebHistory
- //printf("===============================================\n");
-
- }
-
- public void dumpChildFrameScrollPositions() {
- // TODO Auto-generated method stub
-
- }
-
- public void dumpEditingCallbacks() {
- // TODO Auto-generated method stub
-
- }
-
- public void dumpSelectionRect() {
- // TODO Auto-generated method stub
-
- }
-
- public void dumpTitleChanges() {
- if (!mDumpTitleChanges) {
- mTitleChanges = new StringBuffer();
- }
- mDumpTitleChanges = true;
- }
-
- public void keepWebHistory() {
- if (!mKeepWebHistory) {
- mWebHistory = new Vector();
- }
- mKeepWebHistory = true;
- }
-
- public void queueBackNavigation(int howfar) {
- // TODO Auto-generated method stub
-
- }
-
- public void queueForwardNavigation(int howfar) {
- // TODO Auto-generated method stub
-
- }
-
- public void queueLoad(String Url, String frameTarget) {
- // TODO Auto-generated method stub
-
- }
-
- public void queueReload() {
- mWebView.reload();
- }
-
- public void queueScript(String scriptToRunInCurrentContext) {
- mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
- }
-
- public void repaintSweepHorizontally() {
- // TODO Auto-generated method stub
-
- }
-
- public void setAcceptsEditing(boolean b) {
- // TODO Auto-generated method stub
-
- }
-
- public void setMainFrameIsFirstResponder(boolean b) {
- // TODO Auto-generated method stub
-
- }
-
- public void setWindowIsKey(boolean b) {
- // This is meant to show/hide the window. The best I can find
- // is setEnabled()
- mWebView.setEnabled(b);
- }
-
- public void testRepaint() {
- mWebView.invalidate();
- }
-
- // Instrumentation calls this to find
- // if the activity has finished running the layout tests
- // TODO(fqian): need to sync on mFinisheRunning
- public boolean hasFinishedRunning() {
- return mFinishedRunning;
- }
-
- private final WebChromeClient mChromeClient = new WebChromeClient() {
- @Override
- public void onProgressChanged(WebView view, int newProgress) {
- if (newProgress == 100) {
- if (!mSingleTestMode && !mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
- String url = mWebView.getUrl();
- Log.v(LOGTAG, "Finished: "+ url);
- mHandler.removeMessages(MSG_TIMEOUT);
- requestWebKitData();
- } else {
- String url = mWebView.getUrl();
- if (mSingleTestMode) {
- Log.v(LOGTAG, "Single test mode: " + url);
- } else if (mTimedOut) {
- Log.v(LOGTAG, "Timed out before finishing: " + url);
- } else if (mWaitUntilDone) {
- Log.v(LOGTAG, "Waiting for notifyDone: " + url);
- } else if (mRequestedWebKitData) {
- Log.v(LOGTAG, "Requested webkit data ready: " + url);
- }
- }
- }
- }
-
- @Override
- public void onReceivedTitle(WebView view, String title) {
- if (title.length() > 30)
- title = "..."+title.substring(title.length()-30);
- setTitle(title);
- if (mDumpTitleChanges) {
- mTitleChanges.append("TITLE CHANGED: ");
- mTitleChanges.append(title);
- mTitleChanges.append("\n");
- }
- }
-
- @Override
- public boolean onJsAlert(WebView view, String url, String message,
- JsResult result) {
- if (mDialogStrings == null) {
- mDialogStrings = new StringBuffer();
- }
- mDialogStrings.append("ALERT: ");
- mDialogStrings.append(message);
- mDialogStrings.append('\n');
- result.confirm();
- return true;
- }
-
- @Override
- public boolean onJsConfirm(WebView view, String url, String message,
- JsResult result) {
- if (mDialogStrings == null) {
- mDialogStrings = new StringBuffer();
- }
- mDialogStrings.append("CONFIRM: ");
- mDialogStrings.append(message);
- mDialogStrings.append('\n');
- result.confirm();
- return true;
- }
-
- @Override
- public boolean onJsPrompt(WebView view, String url, String message,
- String defaultValue, JsPromptResult result) {
- if (mDialogStrings == null) {
- mDialogStrings = new StringBuffer();
- }
- mDialogStrings.append("PROMPT: ");
- mDialogStrings.append(message);
- mDialogStrings.append(", default text: ");
- mDialogStrings.append(defaultValue);
- mDialogStrings.append('\n');
- result.confirm();
- return true;
- }
- };
-
- private void resetTestStatus() {
- mWaitUntilDone = false;
- mDumpAsText = false;
- mTimedOut = false;
- mDumpTitleChanges = false;
- mRequestedWebKitData = false;
- mEventSender.resetMouse();
- }
-
- private TestRecorder mResultRecorder;
- private HTMLHostCallbackInterface mCallback = null;
- private CallbackProxy mCallbackProxy;
-
- private WebView mWebView;
- private WebViewEventSender mEventSender;
-
- private Vector<String> mTestList;
- private int mTestIndex;
-
- private int mTimeoutInMillis;
- private String mTestPathPrefix;
- private boolean mSingleTestMode;
-
- private AsyncHandler mHandler;
- private boolean mFinishedRunning;
-
- private boolean mTimedOut;
- private boolean mRequestedWebKitData;
- private boolean mDumpAsText;
- private boolean mWaitUntilDone;
- private boolean mDumpTitleChanges;
-
- private StringBuffer mTitleChanges;
- private StringBuffer mDialogStrings;
-
- private boolean mKeepWebHistory;
- private Vector mWebHistory;
-
- static final String TIMEOUT_STR = "**Test timeout";
-
- static final int MSG_TIMEOUT = 0;
- static final int MSG_WEBKIT_DATA = 1;
-
- static final String LOGTAG="DumpRenderTree";
-
- static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
- static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/layout_tests_list.txt";
- static final String TEST_STATUS_FILE = "/sdcard/running_test.txt";
-
- static final String RESUME_FROM_CRASH = "ResumeFromCrash";
- static final String TEST_PATH_PREFIX = "TestPathPrefix";
- static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
- static final String SINGLE_TEST_MODE = "SingleTestMode";
-}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
index 1f37405..8f968b4 100755
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
@@ -27,7 +27,7 @@
/**
- * Instrumentation Test Runner for all MediaPlayer tests.
+ * Instrumentation Test Runner for all DumpRenderTree tests.
*
* Running all tests:
*
@@ -40,6 +40,7 @@
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(LayoutTestsAutoTest.class);
+ suite.addTestSuite(LoadTestsAutoTest.class);
return suite;
}
@@ -51,18 +52,22 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- String path = (String) icicle.get("path");
- LayoutTestsAutoTest.setLayoutTestDir(path);
+ this.mTestPath = (String) icicle.get("path");
String timeout_str = (String) icicle.get("timeout");
- int timeout = 0; // default value
if (timeout_str != null) {
try {
- timeout = Integer.parseInt(timeout_str);
+ this.mTimeoutInMillis = Integer.parseInt(timeout_str);
} catch (Exception e) {
e.printStackTrace();
}
}
- LayoutTestsAutoTest.setTimeoutInMillis(timeout);
+
+ String r = (String)icicle.get("rebaseline");
+ this.mRebaseline = (r != null && r.toLowerCase().equals("true"));
}
+
+ public String mTestPath = null;
+ public int mTimeoutInMillis = 0;
+ public boolean mRebaseline = false;
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 3e65f0358..a857e68 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -25,92 +25,375 @@
import android.util.Log;
import android.view.KeyEvent;
+import android.webkit.WebSettings;
import android.os.Bundle;
import android.os.Message;
-import android.test.ActivityInstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.dumprendertree.HTMLHostActivity;
+import com.android.dumprendertree.TestShellActivity;
import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.IOException;
+import java.util.Vector;
-public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase<Menu> {
+//TestRecorder creates two files, one for passing tests
+//and another for failing tests and writes the paths to
+//layout tests one line at a time. TestRecorder does not
+//have ability to clear the results.
+class MyTestRecorder {
+ private BufferedOutputStream mBufferedOutputPassedStream;
+ private BufferedOutputStream mBufferedOutputFailedStream;
+ private BufferedOutputStream mBufferedOutputNoresultStream;
+
+ public void passed(String layout_file) {
+ try {
+ mBufferedOutputPassedStream.write(layout_file.getBytes());
+ mBufferedOutputPassedStream.write('\n');
+ mBufferedOutputPassedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void failed(String layout_file) {
+ try {
+ mBufferedOutputFailedStream.write(layout_file.getBytes());
+ mBufferedOutputFailedStream.write('\n');
+ mBufferedOutputFailedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void noresult(String layout_file) {
+ try {
+ mBufferedOutputNoresultStream.write(layout_file.getBytes());
+ mBufferedOutputNoresultStream.write('\n');
+ mBufferedOutputNoresultStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public MyTestRecorder(boolean resume) {
+ try {
+ File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
+ File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
+ File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
+
+ mBufferedOutputPassedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
+ mBufferedOutputFailedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume));
+ mBufferedOutputNoresultStream =
+ new BufferedOutputStream(new FileOutputStream(noExpectedResultFile, resume));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void close() {
+ try {
+ mBufferedOutputPassedStream.close();
+ mBufferedOutputFailedStream.close();
+ mBufferedOutputNoresultStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
- private final static String LOGTAG = "LayoutTests";
- private final static int DEFAULT_TIMEOUT_IN_MILLIS = 6000;
- private static String layoutTestDir = null;
- private static int mTimeoutInMillis = 0;
+
+public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
+
+ private static final String LOGTAG = "LayoutTests";
+ static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
+
+ static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
+ static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
+ static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
+ static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/android/layout_tests_list.txt";
+ static final String TEST_STATUS_FILE = "/sdcard/android/running_test.txt";
+
+ private MyTestRecorder mResultRecorder;
+ private Vector<String> mTestList;
+ private boolean mRebaselineResults;
+ private String mTestPathPrefix;
public LayoutTestsAutoTest() {
- super("com.android.dumprendertree", Menu.class);
+ super("com.android.dumprendertree", TestShellActivity.class);
}
// This function writes the result of the layout test to
// Am status so that it can be picked up from a script.
- public void passOrFailCallback(String file, boolean result) {
+ private void passOrFailCallback(String file, boolean result) {
Instrumentation inst = getInstrumentation();
Bundle bundle = new Bundle();
bundle.putBoolean(file, result);
inst.sendStatus(0, bundle);
}
-
- public static void setTimeoutInMillis(int millis) {
- mTimeoutInMillis = (millis > 0) ? millis : DEFAULT_TIMEOUT_IN_MILLIS;
+
+ private void getTestList() {
+ // Read test list.
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(LAYOUT_TESTS_LIST_FILE));
+ String line = inReader.readLine();
+ while (line != null) {
+ if (line.startsWith(mTestPathPrefix))
+ mTestList.add(line);
+ line = inReader.readLine();
+ }
+ inReader.close();
+ Log.v(LOGTAG, "Test list has " + mTestList.size() + " test(s).");
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
+ }
+ }
+
+ private void resumeTestList() {
+ // read out the test name it stoped last time.
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE));
+ String line = inReader.readLine();
+ for (int i = 0; i < mTestList.size(); i++) {
+ if (mTestList.elementAt(i).equals(line)) {
+ mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size()));
+ break;
+ }
+ }
+ inReader.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
+ }
+ }
+
+ private void clearTestStatus() {
+ // Delete TEST_STATUS_FILE
+ try {
+ File f = new File(TEST_STATUS_FILE);
+ if (f.delete())
+ Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
+ else
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
+ }
+ }
+
+ private void updateTestStatus(String s) {
+ // Write TEST_STATUS_FILE
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE));
+ bos.write(s.getBytes());
+ bos.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE);
+ }
+ }
+
+ private String getResultFile(String test) {
+ String shortName = test.substring(0, test.lastIndexOf('.'));
+ // Write actual results to result directory.
+ return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
+ }
+
+ private String getExpectedResultFile(String test) {
+ String shortName = test.substring(0, test.lastIndexOf('.'));
+ return shortName + "-expected.txt";
}
- public static void setLayoutTestDir(String name) {
- if (name == null)
- throw new AssertionError("Layout test directory cannot be null.");
- layoutTestDir = HTMLHostActivity.LAYOUT_TESTS_ROOT + name;
- Log.v("LayoutTestsAutoTest", " Only running the layout tests : " + layoutTestDir);
+ private String getAndroidExpectedResultFile(String expectedResultFile) {
+ return expectedResultFile.replaceFirst(LAYOUT_TESTS_ROOT, ANDROID_EXPECTED_RESULT_DIR);
}
+ // Wrap up
+ private void failedCase(String file) {
+ Log.w("Layout test: ", file + " failed");
+ mResultRecorder.failed(file);
+ }
+
+ private void passedCase(String file) {
+ Log.v("Layout test:", file + " passed");
+ mResultRecorder.passed(file);
+ }
+
+ private void noresultCase(String file) {
+ Log.v("Layout test:", file + " no expected result");
+ mResultRecorder.noresult(file);
+ }
+
+ private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
+ Log.v(LOGTAG, " Processing result: " + testFile);
+
+ File actual = new File(actualResultFile);
+ File expected = new File(expectedResultFile);
+ if (actual.exists() && expected.exists()) {
+ try {
+ boolean passing = true;
+ BufferedReader fr = new BufferedReader(new FileReader(actual));
+ BufferedReader fe = new BufferedReader(new FileReader(expected));
+ while (true) {
+ String s1 = fr.readLine();
+ String s2 = fe.readLine();
+ if (s1 == null && s2 == null)
+ break; // both files are the same
+ if (s1 == null || s2 == null || !s1.equals(s2)) {
+ passing = false;
+ break;
+ }
+ }
+
+ if (passing) {
+ passedCase(testFile);
+ } else {
+ failedCase(testFile);
+ }
+
+ fe.close();
+ fr.close();
+ } catch (FileNotFoundException ex) {
+ Log.e(LOGTAG, "File not found : " + ex.getMessage());
+ } catch (IOException ex) {
+ Log.e(LOGTAG, "IO Error : " + ex.getMessage());
+ }
+ return;
+ }
+
+ if (!expected.exists()) {
+ noresultCase(testFile);
+ }
+ }
+
+ private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
+ activity.setCallback(new TestShellCallback() {
+ public void finished() {
+ synchronized (LayoutTestsAutoTest.this) {
+ LayoutTestsAutoTest.this.notifyAll();
+ }
+ }
+ });
+
+ String resultFile = getResultFile(test);
+ if (mRebaselineResults) {
+ String expectedResultFile = getExpectedResultFile(test);
+ File f = new File(expectedResultFile);
+ if (f.exists()) {
+ return; // don't run test and don't overwrite default tests.
+ }
+
+ resultFile = getAndroidExpectedResultFile(expectedResultFile);
+ }
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClass(activity, TestShellActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+ intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
+ intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
+ activity.startActivity(intent);
+
+ // Wait until done.
+ synchronized (this) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { }
+ }
+
+ if (!mRebaselineResults) {
+ String expectedResultFile = getExpectedResultFile(test);
+ File f = new File(expectedResultFile);
+ if (!f.exists()) {
+ expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
+ }
+
+ processResult(test, resultFile, expectedResultFile);
+ }
+ }
+
// Invokes running of layout tests
// and waits till it has finished running.
public void executeLayoutTests(boolean resume) {
- Instrumentation inst = getInstrumentation();
+ LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
+ // A convenient method to be called by another activity.
+
+ if (runner.mTestPath == null) {
+ Log.e(LOGTAG, "No test specified");
+ return;
+ }
+
+ this.mTestList = new Vector<String>();
- {
- Activity activity = getActivity();
- Intent intent = new Intent();
- intent.setClass(activity, HTMLHostActivity.class);
- intent.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, resume);
- intent.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, false);
- intent.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, layoutTestDir);
- intent.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, mTimeoutInMillis);
- activity.startActivity(intent);
- }
-
- ActivityMonitor htmlHostActivityMonitor =
- inst.addMonitor("com.android.dumprendertree.HTMLHostActivity", null, false);
+ // Read settings
+ try {
+ this.mTestPathPrefix =
+ (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
+ } catch (IOException e) {
+ Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
+ return;
+ }
+
+ this.mRebaselineResults = runner.mRebaseline;
+
+ int timeout = runner.mTimeoutInMillis;
+ if (timeout <= 0) {
+ timeout = DEFAULT_TIMEOUT_IN_MILLIS;
+ }
+
+ this.mResultRecorder = new MyTestRecorder(resume);
+
+ if (!resume)
+ clearTestStatus();
+
+ getTestList();
+ if (resume)
+ resumeTestList();
- HTMLHostActivity activity =
- (HTMLHostActivity) htmlHostActivityMonitor.waitForActivity();
+ TestShellActivity activity = (TestShellActivity) getActivity();
- while (!activity.hasFinishedRunning()) {
- // Poll every 5 seconds to determine if the layout
- // tests have finished running
- try {Thread.sleep(5000); } catch(Exception e){}
- }
+ // Run tests.
+ for (int i = 0; i < mTestList.size(); i++) {
+ String s = mTestList.elementAt(i);
+ updateTestStatus(s);
+ // Run tests
+ runTestAndWaitUntilDone(activity, s, runner.mTimeoutInMillis);
+ }
- // Wait few more seconds so that results are
- // flushed to the /sdcard
- try {Thread.sleep(5000); } catch(Exception e){}
+ updateTestStatus("#DONE");
+
+ activity.finish();
+ }
- // Clean up the HTMLHostActivity activity
- activity.finish();
+
+ private String getTestPath() {
+ LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
+
+ String test_path = LAYOUT_TESTS_ROOT;
+ if (runner.mTestPath != null) {
+ test_path += runner.mTestPath;
+ }
+ try {
+ test_path = new File(test_path).getCanonicalPath();
+ } catch (IOException e) {
+ Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
+ }
+ Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
+
+ return test_path;
}
public void generateTestList() {
try {
- File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE);
+ File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
- findTestsRecursively(bos, layoutTestDir);
+ findTestsRecursively(bos, getTestPath());
bos.flush();
bos.close();
} catch (Exception e) {
@@ -156,7 +439,7 @@
// in chunks.
public void startLayoutTests() {
try {
- File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE);
+ File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
if (!tests_list.exists())
generateTestList();
} catch (Exception e) {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
new file mode 100644
index 0000000..b064dbb
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.Intent;
+
+import android.util.Log;
+
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+
+import com.android.dumprendertree.TestShellActivity;
+import com.android.dumprendertree.TestShellCallback;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+class StreamPipe extends Thread {
+ InputStream in;
+ OutputStream out;
+
+ StreamPipe(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ byte[] buf = new byte[1024];
+ int nofb = this.in.read(buf);
+ while (nofb != -1) {
+ this.out.write(buf, 0, nofb);
+ nofb = this.in.read(buf);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
+
+public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> {
+
+ private final static String LOGTAG = "LoadTest";
+ private final static String LOAD_TEST_RESULT = "/sdcard/load_test_result.txt";
+
+ public LoadTestsAutoTest() {
+ super("com.android.dumprendertree", TestShellActivity.class);
+ }
+
+ // This function writes the result of the layout test to
+ // Am status so that it can be picked up from a script.
+ public void passOrFailCallback(String file, boolean result) {
+ Instrumentation inst = getInstrumentation();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(file, result);
+ inst.sendStatus(0, bundle);
+ }
+
+ // Invokes running of layout tests
+ // and waits till it has finished running.
+ public void runTest() {
+ LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
+
+ if (runner.mTestPath == null) {
+ Log.e(LOGTAG, "No test specified");
+ return;
+ }
+
+ TestShellActivity activity = (TestShellActivity) getActivity();
+
+ // Run tests
+ runTestAndWaitUntilDone(activity, runner.mTestPath, runner.mTimeoutInMillis);
+
+ // TODO(fqian): let am instrumentation pass in the command line, currently
+ // am instrument does not allow spaces in the command.
+ runPostShellCommand("/system/bin/dumpsys meminfo");
+
+ // Kill activity
+ activity.finish();
+ }
+
+ private void runPostShellCommand(String cmd) {
+ if (cmd == null || cmd.length() == 0)
+ return;
+
+ try {
+ // Call dumpsys meminfo
+ Process proc = Runtime.getRuntime().exec(cmd);
+ // Append output to LOAD_TEST_RESULT
+ InputStream input = proc.getInputStream();
+ InputStream error = proc.getErrorStream();
+ FileOutputStream out = new FileOutputStream(LOAD_TEST_RESULT, true);
+
+ StreamPipe p_in = new StreamPipe(input, out);
+ StreamPipe p_err = new StreamPipe(error, System.err);
+
+ p_in.start();
+ p_err.start();
+
+ proc.waitFor();
+ } catch (IOException e) {
+ Log.e(LOGTAG, e.getMessage());
+ } catch (InterruptedException e) {
+ Log.e(LOGTAG, e.getMessage());
+ }
+ }
+
+ // A convenient method to be called by another activity.
+ private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout) {
+ activity.setCallback(new TestShellCallback() {
+ public void finished() {
+ synchronized (LoadTestsAutoTest.this) {
+ LoadTestsAutoTest.this.notifyAll();
+ }
+ }
+ });
+
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClass(activity, TestShellActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(TestShellActivity.TEST_URL, url);
+ intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
+ intent.putExtra(TestShellActivity.RESULT_FILE, LOAD_TEST_RESULT);
+ activity.startActivity(intent);
+
+ // Wait until done.
+ synchronized (this) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { }
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
index de0da61..00e0f89 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
@@ -19,6 +19,7 @@
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
+import android.util.Log;
import java.io.File;
@@ -42,15 +43,12 @@
}
void processFile(String filename, boolean selection)
- {
- Intent result = new Intent();
- result.setClass(this, HTMLHostActivity.class);
- result.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, false);
- result.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, true);
- result.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, filename);
- result.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, 8000);
- startActivity(result);
+ {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setClass(this, TestShellActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ intent.putExtra(TestShellActivity.TEST_URL, "file://" + filename);
+ startActivity(intent);
}
-
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
new file mode 100644
index 0000000..bf8a3b3
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Vector;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.util.Log;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.view.ViewGroup;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.widget.LinearLayout;
+import android.os.*;
+
+public class TestShellActivity extends Activity implements LayoutTestController {
+ public class AsyncHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_TIMEOUT) {
+ mTimedOut = true;
+ requestWebKitData();
+ return;
+ } else if (msg.what == MSG_WEBKIT_DATA) {
+ TestShellActivity.this.dump(mTimedOut, (String)msg.obj);
+ return;
+ }
+
+ super.handleMessage(msg);
+ }
+ }
+
+ public void requestWebKitData() {
+ Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
+
+ if (mRequestedWebKitData)
+ throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
+
+ mRequestedWebKitData = true;
+ if (mDumpAsText) {
+ mWebView.documentAsText(callback);
+ } else {
+ mWebView.externalRepresentation(callback);
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ LinearLayout contentView = new LinearLayout(this);
+ contentView.setOrientation(LinearLayout.VERTICAL);
+ setContentView(contentView);
+
+ mWebView = new WebView(this);
+ mWebView.getSettings().setJavaScriptEnabled(true);
+ mWebView.setWebChromeClient(mChromeClient);
+ mEventSender = new WebViewEventSender(mWebView);
+ mCallbackProxy = new CallbackProxy(mEventSender, this);
+
+ mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
+ mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+ contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
+
+ mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+
+ mHandler = new AsyncHandler();
+
+ Intent intent = getIntent();
+ if (intent != null) {
+ executeIntent(intent);
+ }
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ executeIntent(intent);
+ }
+
+ private void executeIntent(Intent intent) {
+ resetTestStatus();
+ if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
+ return;
+ }
+
+ mTestUrl = intent.getStringExtra(TEST_URL);
+ if (mTestUrl == null)
+ return;
+
+ mResultFile = intent.getStringExtra(RESULT_FILE);
+ mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
+
+ Log.v(LOGTAG, " Loading " + mTestUrl);
+ mWebView.loadUrl(mTestUrl);
+
+ if (mTimeoutInMillis > 0) {
+ // Create a timeout timer
+ Message m = mHandler.obtainMessage(MSG_TIMEOUT);
+ mHandler.sendMessageDelayed(m, mTimeoutInMillis);
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mWebView.stopLoading();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mWebView.destroy();
+ mWebView = null;
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ Log.e(LOGTAG, "Low memory, kill self");
+ System.exit(1);
+ }
+
+ // Dump the page
+ public void dump(boolean timeout, String webkitData) {
+ if (mResultFile == null || mResultFile.length() == 0) {
+ finished();
+ return;
+ }
+
+ try {
+ File parentDir = new File(mResultFile).getParentFile();
+ if (!parentDir.exists()) {
+ parentDir.mkdirs();
+ }
+
+ FileOutputStream os = new FileOutputStream(mResultFile);
+ if (timeout) {
+ Log.w("Layout test: Timeout", mResultFile);
+ os.write(TIMEOUT_STR.getBytes());
+ os.write('\n');
+ }
+ if (mDumpTitleChanges)
+ os.write(mTitleChanges.toString().getBytes());
+ if (mDialogStrings != null)
+ os.write(mDialogStrings.toString().getBytes());
+ mDialogStrings = null;
+ os.write(webkitData.getBytes());
+ os.flush();
+ os.close();
+ } catch (IOException ex) {
+ Log.e(LOGTAG, "Cannot write to " + mResultFile + ", " + ex.getMessage());
+ }
+
+ finished();
+ }
+
+ public void setCallback(TestShellCallback callback) {
+ mCallback = callback;
+ }
+
+ public void finished() {
+ if (mCallback != null) {
+ mCallback.finished();
+ }
+ }
+
+ // .......................................
+ // LayoutTestController Functions
+ public void dumpAsText() {
+ mDumpAsText = true;
+ if (mWebView != null) {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "dumpAsText called: "+url);
+ }
+ }
+
+ public void waitUntilDone() {
+ mWaitUntilDone = true;
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "waitUntilDone called: " + url);
+ }
+
+ public void notifyDone() {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "notifyDone called: " + url);
+ if (mWaitUntilDone) {
+ mWaitUntilDone = false;
+ mChromeClient.onProgressChanged(mWebView, 100);
+ }
+ }
+
+ public void display() {
+ mWebView.invalidate();
+ }
+
+ public void clearBackForwardList() {
+ mWebView.clearHistory();
+
+ }
+
+ public void dumpBackForwardList() {
+ //printf("\n============== Back Forward List ==============\n");
+ // mWebHistory
+ //printf("===============================================\n");
+
+ }
+
+ public void dumpChildFrameScrollPositions() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpEditingCallbacks() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpSelectionRect() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpTitleChanges() {
+ if (!mDumpTitleChanges) {
+ mTitleChanges = new StringBuffer();
+ }
+ mDumpTitleChanges = true;
+ }
+
+ public void keepWebHistory() {
+ if (!mKeepWebHistory) {
+ mWebHistory = new Vector();
+ }
+ mKeepWebHistory = true;
+ }
+
+ public void queueBackNavigation(int howfar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueForwardNavigation(int howfar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueLoad(String Url, String frameTarget) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueReload() {
+ mWebView.reload();
+ }
+
+ public void queueScript(String scriptToRunInCurrentContext) {
+ mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
+ }
+
+ public void repaintSweepHorizontally() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAcceptsEditing(boolean b) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setMainFrameIsFirstResponder(boolean b) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setWindowIsKey(boolean b) {
+ // This is meant to show/hide the window. The best I can find
+ // is setEnabled()
+ mWebView.setEnabled(b);
+ }
+
+ public void testRepaint() {
+ mWebView.invalidate();
+ }
+
+ private final WebChromeClient mChromeClient = new WebChromeClient() {
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ if (newProgress == 100) {
+ if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "Finished: "+ url);
+ mHandler.removeMessages(MSG_TIMEOUT);
+ requestWebKitData();
+ } else {
+ String url = mWebView.getUrl();
+ if (mTimedOut) {
+ Log.v(LOGTAG, "Timed out before finishing: " + url);
+ } else if (mWaitUntilDone) {
+ Log.v(LOGTAG, "Waiting for notifyDone: " + url);
+ } else if (mRequestedWebKitData) {
+ Log.v(LOGTAG, "Requested webkit data ready: " + url);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ if (title.length() > 30)
+ title = "..."+title.substring(title.length()-30);
+ setTitle(title);
+ if (mDumpTitleChanges) {
+ mTitleChanges.append("TITLE CHANGED: ");
+ mTitleChanges.append(title);
+ mTitleChanges.append("\n");
+ }
+ }
+
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message,
+ JsResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("ALERT: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+
+ @Override
+ public boolean onJsConfirm(WebView view, String url, String message,
+ JsResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("CONFIRM: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message,
+ String defaultValue, JsPromptResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("PROMPT: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append(", default text: ");
+ mDialogStrings.append(defaultValue);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+ };
+
+ private void resetTestStatus() {
+ mWaitUntilDone = false;
+ mDumpAsText = false;
+ mTimedOut = false;
+ mDumpTitleChanges = false;
+ mRequestedWebKitData = false;
+ mEventSender.resetMouse();
+ }
+
+ private WebView mWebView;
+ private WebViewEventSender mEventSender;
+ private AsyncHandler mHandler;
+ private TestShellCallback mCallback;
+
+ private CallbackProxy mCallbackProxy;
+
+ private String mTestUrl;
+ private String mResultFile;
+ private int mTimeoutInMillis;
+
+ // States
+ private boolean mTimedOut;
+ private boolean mRequestedWebKitData;
+ private boolean mFinishedRunning;
+
+ // Layout test controller variables.
+ private boolean mDumpAsText;
+ private boolean mWaitUntilDone;
+ private boolean mDumpTitleChanges;
+ private StringBuffer mTitleChanges;
+ private StringBuffer mDialogStrings;
+ private boolean mKeepWebHistory;
+ private Vector mWebHistory;
+
+ static final String TIMEOUT_STR = "**Test timeout";
+
+ static final int MSG_TIMEOUT = 0;
+ static final int MSG_WEBKIT_DATA = 1;
+
+ static final String LOGTAG="TestShell";
+
+ static final String TEST_URL = "TestUrl";
+ static final String RESULT_FILE = "ResultFile";
+ static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
similarity index 89%
rename from tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java
rename to tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
index 60a2915..759c443 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellCallback.java
@@ -16,6 +16,6 @@
package com.android.dumprendertree;
-public interface HTMLHostCallbackInterface {
- public void waitForFinish();
+public interface TestShellCallback {
+ public void finished();
}
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index e248763..fc658f5 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -610,6 +610,62 @@
}
// ==========================================================
+static string
+generate_outputFileName(const Options& options, const document_item_type* items)
+{
+ string result;
+
+ // items has already been checked to have only one interface.
+ if (items->item_type == INTERFACE_TYPE) {
+ interface_type* type = (interface_type*)items;
+
+ // create the path to the destination folder based on the
+ // interface package name
+ result = options.outputBaseFolder;
+ result += OS_PATH_SEPARATOR;
+
+ string package = type->package;
+ size_t len = package.length();
+ for (size_t i=0; i<len; i++) {
+ if (package[i] == '.') {
+ package[i] = OS_PATH_SEPARATOR;
+ }
+ }
+
+ result += package;
+
+ // add the filename by replacing the .aidl extension to .java
+ const char* p = strchr(type->name.data, '.');
+ len = p ? p-type->name.data : strlen(type->name.data);
+
+ result += OS_PATH_SEPARATOR;
+ result.append(type->name.data, len);
+ result += ".java";
+ }
+
+ return result;
+}
+
+// ==========================================================
+static void
+check_outputFileName(const string& path) {
+ size_t len = path.length();
+ for (size_t i=0; i<len ; i++) {
+ if (path[i] == OS_PATH_SEPARATOR) {
+ string p = path.substr(0, i);
+ if (access(path.data(), F_OK) != 0) {
+#ifdef HAVE_MS_C_RUNTIME
+ _mkdir(p.data());
+#else
+ mkdir(p.data(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+#endif
+ }
+ }
+ }
+}
+
+
+// ==========================================================
static int
parse_preprocessed_file(const string& filename)
{
@@ -804,7 +860,17 @@
generate_dep_file(options);
}
- err = generate_java(options.outputFileName, options.inputFileName.c_str(),
+ // if needed, generate the outputFileName from the outputBaseFolder
+ string outputFileName = options.outputFileName;
+ if (outputFileName.length() == 0 &&
+ options.outputBaseFolder.length() > 0) {
+ outputFileName = generate_outputFileName(options, mainDoc);
+ }
+
+ // make sure the folders of the output file all exists
+ check_outputFileName(outputFileName);
+
+ err = generate_java(outputFileName, options.inputFileName.c_str(),
(interface_type*)mainDoc);
return err;
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
index 57b10ae..0aa7db2 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -13,16 +13,19 @@
" aidl --preprocess OUTPUT INPUT...\n"
"\n"
"OPTIONS:\n"
- " -I<DIR> search path for import statements.\n"
- " -d<FILE> generate dependency file.\n"
- " -p<FILE> file created by --preprocess to import.\n"
- " -b fail when trying to compile a parcelable.\n"
+ " -I<DIR> search path for import statements.\n"
+ " -d<FILE> generate dependency file.\n"
+ " -p<FILE> file created by --preprocess to import.\n"
+ " -o<FOLDER> base output folder for generated files.\n"
+ " -b fail when trying to compile a parcelable.\n"
"\n"
"INPUT:\n"
" An aidl interface file.\n"
"\n"
"OUTPUT:\n"
- " The generated interface files. If omitted, the input filename is used, with the .aidl extension changed to a .java extension.\n"
+ " The generated interface files.\n"
+ " If omitted and the -o option is not used, the input filename is used, with the .aidl extension changed to a .java extension.\n"
+ " If the -o option is used, the generated files will be placed in the base output folder, under their package folder\n"
);
return 1;
}
@@ -78,6 +81,14 @@
return usage();
}
}
+ else if (s[1] == 'o') {
+ if (len > 2) {
+ options->outputBaseFolder = s+2;
+ } else {
+ fprintf(stderr, "-o option (%d) requires a path.\n", i);
+ return usage();
+ }
+ }
else if (len == 2 && s[1] == 'b') {
options->failOnParcelable = true;
}
@@ -111,7 +122,7 @@
if (i < argc) {
options->outputFileName = argv[i];
i++;
- } else {
+ } else if (options->outputBaseFolder.length() == 0) {
// copy input into output and change the extension from .aidl to .java
options->outputFileName = options->inputFileName;
string::size_type pos = options->outputFileName.size()-5;
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index dc3c45a..e9bf0f7 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -20,6 +20,7 @@
vector<string> preprocessedFiles;
string inputFileName;
string outputFileName;
+ string outputBaseFolder;
string depFileName;
vector<string> filesToPreprocess;