Merge change 25206 into eclair
* changes:
Make vCard importer code use Account information if possible.
diff --git a/api/current.xml b/api/current.xml
index 7562f2e..6174bff 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -10659,6 +10659,17 @@
visibility="public"
>
</field>
+<field name="screen_background_light_transparent"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301674"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="spinner_background"
type="int"
transient="false"
@@ -12714,6 +12725,17 @@
visibility="public"
>
</field>
+<field name="Theme_Light_WallpaperSettings"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973922"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Theme_NoDisplay"
type="int"
transient="false"
@@ -12802,6 +12824,17 @@
visibility="public"
>
</field>
+<field name="Theme_WallpaperSettings"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973921"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Theme_Wallpaper_NoTitleBar"
type="int"
transient="false"
@@ -117496,6 +117529,37 @@
</implements>
</interface>
</package>
+<package name="android.service.wallpaper"
+>
+<class name="WallpaperSettingsActivity"
+ extends="android.preference.PreferenceActivity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WallpaperSettingsActivity"
+ type="android.service.wallpaper.WallpaperSettingsActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="EXTRA_PREVIEW_MODE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.service.wallpaper.PREVIEW_MODE""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
<package name="android.speech"
>
<class name="RecognizerIntent"
@@ -167438,24 +167502,13 @@
</parameter>
</method>
</class>
-<class name="PluginStub"
- extends="java.lang.Object"
+<interface name="PluginStub"
abstract="true"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
-<constructor name="PluginStub"
- type="android.webkit.PluginStub"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="npp" type="int">
-</parameter>
-</constructor>
<method name="getEmbeddedView"
return="android.view.View"
abstract="true"
@@ -167466,6 +167519,8 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="NPP" type="int">
+</parameter>
<parameter name="context" type="android.content.Context">
</parameter>
</method>
@@ -167479,10 +167534,12 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="NPP" type="int">
+</parameter>
<parameter name="context" type="android.content.Context">
</parameter>
</method>
-</class>
+</interface>
<class name="SslErrorHandler"
extends="android.os.Handler"
abstract="false"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 39ed769..5b55252 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -11,6 +11,7 @@
libstagefright
LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
@@ -32,6 +33,7 @@
libstagefright
LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 1e590f0..7859d5a 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -583,13 +583,8 @@
return;
}
- if (!getConnectivityManager().getBackgroundDataSetting()) {
- if (isLoggable) {
- Log.v(TAG, "not syncing because background data usage isn't allowed");
- }
- setStatusText("Sync is disabled.");
- return;
- }
+ final boolean backgroundDataUsageAllowed =
+ getConnectivityManager().getBackgroundDataSetting();
if (mAccounts == null) setStatusText("The accounts aren't known yet.");
if (!mDataConnectionIsConnected) setStatusText("No data connection");
@@ -686,7 +681,8 @@
} else {
final boolean syncAutomatically = masterSyncAutomatically
&& mSyncStorageEngine.getSyncAutomatically(account, authority);
- boolean syncAllowed = manualSync || syncAutomatically;
+ boolean syncAllowed =
+ manualSync || (backgroundDataUsageAllowed && syncAutomatically);
if (!syncAllowed) {
if (isLoggable) {
Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0cd4036..e425f3a 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -22,10 +22,11 @@
import android.database.SQLException;
import android.os.Debug;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Config;
-import android.util.Log;
import android.util.EventLog;
+import android.util.Log;
import java.io.File;
import java.util.HashMap;
@@ -221,6 +222,10 @@
// that logging is not enabled.
/* package */ final boolean mLogStats;
+ // System property that enables logging of slow queries. Specify the threshold in ms.
+ private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
+ private final int mSlowQueryThreshold;
+
/**
* @param closable
*/
@@ -1202,27 +1207,38 @@
String editTable) {
long timeStart = 0;
- if (Config.LOGV) {
+ if (Config.LOGV || mSlowQueryThreshold != -1) {
timeStart = System.currentTimeMillis();
}
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
+ Cursor cursor = null;
try {
- return driver.query(
+ cursor = driver.query(
cursorFactory != null ? cursorFactory : mFactory,
selectionArgs);
} finally {
- if (Config.LOGV) {
+ if (Config.LOGV || mSlowQueryThreshold != -1) {
+
+ // Force query execution
+ if (cursor != null) {
+ cursor.moveToFirst();
+ cursor.moveToPosition(-1);
+ }
+
long duration = System.currentTimeMillis() - timeStart;
- Log.v(SQLiteCursor.TAG,
- "query (" + duration + " ms): " + driver.toString() + ", args are "
- + (selectionArgs != null
- ? TextUtils.join(",", selectionArgs)
- : "<null>"));
+ if (Config.LOGV || duration >= mSlowQueryThreshold) {
+ Log.v(SQLiteCursor.TAG,
+ "query (" + duration + " ms): " + driver.toString() + ", args are "
+ + (selectionArgs != null
+ ? TextUtils.join(",", selectionArgs)
+ : "<null>"));
+ }
}
}
+ return cursor;
}
/**
@@ -1671,6 +1687,7 @@
mFlags = flags;
mPath = path;
mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
+ mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
mLeakedException = new IllegalStateException(path +
" SQLiteDatabase created and never closed");
diff --git a/core/java/android/service/wallpaper/WallpaperSettingsActivity.java b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java
new file mode 100644
index 0000000..501947da
--- /dev/null
+++ b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.service.wallpaper;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Base class for activities that will be used to configure the settings of
+ * a wallpaper. You should derive from this class to allow it to select the
+ * proper theme of the activity depending on how it is being used.
+ */
+public class WallpaperSettingsActivity extends PreferenceActivity {
+ /**
+ * This boolean extra in the launch intent indicates that the settings
+ * are being used while the wallpaper is in preview mode.
+ */
+ final public static String EXTRA_PREVIEW_MODE
+ = "android.service.wallpaper.PREVIEW_MODE";
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ if (false) {
+ Resources.Theme theme = getTheme();
+ if (getIntent().getBooleanExtra(EXTRA_PREVIEW_MODE, false)) {
+ theme.applyStyle(com.android.internal.R.style.PreviewWallpaperSettings, true);
+ } else {
+ theme.applyStyle(com.android.internal.R.style.ActiveWallpaperSettings, true);
+ }
+ }
+ super.onCreate(icicle);
+ }
+}
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 172e9ac..38881d3 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -401,16 +401,12 @@
private static SparseArray<String> PICKER_SETS =
new SparseArray<String>();
static {
- PICKER_SETS.put('!', "\u00A1");
- PICKER_SETS.put('<', "\u00AB");
- PICKER_SETS.put('>', "\u00BB");
- PICKER_SETS.put('?', "\u00BF");
PICKER_SETS.put('A', "\u00C0\u00C1\u00C2\u00C4\u00C6\u00C3\u00C5\u0104\u0100");
PICKER_SETS.put('C', "\u00C7\u0106\u010C");
PICKER_SETS.put('D', "\u010E");
PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB\u0118\u011A\u0112");
PICKER_SETS.put('L', "\u0141");
- PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A");
+ PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A\u0130");
PICKER_SETS.put('N', "\u00D1\u0143\u0147");
PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6\u014C");
PICKER_SETS.put('R', "\u0158");
@@ -423,7 +419,7 @@
PICKER_SETS.put('c', "\u00E7\u0107\u010D");
PICKER_SETS.put('d', "\u010F");
PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB\u0119\u011B\u0113");
- PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B");
+ PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B\u0131");
PICKER_SETS.put('l', "\u0142");
PICKER_SETS.put('n', "\u00F1\u0144\u0148");
PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6\u014D");
@@ -435,6 +431,33 @@
PICKER_SETS.put('z', "\u017A\u017C\u017E");
PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
"\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\");
+
+ // From packages/inputmethods/LatinIME/res/xml/kbd_symbols.xml
+
+ PICKER_SETS.put('1', "\u00b9\u00bd\u2153\u00bc\u215b");
+ PICKER_SETS.put('2', "\u00b2\u2154");
+ PICKER_SETS.put('3', "\u00b3\u00be\u215c");
+ PICKER_SETS.put('4', "\u2074");
+ PICKER_SETS.put('5', "\u215d");
+ PICKER_SETS.put('7', "\u215e");
+ PICKER_SETS.put('0', "\u207f\u2205");
+ PICKER_SETS.put('$', "\u00a2\u00a3\u20ac\u00a5\u20a3\u20a4\u20b1");
+ PICKER_SETS.put('%', "\u2030");
+ PICKER_SETS.put('*', "\u2020\u2021");
+ PICKER_SETS.put('-', "\u2013\u2014");
+ PICKER_SETS.put('+', "\u00b1");
+ PICKER_SETS.put('(', "[{<");
+ PICKER_SETS.put(')', "]}>");
+ PICKER_SETS.put('!', "\u00a1");
+ PICKER_SETS.put('"', "\u201c\u201d\u00ab\u00bb\u02dd");
+ PICKER_SETS.put('?', "\u00bf");
+ PICKER_SETS.put(',', "\u201a\u201e");
+
+ // From packages/inputmethods/LatinIME/res/xml/kbd_symbols_shift.xml
+
+ PICKER_SETS.put('=', "\u2260\u2248\u221e");
+ PICKER_SETS.put('<', "\u2264\u00ab\u2039");
+ PICKER_SETS.put('>', "\u2265\u00bb\u203a");
};
private boolean showCharacterPicker(View view, Editable content, char c,
diff --git a/core/java/android/webkit/PluginActivity.java b/core/java/android/webkit/PluginActivity.java
index f9e3080..cda7b59 100644
--- a/core/java/android/webkit/PluginActivity.java
+++ b/core/java/android/webkit/PluginActivity.java
@@ -49,10 +49,10 @@
final int npp = intent.getIntExtra(INTENT_EXTRA_NPP_INSTANCE, -1);
// Retrieve the PluginStub implemented in packageName.className
PluginStub stub =
- PluginUtil.getPluginStub(this, packageName, className, npp);
+ PluginUtil.getPluginStub(this, packageName, className);
if (stub != null) {
- View pluginView = stub.getFullScreenView(this);
+ View pluginView = stub.getFullScreenView(npp, this);
if (pluginView != null) {
setContentView(pluginView);
} else {
diff --git a/core/java/android/webkit/PluginStub.java b/core/java/android/webkit/PluginStub.java
index c24da8d..3887d44 100644
--- a/core/java/android/webkit/PluginStub.java
+++ b/core/java/android/webkit/PluginStub.java
@@ -19,32 +19,29 @@
import android.view.View;
/**
- * This abstract class is used to implement plugins in a WebView. A plugin
+ * This interface is used to implement plugins in a WebView. A plugin
* package may extend this class and implement the abstract functions to create
* embedded or fullscreeen views displayed in a WebView. The PluginStub
* implementation will be provided the same NPP instance that is created
* through the native interface.
*/
-public abstract class PluginStub {
- /**
- * Construct a new PluginStub implementation for the given NPP instance.
- * @param npp The native NPP instance.
- */
- public PluginStub(int npp) { }
+public interface PluginStub {
/**
* Return a custom embedded view to draw the plugin.
+ * @param NPP The native NPP instance.
* @param context The current application's Context.
* @return A custom View that will be managed by WebView.
*/
- public abstract View getEmbeddedView(Context context);
+ public abstract View getEmbeddedView(int NPP, Context context);
/**
* Return a custom full-screen view to be displayed when the user requests
* a plugin display as full-screen. Note that the application may choose not
* to display this View as completely full-screen.
+ * @param NPP The native NPP instance.
* @param context The current application's Context.
* @return A custom View that will be managed by the application.
*/
- public abstract View getFullScreenView(Context context);
+ public abstract View getFullScreenView(int NPP, Context context);
}
diff --git a/core/java/android/webkit/PluginUtil.java b/core/java/android/webkit/PluginUtil.java
index c0a7375..8fdbd67 100644
--- a/core/java/android/webkit/PluginUtil.java
+++ b/core/java/android/webkit/PluginUtil.java
@@ -32,19 +32,16 @@
* @param className the fully qualified name of a subclass of PluginStub
*/
/* package */
- static PluginStub getPluginStub(Context context, String packageName,
- String className, int NPP) {
+ static PluginStub getPluginStub(Context context, String packageName,
+ String className) {
try {
Context pluginContext = context.createPackageContext(packageName,
Context.CONTEXT_INCLUDE_CODE |
Context.CONTEXT_IGNORE_SECURITY);
ClassLoader pluginCL = pluginContext.getClassLoader();
- Class<?> stubClass =
- pluginCL.loadClass(className);
- Constructor<?> stubConstructor =
- stubClass.getConstructor(int.class);
- Object stubObject = stubConstructor.newInstance(NPP);
+ Class<?> stubClass = pluginCL.loadClass(className);
+ Object stubObject = stubClass.newInstance();
if (stubObject instanceof PluginStub) {
return (PluginStub) stubObject;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 5f2d65e..ac3334c 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -34,6 +34,7 @@
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
+import android.view.View;
import java.util.ArrayList;
import java.util.Map;
@@ -2060,84 +2061,32 @@
}
}
- // This class looks like a SurfaceView to native code. In java, we can
- // assume the passed in SurfaceView is this class so we can talk to the
- // ViewManager through the ChildView.
- private class SurfaceViewProxy extends SurfaceView
- implements SurfaceHolder.Callback {
- private final ViewManager.ChildView mChildView;
- private int mPointer;
- private final boolean mIsFixedSize;
- SurfaceViewProxy(Context context, ViewManager.ChildView childView,
- int pointer, int pixelFormat, boolean isFixedSize) {
- super(context);
- setWillNotDraw(false); // this prevents the black box artifact
- getHolder().addCallback(this);
- getHolder().setFormat(pixelFormat);
- mChildView = childView;
- mChildView.mView = this;
- mPointer = pointer;
- mIsFixedSize = isFixedSize;
- }
- void destroy() {
- mPointer = 0;
- mChildView.removeView();
- }
- void attach(int x, int y, int width, int height) {
- mChildView.attachView(x, y, width, height);
-
- if (mIsFixedSize) {
- getHolder().setFixedSize(width, height);
- }
- }
-
- // SurfaceHolder.Callback methods
- public void surfaceCreated(SurfaceHolder holder) {
- if (mPointer != 0) {
- nativeSurfaceChanged(mPointer, 0, 0, 0, 0);
- }
- }
- public void surfaceChanged(SurfaceHolder holder, int format, int width,
- int height) {
- if (mPointer != 0) {
- nativeSurfaceChanged(mPointer, 1, format, width, height);
- }
- }
- public void surfaceDestroyed(SurfaceHolder holder) {
- if (mPointer != 0) {
- nativeSurfaceChanged(mPointer, 2, 0, 0, 0);
- }
- }
- }
-
- // PluginWidget functions for mainting SurfaceViews for the Surface drawing
+ // PluginWidget functions for creating SurfaceViews for the Surface drawing
// model.
- private SurfaceView createSurface(int nativePointer, int pixelFormat,
- boolean isFixedSize) {
+ private ViewManager.ChildView createSurface(String packageName, String className,
+ int npp, int x, int y, int width, int height) {
if (mWebView == null) {
return null;
}
- return new SurfaceViewProxy(mContext, mWebView.mViewManager.createView(),
- nativePointer, pixelFormat, isFixedSize);
+ PluginStub stub = PluginUtil.getPluginStub(mWebView.getContext(), packageName, className);
+ if (stub == null) {
+ Log.e(LOGTAG, "Unable to find plugin class (" + className +
+ ") in the apk (" + packageName + ")");
+ return null;
+ }
+
+ View pluginView = stub.getEmbeddedView(npp, mWebView.getContext());
+
+ ViewManager.ChildView view = mWebView.mViewManager.createView();
+ view.mView = pluginView;
+ view.attachView(x, y, width, height);
+ return view;
}
-
- private void destroySurface(SurfaceView surface) {
- SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
- proxy.destroy();
+
+ private void destroySurface(ViewManager.ChildView childView) {
+ childView.removeView();
}
- private void attachSurface(SurfaceView surface, int x, int y,
- int width, int height) {
- SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
- proxy.attach(x, y, width, height);
- }
-
- // Callback for the SurfaceHolder.Callback. Called for all the surface
- // callbacks. The state parameter is one of Created(0), Changed(1),
- // Destroyed(2).
- private native void nativeSurfaceChanged(int pointer, int state, int format,
- int width, int height);
-
private native void nativePause();
private native void nativeResume();
private native void nativeFreeMemory();
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 9ec8347..33e83c3 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1148,9 +1148,12 @@
if (sel != null) {
positionSelector(sel);
mSelectedTop = sel.getTop();
+ } else if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
+ View child = getChildAt(mMotionPosition - mFirstPosition);
+ positionSelector(child);
} else {
- mSelectedTop = 0;
- mSelectorRect.setEmpty();
+ mSelectedTop = 0;
+ mSelectorRect.setEmpty();
}
mLayoutMode = LAYOUT_NORMAL;
@@ -1231,8 +1234,12 @@
private void setupChild(View child, int position, int y, boolean flow, int childrenLeft,
boolean selected, boolean recycled, int where) {
boolean isSelected = selected && shouldShowSelector();
-
final boolean updateChildSelected = isSelected != child.isSelected();
+ final int mode = mTouchMode;
+ final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL &&
+ mMotionPosition == position;
+ final boolean updateChildPressed = isPressed != child.isPressed();
+
boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested();
// Respect layout params that are already in the view. Otherwise make
@@ -1257,6 +1264,10 @@
}
}
+ if (updateChildPressed) {
+ child.setPressed(isPressed);
+ }
+
if (needToMeasure) {
int childHeightSpec = ViewGroup.getChildMeasureSpec(
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 6316864..41c9267 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1542,37 +1542,42 @@
recycleBin.scrapActiveViews();
if (sel != null) {
- // the current selected item should get focus if items
- // are focusable
- if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
- final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
- focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
- if (!focusWasTaken) {
- // selected item didn't take focus, fine, but still want
- // to make sure something else outside of the selected view
- // has focus
- final View focused = getFocusedChild();
- if (focused != null) {
- focused.clearFocus();
- }
- positionSelector(sel);
- } else {
- sel.setSelected(false);
- mSelectorRect.setEmpty();
- }
- } else {
- positionSelector(sel);
- }
- mSelectedTop = sel.getTop();
+ // the current selected item should get focus if items
+ // are focusable
+ if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
+ final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
+ focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
+ if (!focusWasTaken) {
+ // selected item didn't take focus, fine, but still want
+ // to make sure something else outside of the selected view
+ // has focus
+ final View focused = getFocusedChild();
+ if (focused != null) {
+ focused.clearFocus();
+ }
+ positionSelector(sel);
+ } else {
+ sel.setSelected(false);
+ mSelectorRect.setEmpty();
+ }
+ } else {
+ positionSelector(sel);
+ }
+ mSelectedTop = sel.getTop();
} else {
- mSelectedTop = 0;
- mSelectorRect.setEmpty();
+ if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL) {
+ View child = getChildAt(mMotionPosition - mFirstPosition);
+ positionSelector(child);
+ } else {
+ mSelectedTop = 0;
+ mSelectorRect.setEmpty();
+ }
- // even if there is not selected position, we may need to restore
- // focus (i.e. something focusable in touch mode)
- if (hasFocus() && focusLayoutRestoreView != null) {
- focusLayoutRestoreView.requestFocus();
- }
+ // even if there is not selected position, we may need to restore
+ // focus (i.e. something focusable in touch mode)
+ if (hasFocus() && focusLayoutRestoreView != null) {
+ focusLayoutRestoreView.requestFocus();
+ }
}
// tell focus view we are done mucking with it, if it is still in
@@ -1686,6 +1691,10 @@
boolean selected, boolean recycled) {
final boolean isSelected = selected && shouldShowSelector();
final boolean updateChildSelected = isSelected != child.isSelected();
+ final int mode = mTouchMode;
+ final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL &&
+ mMotionPosition == position;
+ final boolean updateChildPressed = isPressed != child.isPressed();
final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested();
// Respect layout params that are already in the view. Otherwise make some up...
@@ -1711,6 +1720,10 @@
child.setSelected(isSelected);
}
+ if (updateChildPressed) {
+ child.setPressed(isPressed);
+ }
+
if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
if (child instanceof Checkable) {
((Checkable) child).setChecked(mCheckStates.get(position));
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 760b8ff..e55fbb8 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -249,7 +249,7 @@
lp.height = LayoutParams.WRAP_CONTENT;
lp.width = LayoutParams.FILL_PARENT;
lp.type = LayoutParams.TYPE_APPLICATION_PANEL;
- lp.format = PixelFormat.TRANSPARENT;
+ lp.format = PixelFormat.TRANSLUCENT;
lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons;
mContainerLayoutParams = lp;
diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java
new file mode 100644
index 0000000..7b940c9
--- /dev/null
+++ b/core/java/com/android/internal/widget/RotarySelector.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+
+import com.android.internal.R;
+
+
+/**
+ * Custom view that presents up to two items that are selectable by rotating a semi-circle from
+ * left to right, or right to left. Used by incoming call screen, and the lock screen when no
+ * security pattern is set.
+ */
+public class RotarySelector extends View {
+ private static final String LOG_TAG = "RotarySelector";
+ private static final boolean DBG = false;
+
+ // Listener for onDialTrigger() callbacks.
+ private OnDialTriggerListener mOnDialTriggerListener;
+
+ private float mDensity;
+
+ // UI elements
+ private Drawable mBackground;
+ private Drawable mDimple;
+
+ private Drawable mLeftHandleIcon;
+ private Drawable mRightHandleIcon;
+
+ private Drawable mArrowShortLeftAndRight;
+ private Drawable mArrowLongLeft; // Long arrow starting on the left, pointing clockwise
+ private Drawable mArrowLongRight; // Long arrow starting on the right, pointing CCW
+
+ // positions of the left and right handle
+ private int mLeftHandleX;
+ private int mRightHandleX;
+
+ // current offset of user's dragging
+ private int mTouchDragOffset = 0;
+
+ // state of the animation used to bring the handle back to its start position when
+ // the user lets go before triggering an action
+ private boolean mAnimating = false;
+ private long mAnimationEndTime;
+ private int mAnimatingDelta;
+ AccelerateInterpolator mInterpolator;
+
+ /**
+ * True after triggering an action if the user of {@link OnDialTriggerListener} wants to
+ * freeze the UI (until they transition to another screen).
+ */
+ private boolean mFrozen = false;
+
+ /**
+ * If the user is currently dragging something.
+ */
+ private int mGrabbedState = NOTHING_GRABBED;
+ private static final int NOTHING_GRABBED = 0;
+ private static final int LEFT_HANDLE_GRABBED = 1;
+ private static final int RIGHT_HANDLE_GRABBED = 2;
+
+ /**
+ * Whether the user has triggered something (e.g dragging the left handle all the way over to
+ * the right).
+ */
+ private boolean mTriggered = false;
+
+ // Vibration (haptic feedback)
+ private Vibrator mVibrator;
+ private static final long VIBRATE_SHORT = 60; // msec
+ private static final long VIBRATE_LONG = 100; // msec
+
+ // Various tweakable layout or behavior parameters:
+
+ // How close to the edge of the screen, we let the handle get before
+ // triggering an action:
+ private static final int EDGE_THRESHOLD_DIP = 70;
+
+ /**
+ * The drawable for the arrows need to be scrunched this many dips towards the rotary bg below
+ * it.
+ */
+ private static final int ARROW_SCRUNCH_DIP = 6;
+
+ /**
+ * How far inset the left and right circles should be
+ */
+ private static final int EDGE_PADDING_DIP = 9;
+
+ /**
+ * Dimensions of arc in background drawable.
+ */
+ static final int OUTER_ROTARY_RADIUS_DIP = 390;
+ static final int ROTARY_STROKE_WIDTH_DIP = 83;
+ private static final int ANIMATION_DURATION_MILLIS = 300;
+
+ private static final boolean DRAW_CENTER_DIMPLE = false;
+
+ /**
+ * Constructor used when this widget is created from a layout file.
+ */
+ public RotarySelector(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ if (DBG) log("IncomingCallDialWidget constructor...");
+
+ Resources r = getResources();
+ mDensity = r.getDisplayMetrics().density;
+ if (DBG) log("- Density: " + mDensity);
+ // Density is 1.0 on HVGA (like Dream), and 1.5 on WVGA.
+ // Usage: raw_pixel_value = (int) (dpi_value * mDensity + 0.5f)
+
+ // Assets (all are BitmapDrawables).
+ mBackground = r.getDrawable(R.drawable.jog_dial_bg_cropped);
+ mDimple = r.getDrawable(R.drawable.jog_dial_dimple);
+
+ mArrowLongLeft = r.getDrawable(R.drawable.jog_dial_arrow_long_left_green);
+ mArrowLongRight = r.getDrawable(R.drawable.jog_dial_arrow_long_right_red);
+ mArrowShortLeftAndRight = r.getDrawable(R.drawable.jog_dial_arrow_short_left_and_right);
+
+ mInterpolator = new AccelerateInterpolator();
+ }
+
+ /**
+ * Sets the left handle icon to a given resource.
+ *
+ * The resource should refer to a Drawable object, or use 0 to remove
+ * the icon.
+ *
+ * @param resId the resource ID.
+ */
+ public void setLeftHandleResource(int resId) {
+ Drawable d = null;
+ if (resId != 0) {
+ d = getResources().getDrawable(resId);
+ }
+ setLeftHandleDrawable(d);
+ }
+
+ /**
+ * Sets the left handle icon to a given Drawable.
+ *
+ * @param d the Drawable to use as the icon, or null to remove the icon.
+ */
+ public void setLeftHandleDrawable(Drawable d) {
+ mLeftHandleIcon = d;
+ invalidate();
+ }
+
+ /**
+ * Sets the right handle icon to a given resource.
+ *
+ * The resource should refer to a Drawable object, or use 0 to remove
+ * the icon.
+ *
+ * @param resId the resource ID.
+ */
+ public void setRightHandleResource(int resId) {
+ Drawable d = null;
+ if (resId != 0) {
+ d = getResources().getDrawable(resId);
+ }
+ setRightHandleDrawable(d);
+ }
+
+ /**
+ * Sets the right handle icon to a given Drawable.
+ *
+ * @param d the Drawable to use as the icon, or null to remove the icon.
+ */
+ public void setRightHandleDrawable(Drawable d) {
+ mRightHandleIcon = d;
+ invalidate();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int width = MeasureSpec.getSize(widthMeasureSpec); // screen width
+
+ final int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
+ final int backgroundH = mBackground.getIntrinsicHeight();
+
+ // by making the height less than arrow + bg, arrow and bg will be scrunched together,
+ // overlaying somewhat (though on transparent portions of the drawable).
+ // this works because the arrows are drawn from the top, and the rotary bg is drawn
+ // from the bottom.
+ final int arrowScrunch = (int) (ARROW_SCRUNCH_DIP * mDensity);
+ setMeasuredDimension(width, backgroundH + arrowH - arrowScrunch);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ mLeftHandleX = (int) (EDGE_PADDING_DIP * mDensity) + mDimple.getIntrinsicWidth() / 2;
+ mRightHandleX =
+ getWidth() - (int) (EDGE_PADDING_DIP * mDensity) - mDimple.getIntrinsicWidth() / 2;
+ }
+
+// private Paint mPaint = new Paint();
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (DBG) {
+ log(String.format("onDraw: mAnimating=%s, mTouchDragOffset=%d, mGrabbedState=%d," +
+ "mFrozen=%s",
+ mAnimating, mTouchDragOffset, mGrabbedState, mFrozen));
+ }
+
+ final int height = getHeight();
+
+ // update animating state before we draw anything
+ if (mAnimating && !mFrozen) {
+ long millisLeft = mAnimationEndTime - System.currentTimeMillis();
+ if (DBG) log("millisleft for animating: " + millisLeft);
+ if (millisLeft <= 0) {
+ reset();
+ } else {
+ float interpolation = mInterpolator.getInterpolation(
+ (float) millisLeft / ANIMATION_DURATION_MILLIS);
+ mTouchDragOffset = (int) (mAnimatingDelta * interpolation);
+ }
+ }
+
+
+ // Background:
+ final int backgroundW = mBackground.getIntrinsicWidth();
+ final int backgroundH = mBackground.getIntrinsicHeight();
+ final int backgroundY = height - backgroundH;
+ if (DBG) log("- Background INTRINSIC: " + backgroundW + " x " + backgroundH);
+ mBackground.setBounds(0, backgroundY,
+ backgroundW, backgroundY + backgroundH);
+ if (DBG) log(" Background BOUNDS: " + mBackground.getBounds());
+ mBackground.draw(canvas);
+
+ // Arrows:
+ // All arrow assets are the same size (they're the full width of
+ // the screen) regardless of which arrows are actually visible.
+ int arrowW = mArrowShortLeftAndRight.getIntrinsicWidth();
+ int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
+
+ // Draw the correct arrow(s) depending on the current state:
+ Drawable currentArrow;
+ switch (mGrabbedState) {
+ case NOTHING_GRABBED:
+ currentArrow = mArrowShortLeftAndRight;
+ break;
+ case LEFT_HANDLE_GRABBED:
+ currentArrow = mArrowLongLeft;
+ break;
+ case RIGHT_HANDLE_GRABBED:
+ currentArrow = mArrowLongRight;
+ break;
+ default:
+ throw new IllegalStateException("invalid mGrabbedState: " + mGrabbedState);
+ }
+ currentArrow.setBounds(0, 0, arrowW, arrowH);
+ currentArrow.draw(canvas);
+
+ // debug: draw circle that should match the outer arc (good sanity check)
+// mPaint.setColor(Color.RED);
+// mPaint.setStyle(Paint.Style.STROKE);
+// float or = OUTER_ROTARY_RADIUS_DIP * mDensity;
+// canvas.drawCircle(getWidth() / 2, or + mBackground.getBounds().top, or, mPaint);
+
+ final int outerRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP);
+ final int innerRadius =
+ (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity);
+ final int bgTop = mBackground.getBounds().top;
+ {
+ final int xOffset = mLeftHandleX + mTouchDragOffset;
+ final int drawableY = getYOnArc(
+ mBackground,
+ innerRadius,
+ outerRadius,
+ xOffset);
+
+ drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
+ drawCentered(mLeftHandleIcon, canvas, xOffset, drawableY + bgTop);
+ }
+
+ if (DRAW_CENTER_DIMPLE) {
+ final int xOffset = getWidth() / 2 + mTouchDragOffset;
+ final int drawableY = getYOnArc(
+ mBackground,
+ innerRadius,
+ outerRadius,
+ xOffset);
+
+ drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
+ }
+
+ {
+ final int xOffset = mRightHandleX + mTouchDragOffset;
+ final int drawableY = getYOnArc(
+ mBackground,
+ innerRadius,
+ outerRadius,
+ xOffset);
+
+ drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
+ drawCentered(mRightHandleIcon, canvas, xOffset, drawableY + bgTop);
+ }
+
+ if (mAnimating) invalidate();
+ }
+
+ /**
+ * Assuming drawable is a bounding box around a piece of an arc drawn by two concentric circles
+ * (as the background drawable for the rotary widget is), and given an x coordinate along the
+ * drawable, return the y coordinate of a point on the arc that is between the two concentric
+ * circles. The resulting y combined with the incoming x is a point along the circle in
+ * between the two concentric circles.
+ *
+ * @param drawable The drawable.
+ * @param innerRadius The radius of the circle that intersects the drawable at the bottom two
+ * corders of the drawable (top two corners in terms of drawing coordinates).
+ * @param outerRadius The radius of the circle who's top most point is the top center of the
+ * drawable (bottom center in terms of drawing coordinates).
+ * @param x The distance along the x axis of the desired point.
+ * @return The y coordinate, in drawing coordinates, that will place (x, y) along the circle
+ * in between the two concentric circles.
+ */
+ private int getYOnArc(Drawable drawable, int innerRadius, int outerRadius, int x) {
+
+ // the hypotenuse
+ final int halfWidth = (outerRadius - innerRadius) / 2;
+ final int middleRadius = innerRadius + halfWidth;
+
+ // the bottom leg of the triangle
+ final int triangleBottom = (drawable.getIntrinsicWidth() / 2) - x;
+
+ // "Our offense is like the pythagorean theorem: There is no answer!" - Shaquille O'Neal
+ final int triangleY =
+ (int) Math.sqrt(middleRadius * middleRadius - triangleBottom * triangleBottom);
+
+ // convert to drawing coordinates:
+ // middleRadius - triangleY =
+ // the vertical distance from the outer edge of the circle to the desired point
+ // from there we add the distance from the top of the drawable to the middle circle
+ return middleRadius - triangleY + halfWidth;
+ }
+
+ /**
+ * Handle touch screen events.
+ *
+ * @param event The motion event.
+ * @return True if the event was handled, false otherwise.
+ */
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mAnimating || mFrozen) {
+ return true;
+ }
+
+ final int eventX = (int) event.getX();
+ final int hitWindow = mDimple.getIntrinsicWidth();
+
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (DBG) log("touch-down");
+ mTriggered = false;
+ if (mGrabbedState != RotarySelector.NOTHING_GRABBED) {
+ reset();
+ invalidate();
+ }
+ if (eventX < mLeftHandleX + hitWindow) {
+ mTouchDragOffset = eventX - mLeftHandleX;
+ mGrabbedState = RotarySelector.LEFT_HANDLE_GRABBED;
+ invalidate();
+ vibrate(VIBRATE_SHORT);
+ } else if (eventX > mRightHandleX - hitWindow) {
+ mTouchDragOffset = eventX - mRightHandleX;
+ mGrabbedState = RotarySelector.RIGHT_HANDLE_GRABBED;
+ invalidate();
+ vibrate(VIBRATE_SHORT);
+ }
+ } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ if (DBG) log("touch-move");
+ if (mGrabbedState == RotarySelector.LEFT_HANDLE_GRABBED) {
+ mTouchDragOffset = eventX - mLeftHandleX;
+ invalidate();
+ if (eventX >= mRightHandleX - EDGE_PADDING_DIP && !mTriggered) {
+ mTriggered = true;
+ mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
+ }
+ } else if (mGrabbedState == RotarySelector.RIGHT_HANDLE_GRABBED) {
+ mTouchDragOffset = eventX - mRightHandleX;
+ invalidate();
+ if (eventX <= mLeftHandleX + EDGE_PADDING_DIP && !mTriggered) {
+ mTriggered = true;
+ mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
+ }
+ }
+ } else if ((event.getAction() == MotionEvent.ACTION_UP)) {
+ if (DBG) log("touch-up");
+ // handle animating back to start if they didn't trigger
+ if (mGrabbedState == RotarySelector.LEFT_HANDLE_GRABBED
+ && Math.abs(eventX - mLeftHandleX) > 5) {
+ mAnimating = true;
+ mAnimationEndTime = System.currentTimeMillis() + ANIMATION_DURATION_MILLIS;
+ mAnimatingDelta = eventX - mLeftHandleX;
+ } else if (mGrabbedState == RotarySelector.RIGHT_HANDLE_GRABBED
+ && Math.abs(eventX - mRightHandleX) > 5) {
+ mAnimating = true;
+ mAnimationEndTime = System.currentTimeMillis() + ANIMATION_DURATION_MILLIS;
+ mAnimatingDelta = eventX - mRightHandleX;
+ }
+
+ mTouchDragOffset = 0;
+ mGrabbedState = RotarySelector.NOTHING_GRABBED;
+ invalidate();
+ } else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
+ if (DBG) log("touch-cancel");
+ reset();
+ invalidate();
+ }
+ return true;
+ }
+
+ private void reset() {
+ mAnimating = false;
+ mTouchDragOffset = 0;
+ mGrabbedState = RotarySelector.NOTHING_GRABBED;
+ mTriggered = false;
+ }
+
+ /**
+ * Triggers haptic feedback.
+ */
+ private synchronized void vibrate(long duration) {
+ if (mVibrator == null) {
+ mVibrator = (android.os.Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+ }
+ mVibrator.vibrate(duration);
+ }
+
+ /**
+ * Sets the bounds of the specified Drawable so that it's centered
+ * on the point (x,y), then draws it onto the specified canvas.
+ * TODO: is there already a utility method somewhere for this?
+ */
+ private static void drawCentered(Drawable d, Canvas c, int x, int y) {
+ int w = d.getIntrinsicWidth();
+ int h = d.getIntrinsicHeight();
+
+ // if (DBG) log("--> drawCentered: " + x + " , " + y + "; intrinsic " + w + " x " + h);
+ d.setBounds(x - (w / 2), y - (h / 2),
+ x + (w / 2), y + (h / 2));
+ d.draw(c);
+ }
+
+
+ /**
+ * Registers a callback to be invoked when the dial
+ * is "triggered" by rotating it one way or the other.
+ *
+ * @param l the OnDialTriggerListener to attach to this view
+ */
+ public void setOnDialTriggerListener(OnDialTriggerListener l) {
+ mOnDialTriggerListener = l;
+ }
+
+ /**
+ * Dispatches a trigger event to our listener.
+ */
+ private boolean dispatchTriggerEvent(int whichHandle) {
+ vibrate(VIBRATE_LONG);
+ if (mOnDialTriggerListener != null) {
+ return mOnDialTriggerListener.onDialTrigger(this, whichHandle);
+ }
+ return false;
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the dial
+ * is "triggered" by rotating it one way or the other.
+ */
+ public interface OnDialTriggerListener {
+ /**
+ * The dial was triggered because the user grabbed the left handle,
+ * and rotated the dial clockwise.
+ */
+ public static final int LEFT_HANDLE = 1;
+
+ /**
+ * The dial was triggered because the user grabbed the right handle,
+ * and rotated the dial counterclockwise.
+ */
+ public static final int RIGHT_HANDLE = 2;
+
+ /**
+ * @hide
+ * The center handle is currently unused.
+ */
+ public static final int CENTER_HANDLE = 3;
+
+ /**
+ * Called when the dial is triggered.
+ *
+ * @param v The view that was triggered
+ * @param whichHandle Which "dial handle" the user grabbed,
+ * either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}, or
+ * {@link #CENTER_HANDLE}.
+ * @return Whether the widget should freeze (e.g when the action goes to another screen,
+ * you want the UI to stay put until the transition occurs).
+ */
+ boolean onDialTrigger(View v, int whichHandle);
+ }
+
+
+ // Debugging / testing code
+
+ private void log(String msg) {
+ Log.d(LOG_TAG, msg);
+ }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 53e0125..c4536be 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -52,6 +52,23 @@
<protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
<protected-broadcast android:name="android.intent.action.REBOOT" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
+ <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.NAME_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.NAME_FAILED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
+ <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
+
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
<!-- ====================================== -->
diff --git a/core/res/res/drawable/ic_jog_dial_answer.png b/core/res/res/drawable/ic_jog_dial_answer.png
new file mode 100644
index 0000000..e2bc483
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_answer.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_decline.png b/core/res/res/drawable/ic_jog_dial_decline.png
new file mode 100644
index 0000000..81c76b5
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_decline.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_silence_ringer.png b/core/res/res/drawable/ic_jog_dial_silence_ringer.png
new file mode 100644
index 0000000..6d573e6
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_silence_ringer.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png
new file mode 100644
index 0000000..3804c25
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png
new file mode 100644
index 0000000..62f8e15
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_unlock.png b/core/res/res/drawable/ic_jog_dial_unlock.png
new file mode 100644
index 0000000..e697d91
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_unlock.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_left_green.png b/core/res/res/drawable/jog_dial_arrow_long_left_green.png
new file mode 100644
index 0000000..334a8e0
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_left_green.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png
new file mode 100644
index 0000000..2e011ca3
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png
new file mode 100644
index 0000000..323745e
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_right_red.png b/core/res/res/drawable/jog_dial_arrow_long_right_red.png
new file mode 100644
index 0000000..1e97c9a
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_right_red.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png
new file mode 100644
index 0000000..3536e58
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_short_left.png b/core/res/res/drawable/jog_dial_arrow_short_left.png
new file mode 100644
index 0000000..4a4ab3ae
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_short_left.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png b/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png
new file mode 100644
index 0000000..987cfa7
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_short_right.png b/core/res/res/drawable/jog_dial_arrow_short_right.png
new file mode 100644
index 0000000..ee79875
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_short_right.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_bg_cropped.png b/core/res/res/drawable/jog_dial_bg_cropped.png
new file mode 100644
index 0000000..60d93d2
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_bg_cropped.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_dimple.png b/core/res/res/drawable/jog_dial_dimple.png
new file mode 100644
index 0000000..85d3a43
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_dimple.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_rotary_unlock.xml b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
new file mode 100644
index 0000000..cf97d04
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is the general lock screen which shows information about the
+ state of the device, as well as instructions on how to get past it
+ depending on the state of the device. It is the same for landscape
+ and portrait.-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/root"
+ >
+
+<RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="#A0000000"
+ >
+
+ <TextView
+ android:id="@+id/carrier"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="20dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ />
+
+ <TextView
+ android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/carrier"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="25dip"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="55sp"
+ />
+
+ <TextView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/time"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="-12dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:layout_marginTop="10dip"
+ android:layout_below="@id/date"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+
+ <TextView
+ android:id="@+id/status1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/divider"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="6dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ />
+
+ <TextView
+ android:id="@+id/status2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/status1"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="6dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ />
+
+ <TextView
+ android:id="@+id/screenLocked"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/status2"
+ android:layout_centerHorizontal="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorSecondary"
+ android:gravity="center"
+ android:layout_marginTop="12dip"
+ />
+
+ <!-- By having the rotary selector hang below "screen locked" text, we get a layout more
+ robust for different screen sizes. On wvga, the widget should be flush with the bottom.-->
+ <com.android.internal.widget.RotarySelector
+ android:id="@+id/rotary"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/screenLocked"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="24dip"
+ />
+
+ <!-- emergency call button shown when sim is missing or PUKd -->
+ <Button
+ android:id="@+id/emergencyCallButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/screenLocked"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="24dip"
+ android:drawableLeft="@drawable/ic_emergency"
+ android:drawablePadding="8dip"
+ />
+
+</RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 560796a..62a230c 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -24,7 +24,14 @@
<drawable name="status_bar_opened_default_background">#ff000000</drawable>
<drawable name="search_bar_default_color">#ff000000</drawable>
<drawable name="safe_mode_background">#60000000</drawable>
+ <!-- Background drawable that can be used for a transparent activity to
+ be able to display a dark UI: this darkens its background to make
+ a dark (default theme) UI more visible. -->
<drawable name="screen_background_dark_transparent">#80000000</drawable>
+ <!-- Background drawable that can be used for a transparent activity to
+ be able to display a light UI: this lightens its background to make
+ a light UI more visible. -->
+ <drawable name="screen_background_light_transparent">#80ffffff</drawable>
<color name="safe_mode_text">#80ffffff</color>
<color name="white">#ffffffff</color>
<color name="black">#ff000000</color>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c4636f3..2bc2a0f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1168,10 +1168,13 @@
<public type="style" name="Theme.Wallpaper" />
<public type="style" name="Theme.Wallpaper.NoTitleBar" />
<public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />
+ <public type="style" name="Theme.WallpaperSettings" />
+ <public type="style" name="Theme.Light.WallpaperSettings" />
<!-- Semi-transparent background that can be used when placing a dark
themed UI on top of some arbitrary background (such as the
wallpaper). This darkens the background sufficiently that the UI
can be seen. -->
<public type="drawable" name="screen_background_dark_transparent" />
+ <public type="drawable" name="screen_background_light_transparent" />
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index fae612c..69612e9 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -458,7 +458,6 @@
<style name="Widget.ListView.White" parent="Widget.AbsListView">
<item name="android:listSelector">@android:drawable/list_selector_background</item>
- <item name="android:background">@android:color/white</item>
<item name="android:divider">@android:drawable/divider_horizontal_bright_opaque</item>
</style>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 4f76c56..1aa48ee 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -303,6 +303,32 @@
<item name="android:windowContentOverlay">@null</item>
</style>
+ <!-- Theme for a wallpaper's setting activity that is designed to be on
+ top of a dark background. -->
+ <style name="Theme.WallpaperSettings">
+ <item name="android:windowBackground">@android:drawable/screen_background_dark_transparent</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
+ </style>
+
+ <!-- Theme for a wallpaper's setting activity that is designed to be on
+ top of a light background. -->
+ <style name="Theme.Light.WallpaperSettings">
+ <item name="android:windowBackground">@android:drawable/screen_background_light_transparent</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
+ </style>
+
+ <!-- Style to apply on top of a wallpaper settings theme when it is being
+ shown on top of the real wallpaper -->
+ <style name="ActiveWallpaperSettings">
+ </style>
+
+ <!-- Style to apply on top of a wallpaper settings theme when it is being
+ shown on top of the real wallpaper -->
+ <style name="PreviewWallpaperSettings">
+ </style>
+
<!-- Default theme for translucent activities, that is windows that allow you
to see through them to the windows behind. This sets up the translucent
flag and appropriate animations for your windows. -->
diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.0_r1/requirements.jd
index af06675..4163513 100644
--- a/docs/html/sdk/1.0_r1/requirements.jd
+++ b/docs/html/sdk/1.0_r1/requirements.jd
@@ -14,7 +14,13 @@
<ul>
<li>Windows XP or Vista</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
- <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+ <li>Linux (tested on Linux Ubuntu Dapper Drake)
+ <ul>
+ <li>64-bit distributions must be capable of running 32-bit applications.
+ For information about how to add support for 32-bit applications, see
+ the <a href="installing.html#installnotes">Installation Notes</a>.</li>
+ </ul>
+ </li>
</ul>
<h4>Supported Development Environments:</h4>
diff --git a/docs/html/sdk/1.0_r2/requirements.jd b/docs/html/sdk/1.0_r2/requirements.jd
index 74d90ef..4f7c093 100644
--- a/docs/html/sdk/1.0_r2/requirements.jd
+++ b/docs/html/sdk/1.0_r2/requirements.jd
@@ -13,7 +13,13 @@
<ul>
<li>Windows XP or Vista</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
- <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+ <li>Linux (tested on Linux Ubuntu Dapper Drake)
+ <ul>
+ <li>64-bit distributions must be capable of running 32-bit applications.
+ For information about how to add support for 32-bit applications, see
+ the <a href="installing.html#installnotes">Installation Notes</a>.</li>
+ </ul>
+ </li>
</ul>
<h4>Supported Development Environments:</h4>
diff --git a/docs/html/sdk/1.1_r1/requirements.jd b/docs/html/sdk/1.1_r1/requirements.jd
index 95b658b..9d8f9eb 100644
--- a/docs/html/sdk/1.1_r1/requirements.jd
+++ b/docs/html/sdk/1.1_r1/requirements.jd
@@ -11,7 +11,13 @@
<ul>
<li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
- <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+ <li>Linux (tested on Linux Ubuntu Dapper Drake)
+ <ul>
+ <li>64-bit distributions must be capable of running 32-bit applications.
+ For information about how to add support for 32-bit applications, see
+ the <a href="installing.html#installnotes">Installation Notes</a>.</li>
+ </ul>
+ </li>
</ul>
<h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.5_r1/requirements.jd b/docs/html/sdk/1.5_r1/requirements.jd
index 4ed38a7..c10ccac 100644
--- a/docs/html/sdk/1.5_r1/requirements.jd
+++ b/docs/html/sdk/1.5_r1/requirements.jd
@@ -7,7 +7,13 @@
<ul>
<li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
- <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+ <li>Linux (tested on Linux Ubuntu Dapper Drake)
+ <ul>
+ <li>64-bit distributions must be capable of running 32-bit applications.
+ For information about how to add support for 32-bit applications, see
+ the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+ </ul>
+ </li>
</ul>
<h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.5_r2/requirements.jd b/docs/html/sdk/1.5_r2/requirements.jd
index 4ed38a7..c10ccac 100644
--- a/docs/html/sdk/1.5_r2/requirements.jd
+++ b/docs/html/sdk/1.5_r2/requirements.jd
@@ -7,7 +7,13 @@
<ul>
<li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
- <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+ <li>Linux (tested on Linux Ubuntu Dapper Drake)
+ <ul>
+ <li>64-bit distributions must be capable of running 32-bit applications.
+ For information about how to add support for 32-bit applications, see
+ the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+ </ul>
+ </li>
</ul>
<h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.5_r3/requirements.jd b/docs/html/sdk/1.5_r3/requirements.jd
index 5f20cf1..5bcee27 100644
--- a/docs/html/sdk/1.5_r3/requirements.jd
+++ b/docs/html/sdk/1.5_r3/requirements.jd
@@ -10,7 +10,13 @@
<ul>
<li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
- <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+ <li>Linux (tested on Linux Ubuntu Dapper Drake)
+ <ul>
+ <li>64-bit distributions must be capable of running 32-bit applications.
+ For information about how to add support for 32-bit applications, see
+ the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+ </ul>
+ </li>
</ul>
<h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.6_r1/requirements.jd b/docs/html/sdk/1.6_r1/requirements.jd
index 8e698fa..8cfc049 100644
--- a/docs/html/sdk/1.6_r1/requirements.jd
+++ b/docs/html/sdk/1.6_r1/requirements.jd
@@ -11,7 +11,13 @@
<ul>
<li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
<li>Mac OS X 10.4.8 or later (x86 only)</li>
- <li>Linux (tested on Linux Ubuntu Hardy Heron)</li>
+ <li>Linux (tested on Linux Ubuntu Hardy Heron)
+ <ul>
+ <li>64-bit distributions must be capable of running 32-bit applications.
+ For information about how to add support for 32-bit applications, see
+ the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+ </ul>
+ </li>
</ul>
<h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/RELEASENOTES.jd b/docs/html/sdk/RELEASENOTES.jd
index 130a92c..0dcafd3 100644
--- a/docs/html/sdk/RELEASENOTES.jd
+++ b/docs/html/sdk/RELEASENOTES.jd
@@ -24,6 +24,11 @@
Devices</a> and download new SDK packages (such as platform versions and
add-ons) into your environment.</li>
<li>Improved support for test packages in New Project Wizard</li>
+ <li>The reference documentation now offers a "Filter by API Level"
+capability that lets you display only the parts of the API that are actually
+available to your application, based on the <code>android:minSdkVersion</code>
+value the application declares in its manifest. For more information, see
+<a href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a></li>
</ul>
<p>For details about the Android platforms included in the SDK — including
@@ -71,8 +76,8 @@
<h3>Android SDK and AVD Manager</h3>
-<p>The SDK offers a new tool called Android AVD Manager that lets you manage
-your SDK and AVD environments more efficiently. </p>
+<p>The SDK offers a new tool called Android SDK and AVD Manager that lets you
+manage your SDK and AVD environments more efficiently. </p>
<p>Using the tool, you can quickly check what Android platforms, add-ons,
extras, and documentation packages are available in your SDK environment, what
@@ -181,7 +186,7 @@
<p>Besides these defaults, You can also create an AVD that overrides the default
density for each skin, to create any combination of resolution/density (WVGA
with medium density, for instance). To do so, use the <code>android</code> tool
-command line to create a new AVD that uses a custom hardare configuration. See
+command line to create a new AVD that uses a custom hardware configuration. See
<a href="{@docRoot}guide/developing/tools/avd.html#createavd">Creating an
AVD</a> for more information.</p>
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index e82f297..f42788e 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -271,7 +271,8 @@
public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
final BitmapState state = mBitmapState;
- if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
+ if (state.mPaint.getShader() == null ||
+ state.mTileModeX != xmode || state.mTileModeY != ymode) {
state.mTileModeX = xmode;
state.mTileModeY = ymode;
mRebuildShader = true;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 0014d5c..10e0197 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -25,6 +25,8 @@
#include <OMX_Core.h>
#include <OMX_Video.h>
+#include "jni.h"
+
namespace android {
class IMemory;
@@ -102,15 +104,22 @@
size_t encodedWidth, size_t encodedHeight,
size_t displayWidth, size_t displayHeight) = 0;
- // Note: This method is _not_ virtual, it exists as a wrapper around
+ // Note: These methods are _not_ virtual, it exists as a wrapper around
// the virtual "createRenderer" method above facilitating extraction
- // of the ISurface from a regular Surface.
+ // of the ISurface from a regular Surface or a java Surface object.
sp<IOMXRenderer> createRenderer(
const sp<Surface> &surface,
const char *componentName,
OMX_COLOR_FORMATTYPE colorFormat,
size_t encodedWidth, size_t encodedHeight,
size_t displayWidth, size_t displayHeight);
+
+ sp<IOMXRenderer> createRendererFromJavaSurface(
+ JNIEnv *env, jobject javaSurface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight);
};
struct omx_message {
diff --git a/include/media/stagefright/SoftwareRenderer.h b/include/media/stagefright/SoftwareRenderer.h
index 705b914..b61858c 100644
--- a/include/media/stagefright/SoftwareRenderer.h
+++ b/include/media/stagefright/SoftwareRenderer.h
@@ -18,6 +18,7 @@
#define SOFTWARE_RENDERER_H_
+#include <OMX_Video.h>
#include <media/stagefright/VideoRenderer.h>
#include <utils/RefBase.h>
@@ -29,6 +30,7 @@
class SoftwareRenderer : public VideoRenderer {
public:
SoftwareRenderer(
+ OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight);
@@ -39,6 +41,12 @@
const void *data, size_t size, void *platformPrivate);
private:
+ uint8_t *initClip();
+
+ void renderCbYCrY(const void *data, size_t size);
+ void renderYUV420Planar(const void *data, size_t size);
+
+ OMX_COLOR_FORMATTYPE mColorFormat;
sp<ISurface> mISurface;
size_t mDisplayWidth, mDisplayHeight;
size_t mDecodedWidth, mDecodedHeight;
@@ -46,6 +54,8 @@
sp<MemoryHeapBase> mMemoryHeap;
int mIndex;
+ uint8_t *mClip;
+
SoftwareRenderer(const SoftwareRenderer &);
SoftwareRenderer &operator=(const SoftwareRenderer &);
};
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 118fb83..2cedeb6 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -212,7 +212,7 @@
void setUsage(uint32_t reqUsage);
- bool getUsage(uint32_t* usage);
+ uint32_t getUsage() const;
// constants
sp<SurfaceComposerClient> mClient;
@@ -227,7 +227,6 @@
// protected by mSurfaceLock
Rect mSwapRectangle;
uint32_t mUsage;
- int32_t mUsageChanged;
// protected by mSurfaceLock. These are also used from lock/unlock
// but in that case, they must be called form the same thread.
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index bbfc54b9..38a897d 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -607,9 +607,10 @@
void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
{
+ // this would be where the color-key would be set, should we need it.
GLclampx red = 0;
GLclampx green = 0;
- GLclampx blue = 0x1818;
+ GLclampx blue = 0;
mLayer.clearWithOpenGL(clip, red, green, blue, 0);
}
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index c3fbea2..64522fb 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -361,7 +361,6 @@
const_cast<uint32_t&>(android_native_window_t::flags) = 0;
// be default we request a hardware surface
mUsage = GRALLOC_USAGE_HW_RENDER;
- mUsageChanged = true;
mNeedFullUpdate = false;
}
@@ -498,14 +497,14 @@
LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
return bufIdx;
}
-
- // FIXME: in case of failure below, we need to undo the dequeue
-
- uint32_t usage;
- const bool usageChanged = getUsage(&usage);
+
+ // below we make sure we AT LEAST have the usage flags we want
+ const uint32_t usage(getUsage());
const sp<SurfaceBuffer>& backBuffer(mBuffers[bufIdx]);
- if ((backBuffer == 0) || usageChanged ||
- mSharedBufferClient->needNewBuffer(bufIdx)) {
+ if (backBuffer == 0 ||
+ ((uint32_t(backBuffer->usage) & usage) != usage) ||
+ mSharedBufferClient->needNewBuffer(bufIdx))
+ {
err = getBufferLocked(bufIdx, usage);
LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)",
bufIdx, usage, strerror(-err));
@@ -600,21 +599,13 @@
void Surface::setUsage(uint32_t reqUsage)
{
Mutex::Autolock _l(mSurfaceLock);
- if (mUsage != reqUsage) {
- mUsageChanged = true;
- mUsage = reqUsage;
- }
+ mUsage = reqUsage;
}
-bool Surface::getUsage(uint32_t* usage)
+uint32_t Surface::getUsage() const
{
Mutex::Autolock _l(mSurfaceLock);
- *usage = mUsage;
- if (mUsageChanged) {
- mUsageChanged = false;
- return true;
- }
- return false;
+ return mUsage;
}
// ----------------------------------------------------------------------------
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 9d442c3..7c01687 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -37,6 +37,7 @@
endif
LOCAL_C_INCLUDES := \
+ $(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 10bebd0..0cec7bb 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -45,6 +45,31 @@
displayWidth, displayHeight);
}
+sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
+ JNIEnv *env, jobject javaSurface,
+ const char *componentName,
+ OMX_COLOR_FORMATTYPE colorFormat,
+ size_t encodedWidth, size_t encodedHeight,
+ size_t displayWidth, size_t displayHeight) {
+ jclass surfaceClass = env->FindClass("android/view/Surface");
+ if (surfaceClass == NULL) {
+ LOGE("Can't find android/view/Surface");
+ return NULL;
+ }
+
+ jfieldID surfaceID = env->GetFieldID(surfaceClass, "mSurface", "I");
+ if (surfaceID == NULL) {
+ LOGE("Can't find Surface.mSurface");
+ return NULL;
+ }
+
+ sp<Surface> surface = (Surface *)env->GetIntField(javaSurface, surfaceID);
+
+ return createRenderer(
+ surface, componentName, colorFormat, encodedWidth,
+ encodedHeight, displayWidth, displayHeight);
+}
+
class BpOMX : public BpInterface<IOMX> {
public:
BpOMX(const sp<IBinder> &impl)
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 93b7a3a..f21eb73 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -47,6 +47,7 @@
endif
LOCAL_C_INCLUDES := external/tremor/Tremor \
+ $(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
$(TOP)/frameworks/base/media/libstagefright/omx
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 79a32b5..3c343a3 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -38,6 +38,7 @@
endif
LOCAL_C_INCLUDES:= \
+ $(JNI_H_INCLUDE) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
$(TOP)/external/opencore/android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 22c2f39..ba4c4c7 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -229,6 +229,7 @@
}
if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
// XXX Required on P....on only.
+ quirks |= kRequiresAllocateBufferOnInputPorts;
quirks |= kRequiresAllocateBufferOnOutputPorts;
}
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 77e42be..4cadccd 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -7,6 +7,7 @@
LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
LOCAL_C_INCLUDES += $(TOP)/hardware/ti/omap3/liboverlay
+LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_SRC_FILES:= \
OMX.cpp \
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 1e59b52..8b83dd6 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -609,6 +609,7 @@
} else {
LOGW("Using software renderer.");
impl = new SoftwareRenderer(
+ colorFormat,
surface,
displayWidth, displayHeight,
encodedWidth, encodedHeight);
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index da97d55..a1c478f 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -27,17 +27,20 @@
#define QCOM_YUV 0
SoftwareRenderer::SoftwareRenderer(
+ OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight)
- : mISurface(surface),
+ : mColorFormat(colorFormat),
+ mISurface(surface),
mDisplayWidth(displayWidth),
mDisplayHeight(displayHeight),
mDecodedWidth(decodedWidth),
mDecodedHeight(decodedHeight),
mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565
mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
- mIndex(0) {
+ mIndex(0),
+ mClip(NULL) {
CHECK(mISurface.get() != NULL);
CHECK(mDecodedWidth > 0);
CHECK(mDecodedHeight > 0);
@@ -55,29 +58,37 @@
SoftwareRenderer::~SoftwareRenderer() {
mISurface->unregisterBuffers();
+
+ delete[] mClip;
+ mClip = NULL;
}
void SoftwareRenderer::render(
const void *data, size_t size, void *platformPrivate) {
+ switch (mColorFormat) {
+ case OMX_COLOR_FormatYUV420Planar:
+ return renderYUV420Planar(data, size);
+
+ case OMX_COLOR_FormatCbYCrY:
+ return renderCbYCrY(data, size);
+
+ default:
+ {
+ LOGW("Cannot render color format %ld", mColorFormat);
+ break;
+ }
+ }
+}
+
+void SoftwareRenderer::renderYUV420Planar(
+ const void *data, size_t size) {
if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
LOGE("size is %d, expected %d",
size, (mDecodedHeight * mDecodedWidth * 3) / 2);
}
CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
- static const signed kClipMin = -278;
- static const signed kClipMax = 535;
- static uint8_t kClip[kClipMax - kClipMin + 1];
- static uint8_t *kAdjustedClip = &kClip[-kClipMin];
-
- static bool clipInitialized = false;
-
- if (!clipInitialized) {
- for (signed i = kClipMin; i <= kClipMax; ++i) {
- kClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
- }
- clipInitialized = true;
- }
+ uint8_t *kAdjustedClip = initClip();
size_t offset = mIndex * mFrameSize;
@@ -172,4 +183,78 @@
mIndex = 1 - mIndex;
}
+void SoftwareRenderer::renderCbYCrY(
+ const void *data, size_t size) {
+ if (size != (mDecodedHeight * mDecodedWidth * 2)) {
+ LOGE("size is %d, expected %d",
+ size, (mDecodedHeight * mDecodedWidth * 2));
+ }
+ CHECK(size >= (mDecodedWidth * mDecodedHeight * 2));
+
+ uint8_t *kAdjustedClip = initClip();
+
+ size_t offset = mIndex * mFrameSize;
+ void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
+ uint32_t *dst_ptr = (uint32_t *)dst;
+
+ const uint8_t *src = (const uint8_t *)data;
+
+ for (size_t y = 0; y < mDecodedHeight; ++y) {
+ for (size_t x = 0; x < mDecodedWidth; x += 2) {
+ signed y1 = (signed)src[2 * x + 1] - 16;
+ signed y2 = (signed)src[2 * x + 3] - 16;
+ signed u = (signed)src[2 * x] - 128;
+ signed v = (signed)src[2 * x + 2] - 128;
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = (tmp1 + u_b) / 256;
+ signed g1 = (tmp1 + v_g + u_g) / 256;
+ signed r1 = (tmp1 + v_r) / 256;
+
+ signed tmp2 = y2 * 298;
+ signed b2 = (tmp2 + u_b) / 256;
+ signed g2 = (tmp2 + v_g + u_g) / 256;
+ signed r2 = (tmp2 + v_r) / 256;
+
+ uint32_t rgb1 =
+ ((kAdjustedClip[r1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[b1] >> 3);
+
+ uint32_t rgb2 =
+ ((kAdjustedClip[r2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[b2] >> 3);
+
+ dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ }
+
+ src += mDecodedWidth * 2;
+ dst_ptr += mDecodedWidth / 2;
+ }
+
+ mISurface->postBuffer(offset);
+ mIndex = 1 - mIndex;
+}
+
+uint8_t *SoftwareRenderer::initClip() {
+ static const signed kClipMin = -278;
+ static const signed kClipMax = 535;
+
+ if (mClip == NULL) {
+ mClip = new uint8_t[kClipMax - kClipMin + 1];
+
+ for (signed i = kClipMin; i <= kClipMax; ++i) {
+ mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
+ }
+ }
+
+ return &mClip[-kClipMin];
+}
+
} // namespace android
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
new file mode 100644
index 0000000..0401390
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -0,0 +1,84 @@
+package com.android.mediaframeworktest;
+
+import android.media.MediaRecorder;
+import android.os.SystemProperties;
+import java.util.HashMap;
+
+public class MediaProfileReader {
+
+ public static final HashMap<String, Integer>
+ OUTPUT_FORMAT_TABLE = new HashMap<String, Integer>();
+ public static String MEDIA_ENC_VID = "ro.media.enc.vid.";
+ public static String MEDIA_AUD_VID = "ro.media.enc.aud.";
+ public static String[] VIDEO_ENCODER_PROPERTY = {".width", ".height", ".bps", ".fps",};
+ public static String[] AUDIO_ENCODER_PROPERTY = {".bps", ".hz", ".ch",};
+
+ public static String getVideoCodecProperty() {
+ String s;
+ s = SystemProperties.get("ro.media.enc.vid.codec");
+ return s;
+ }
+
+ public static String getAudioCodecProperty() {
+ String s;
+ s = SystemProperties.get("ro.media.enc.aud.codec");
+ return s;
+ }
+
+ public static String getDeviceType() {
+ // push all the property into one big table
+ String s;
+ s = SystemProperties.get("ro.product.name");
+ return s;
+ }
+
+ public static void createVideoProfileTable() {
+ // push all the property into one big table
+ String encoderType = getVideoCodecProperty();
+ String encoder[] = encoderType.split(",");
+ for (int i = 0; i < encoder.length; i++) {
+ for (int j = 0; j < VIDEO_ENCODER_PROPERTY.length; j++) {
+ String propertyName = MEDIA_ENC_VID + encoder[i] + VIDEO_ENCODER_PROPERTY[j];
+ String prop = SystemProperties.get(propertyName);
+ //push to the table
+ String propRange[] = prop.split(",");
+ OUTPUT_FORMAT_TABLE.put((encoder[i] + VIDEO_ENCODER_PROPERTY[j] + "_low"),
+ Integer.parseInt(propRange[0]));
+ OUTPUT_FORMAT_TABLE.put((encoder[i] + VIDEO_ENCODER_PROPERTY[j] + "_high"),
+ Integer.parseInt(propRange[1]));
+ }
+
+ }
+ }
+
+ public static void createAudioProfileTable() {
+ // push all the property into one big table
+ String audioType = getAudioCodecProperty();
+ String encoder[] = audioType.split(",");
+ for (int i = 0; i < encoder.length; i++) {
+ for (int j = 0; j < AUDIO_ENCODER_PROPERTY.length; j++) {
+ String propertyName = MEDIA_AUD_VID + encoder[i] + AUDIO_ENCODER_PROPERTY[j];
+ String prop = SystemProperties.get(propertyName);
+ //push to the table
+ String propRange[] = prop.split(",");
+ OUTPUT_FORMAT_TABLE.put((encoder[i] + AUDIO_ENCODER_PROPERTY[j] + "_low"),
+ Integer.parseInt(propRange[0]));
+ OUTPUT_FORMAT_TABLE.put((encoder[i] + AUDIO_ENCODER_PROPERTY[j] + "_high"),
+ Integer.parseInt(propRange[1]));
+ }
+
+ }
+ }
+
+ public static void createEncoderTable(){
+ OUTPUT_FORMAT_TABLE.put("h263", MediaRecorder.VideoEncoder.H263);
+ OUTPUT_FORMAT_TABLE.put("h264", MediaRecorder.VideoEncoder.H264);
+ OUTPUT_FORMAT_TABLE.put("m4v", MediaRecorder.VideoEncoder.MPEG_4_SP);
+ OUTPUT_FORMAT_TABLE.put("amrnb", MediaRecorder.AudioEncoder.AMR_NB);
+ OUTPUT_FORMAT_TABLE.put("amrwb", MediaRecorder.AudioEncoder.AMR_WB);
+ OUTPUT_FORMAT_TABLE.put("aac", MediaRecorder.AudioEncoder.AAC);
+ OUTPUT_FORMAT_TABLE.put("aacplus", MediaRecorder.AudioEncoder.AAC_PLUS);
+ OUTPUT_FORMAT_TABLE.put("eaacplus",
+ MediaRecorder.AudioEncoder.EAAC_PLUS);
+ }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index ef0a3b1..39846c6 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -29,7 +29,7 @@
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-
+import com.android.mediaframeworktest.MediaProfileReader;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
@@ -46,6 +46,9 @@
private SurfaceHolder mSurfaceHolder = null;
private MediaRecorder mRecorder;
+
+ private int MIN_VIDEO_FPS = 5;
+
Context mContext;
Camera mCamera;
@@ -96,7 +99,70 @@
}
}
-
+ private boolean recordVideoWithPara(String encoder, String audio, String quality){
+ boolean recordSuccess = false;
+ int videoEncoder = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder);
+ int audioEncoder = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio);
+ int videoWidth = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".width_" + quality);
+ int videoHeight =
+ MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".height_" + quality);
+ int videoFps = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".fps_" + quality);
+ int videoBitrate = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".bps_" + quality);
+ int audioBitrate = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio + ".bps_" + quality);
+ int audioChannels = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio + ".ch_" + quality);
+ int audioSamplingRate =
+ MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio + ".hz_" + quality);
+
+ if (videoFps < MIN_VIDEO_FPS) {
+ videoFps = MIN_VIDEO_FPS;
+ }
+ mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
+ String filename = ("/sdcard/" + encoder + "_" + audio + "_" + quality + ".3gp");
+ try {
+ Log.v(TAG, "video encoder :" + videoEncoder);
+ Log.v(TAG, "audio encoder :" + audioEncoder);
+ Log.v(TAG, "quality : " + quality);
+ Log.v(TAG, "encoder : " + encoder);
+ Log.v(TAG, "audio : " + audio);
+ Log.v(TAG, "videoWidth : " + videoWidth);
+ Log.v(TAG, "videoHeight : " + videoHeight);
+ Log.v(TAG, "videoFPS : " + videoFps);
+ Log.v(TAG, "videobitrate : " + videoBitrate);
+ Log.v(TAG, "audioBitrate : " + audioBitrate);
+ Log.v(TAG, "audioChannel : " + audioChannels);
+ Log.v(TAG, "AudioSampleRate : " + audioSamplingRate);
+
+ MediaRecorder mMediaRecorder = new MediaRecorder();
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
+ mMediaRecorder.setOutputFile(filename);
+ mMediaRecorder.setVideoFrameRate(videoFps);
+ mMediaRecorder.setVideoSize(videoWidth, videoHeight);
+ mMediaRecorder.setParameters(String.format("video-param-encoding-bitrate=%d",
+ videoBitrate));
+ mMediaRecorder.setParameters(String.format("audio-param-encoding-bitrate=%d",
+ audioBitrate));
+ mMediaRecorder.setParameters(String.format("audio-param-number-of-channels=%d",
+ audioChannels));
+ mMediaRecorder.setParameters(String.format("audio-param-sampling-rate=%d",
+ audioSamplingRate));
+ mMediaRecorder.setVideoEncoder(videoEncoder);
+ mMediaRecorder.setAudioEncoder(audioEncoder);
+ mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
+ mMediaRecorder.prepare();
+ mMediaRecorder.start();
+ Thread.sleep(MediaNames.RECORDED_TIME);
+ mMediaRecorder.stop();
+ mMediaRecorder.release();
+ recordSuccess = validateVideo(filename, videoWidth, videoHeight);
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ return false;
+ }
+ return recordSuccess;
+ }
+
private boolean invalidRecordSetting(int frameRate, int width, int height,
int videoFormat, int outFormat, String outFile, boolean videoOnly) {
try {
@@ -356,6 +422,35 @@
MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false);
assertTrue("Invalid FrameRate", isTestInvalidFrameRateSuccessful);
}
-
+
+ @LargeTest
+ //est cases for the new codec
+ public void testDeviceSpecificCodec() throws Exception {
+ boolean recordSuccess = false;
+ String deviceType = MediaProfileReader.getDeviceType();
+ Log.v(TAG, "deviceType = " + deviceType);
+ if (deviceType.compareTo("voles") == 0) {
+ // Test cases are device specified
+ MediaProfileReader.createVideoProfileTable();
+ MediaProfileReader.createAudioProfileTable();
+ MediaProfileReader.createEncoderTable();
+ String encoderType = MediaProfileReader.getVideoCodecProperty();
+ String encoder[] = encoderType.split(",");
+ String audioType = MediaProfileReader.getAudioCodecProperty();
+ String audio[] = audioType.split(",");
+ for (int k = 0; k < 2; k++) {
+ for (int i = 0; i < encoder.length; i++) {
+ for (int j = 0; j < audio.length; j++) {
+ if (k == 0) {
+ recordSuccess = recordVideoWithPara(encoder[i], audio[j], "high");
+ } else {
+ recordSuccess = recordVideoWithPara(encoder[i], audio[j], "low");
+ }
+ assertTrue((encoder[i] + audio[j]), recordSuccess);
+ }
+ }
+ }
+ }
+ }
}
diff --git a/preloaded-classes b/preloaded-classes
index 3da4797..8c5e835 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -724,6 +724,7 @@
com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatAttribute
com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatSymbol
com.ibm.icu4jni.text.RuleBasedCollator
+com.ibm.icu4jni.util.Resources$DefaultTimeZones
dalvik.system.DexFile
dalvik.system.PathClassLoader
java.beans.PropertyChangeEvent
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 8e85a6a..bd2c3ed 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -1244,12 +1244,6 @@
"Skipping hidden or animating token: " + w);
continue;
}
- // If this window's app token is ot fullscreen, also irrelevant.
- if (!w.mAppToken.appFullscreen) {
- if (DEBUG_WALLPAPER) Log.v(TAG,
- "Skipping non-fullscreen token: " + w);
- continue;
- }
}
if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w + ": readyfordisplay="
+ w.isReadyForDisplay() + " drawpending=" + w.mDrawPending
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index d680b8a..83552dd 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -1490,10 +1490,13 @@
/// ---------- Expanded View --------------
pixelFormat = PixelFormat.TRANSLUCENT;
- if (false) {
- bg = mExpandedView.getBackground();
- if (bg != null) {
- pixelFormat = bg.getOpacity();
+ bg = mExpandedView.getBackground();
+ if (bg != null) {
+ pixelFormat = bg.getOpacity();
+ if (pixelFormat != PixelFormat.TRANSLUCENT) {
+ // we want good-looking gradients, so we force a 8-bits per
+ // pixel format.
+ pixelFormat = PixelFormat.RGBX_8888;
}
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index e1bd1db..c8490e9 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -100,10 +100,14 @@
public Drawable cachedPhoto;
public boolean isCachedPhotoCurrent;
+ private boolean mIsEmergency;
+
// Don't keep checking VM if it's going to throw an exception for this proc.
private static boolean sSkipVmCheck = false;
public CallerInfo() {
+ // TODO: Move all the basic initialization here?
+ mIsEmergency = false;
}
/**
@@ -221,13 +225,7 @@
// or if it is the voicemail number. If it is either, take a
// shortcut and skip the query.
if (PhoneNumberUtils.isEmergencyNumber(number)) {
- CallerInfo ci = new CallerInfo();
-
- // Note we're setting the phone number here (refer to javadoc
- // comments at the top of CallerInfo class).
- ci.phoneNumber = context.getString(
- com.android.internal.R.string.emergency_call_dialog_number_for_display);
- return ci;
+ return new CallerInfo().markAsEmergency(context);
} else {
try {
if (!sSkipVmCheck && PhoneNumberUtils.compare(number,
@@ -296,6 +294,35 @@
return callerID;
}
+ // Accessors
+
+ /**
+ * @return true if the caller info is an emergency number.
+ */
+ public boolean isEmergencyNumber() {
+ return mIsEmergency;
+ }
+
+ /**
+ * Mark this CallerInfo as an emergency call.
+ * @param context To lookup the localized 'Emergency Number' string.
+ * @return this instance.
+ */
+ // TODO: Note we're setting the phone number here (refer to
+ // javadoc comments at the top of CallerInfo class) to a localized
+ // string 'Emergency Number'. This is pretty bad because we are
+ // making UI work here instead of just packaging the data. We
+ // should set the phone number to the dialed number and name to
+ // 'Emergency Number' and let the UI make the decision about what
+ // should be displayed.
+ /* package */ CallerInfo markAsEmergency(Context context) {
+ phoneNumber = context.getString(
+ com.android.internal.R.string.emergency_call_dialog_number_for_display);
+ photoResource = com.android.internal.R.drawable.picture_emergency;
+ mIsEmergency = true;
+ return this;
+ }
+
private static String normalize(String s) {
if (s == null || s.length() > 0) {
return s;
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 3d4f78c..4227a84 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -37,7 +37,7 @@
public class CallerInfoAsyncQuery {
private static final boolean DBG = false;
- private static final String LOG_TAG = "PHONE";
+ private static final String LOG_TAG = "CallerInfoAsyncQuery";
private static final int EVENT_NEW_QUERY = 1;
private static final int EVENT_ADD_LISTENER = 2;
@@ -223,13 +223,9 @@
// voicemail number, and adjust other data (including photoResource)
// accordingly.
if (cw.event == EVENT_EMERGENCY_NUMBER) {
- mCallerInfo = new CallerInfo();
// Note we're setting the phone number here (refer to javadoc
// comments at the top of CallerInfo class).
- mCallerInfo.phoneNumber = mQueryContext.getString(com.android.internal
- .R.string.emergency_call_dialog_number_for_display);
- mCallerInfo.photoResource = com.android.internal.R.drawable.picture_emergency;
-
+ mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
} else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
mCallerInfo = new CallerInfo();
try {
@@ -390,4 +386,3 @@
Log.d(LOG_TAG, msg);
}
}
-
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 806c31d..5bf1a0f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -436,7 +436,9 @@
voiceCallStartedRegistrants.notifyRegistrants (
new AsyncResult(null, null, null));
}
-
+ if (Phone.DEBUG_PHONE) {
+ log("update phone state, old= , new= , " + oldState + state);
+ }
if (state != oldState) {
phone.notifyPhoneStateChanged();
}
@@ -519,27 +521,12 @@
return;
}
} else {
- connections[i] = new CdmaConnection(phone.getContext(), dc, this, i);
-
- // it's a ringing call
- if (connections[i].getCall() == ringingCall) {
- newRinging = connections[i];
- } else {
- // Something strange happened: a call appeared
- // which is neither a ringing call or one we created.
- // Either we've crashed and re-attached to an existing
- // call, or something else (eg, SIM) initiated the call.
-
- Log.i(LOG_TAG,"Phantom call appeared " + dc);
-
- // If it's a connected call, set the connect time so that
- // it's non-zero. It may not be accurate, but at least
- // it won't appear as a Missed Call.
- if (dc.state != DriverCall.State.ALERTING
- && dc.state != DriverCall.State.DIALING) {
- connections[i].connectTime = System.currentTimeMillis();
- }
-
+ if (Phone.DEBUG_PHONE) {
+ log("pending Mo= , dc= " + pendingMO + dc);
+ }
+ // find if the MT call is a new ring or unknown connection
+ newRinging = checkMtFindNewRinging(dc,i);
+ if (newRinging == null) {
unknownConnectionAppeared = true;
}
}
@@ -571,9 +558,28 @@
// list but kept in the Call list
connections[i] = null;
} else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */
- boolean changed;
- changed = conn.update(dc);
- hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
+ // Call collision case
+ if (conn.isIncoming != dc.isMT) {
+ if (dc.isMT == true){
+ // Mt call takes precedence than Mo,drops Mo
+ droppedDuringPoll.add(conn);
+ // find if the MT call is a new ring or unknown connection
+ newRinging = checkMtFindNewRinging(dc,i);
+ if (newRinging == null) {
+ unknownConnectionAppeared = true;
+ }
+ } else {
+ // Call info stored in conn is not consistent with the call info from dc.
+ // We should follow the rule of MT calls taking precedence over MO calls
+ // when there is conflict, so here we drop the call info from dc and
+ // continue to use the call info from conn, and only take a log.
+ Log.e(LOG_TAG,"Error in RIL, Phantom call appeared " + dc);
+ }
+ } else {
+ boolean changed;
+ changed = conn.update(dc);
+ hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
+ }
}
if (REPEAT_POLLING) {
@@ -1028,6 +1034,34 @@
mIsInEmergencyCall = true;
}
}
+ /**
+ * Check the MT call to see if it's a new ring or
+ * a unknown connection.
+ */
+ private Connection checkMtFindNewRinging(DriverCall dc, int i) {
+
+ Connection newRinging = null;
+
+ connections[i] = new CdmaConnection(phone.getContext(), dc, this, i);
+ // it's a ringing call
+ if (connections[i].getCall() == ringingCall) {
+ newRinging = connections[i];
+ if (Phone.DEBUG_PHONE) log("Notify new ring " + dc);
+ } else {
+ // Something strange happened: a call which is neither
+ // a ringing call nor the one we created. It could be the
+ // call collision result from RIL
+ Log.e(LOG_TAG,"Phantom call appeared " + dc);
+ // If it's a connected call, set the connect time so that
+ // it's non-zero. It may not be accurate, but at least
+ // it won't appear as a Missed Call.
+ if (dc.state != DriverCall.State.ALERTING
+ && dc.state != DriverCall.State.DIALING) {
+ connections[i].connectTime = System.currentTimeMillis();
+ }
+ }
+ return newRinging;
+ }
/**
* Check if current call is in emergency call
diff --git a/telephony/tests/TelephonyTest/Android.mk b/telephony/tests/TelephonyTest/Android.mk
new file mode 100644
index 0000000..1ef8448
--- /dev/null
+++ b/telephony/tests/TelephonyTest/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := telephonytest
+
+include $(BUILD_PACKAGE)
diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/TelephonyTest/AndroidManifest.xml
new file mode 100644
index 0000000..c0cc0d5
--- /dev/null
+++ b/telephony/tests/TelephonyTest/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.telephonytest">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:label="TelephonyTest"
+ android:name="TelephonyTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+ <instrumentation android:name=".TelephonyUnitTestRunner"
+ android:targetPackage="com.android.telephonytest"
+ android:label="Telephony unit tests InstrumentationRunner">
+ </instrumentation>
+</manifest>
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
new file mode 100644
index 0000000..5da940d
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telephonytest;
+
+import junit.framework.TestSuite;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+/**
+ * Instrumentation Test Runner for all Telephony unit tests.
+ *
+ * Running all tests:
+ *
+ * runtest telephony-unit
+ * or
+ * adb shell am instrument -w com.android.telephonytest/.TelephonyUnitTestRunner
+ */
+
+public class TelephonyUnitTestRunner extends InstrumentationTestRunner {
+
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return TelephonyUnitTestRunner.class.getClassLoader();
+ }
+}
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
new file mode 100644
index 0000000..4cd0266
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.telephonytest.unit;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import com.android.internal.telephony.CallerInfo;
+import com.android.internal.telephony.CallerInfoAsyncQuery;
+import android.util.Log;
+import android.os.Looper;
+import android.test.ActivityInstrumentationTestCase;
+import android.util.StringBuilderPrinter;
+
+/*
+ * Check the CallerInfo utility class works as expected.
+ *
+ */
+
+public class CallerInfoUnitTest extends AndroidTestCase {
+ private CallerInfo mInfo;
+ private Context mContext;
+
+ private static final String kEmergencyNumber = "Emergency Number";
+ private static final int kToken = 0xdeadbeef;
+ private static final String TAG = "CallerInfoUnitTest";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = new MockContext();
+ mInfo = new CallerInfo();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Checks the caller info instance is flagged as an emergency if
+ * the number is an emergency one. There is no test for the
+ * contact based constructors because emergency number are not in
+ * the contact DB.
+ */
+ @SmallTest
+ public void testEmergencyIsProperlySet() throws Exception {
+ assertFalse(mInfo.isEmergencyNumber());
+
+ mInfo = CallerInfo.getCallerInfo(mContext, "911");
+ assertIsValidEmergencyCallerInfo();
+
+ mInfo = CallerInfo.getCallerInfo(mContext, "tel:911");
+ assertIsValidEmergencyCallerInfo();
+
+
+ // This one hits the content resolver.
+ mInfo = CallerInfo.getCallerInfo(mContext, "18001234567");
+ assertFalse(mInfo.isEmergencyNumber());
+ }
+
+ /**
+ * Same as testEmergencyIsProperlySet but uses the async query api.
+ */
+ @SmallTest
+ public void testEmergencyIsProperlySetUsingAsyncQuery() throws Exception {
+ QueryRunner query;
+
+ query = new QueryRunner("911");
+ query.runAndCheckCompletion();
+ assertIsValidEmergencyCallerInfo();
+
+ query = new QueryRunner("tel:911");
+ query.runAndCheckCompletion();
+ assertIsValidEmergencyCallerInfo();
+
+ query = new QueryRunner("18001234567");
+ query.runAndCheckCompletion();
+ assertFalse(mInfo.isEmergencyNumber());
+ }
+
+ /**
+ * For emergency caller info, phoneNumber should be set to the
+ * string emergency_call_dialog_number_for_display and the
+ * photoResource should be set to the picture_emergency drawable.
+ */
+ @SmallTest
+ public void testEmergencyNumberAndPhotoAreSet() throws Exception {
+ mInfo = CallerInfo.getCallerInfo(mContext, "911");
+
+ assertIsValidEmergencyCallerInfo();
+ }
+
+ //
+ // Helpers
+ //
+
+ // Partial implementation of MockResources.
+ public class MockResources extends android.test.mock.MockResources
+ {
+ @Override
+ public String getString(int resId) throws Resources.NotFoundException {
+ switch (resId) {
+ case com.android.internal.R.string.emergency_call_dialog_number_for_display:
+ return kEmergencyNumber;
+ default:
+ throw new UnsupportedOperationException("Missing handling for resid " + resId);
+ }
+ }
+ }
+
+ // Partial implementation of MockContext.
+ public class MockContext extends android.test.mock.MockContext {
+ private ContentResolver mResolver;
+ private Resources mResources;
+
+ public MockContext() {
+ mResolver = new android.test.mock.MockContentResolver();
+ mResources = new MockResources();
+ }
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mResolver;
+ }
+
+ @Override
+ public Resources getResources() {
+ return mResources;
+ }
+ }
+
+ /**
+ * Class to run a CallerInfoAsyncQuery in a separate thread, with
+ * its own Looper. We cannot use the main Looper because on the
+ * 1st quit the thread is maked dead, ie no further test can use
+ * it. Also there is not way to inject a Looper instance in the
+ * query, so we have to use a thread with its own looper.
+ */
+ private class QueryRunner extends Thread
+ implements CallerInfoAsyncQuery.OnQueryCompleteListener {
+ private Looper mLooper;
+ private String mNumber;
+ private boolean mAsyncCompleted;
+
+ public QueryRunner(String number) {
+ super();
+ mNumber = number;
+ }
+
+ // Run the query in the thread, wait for completion.
+ public void runAndCheckCompletion() throws InterruptedException {
+ start();
+ join();
+ assertTrue(mAsyncCompleted);
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ mAsyncCompleted = false;
+ // The query will pick the thread local looper we've just prepared.
+ CallerInfoAsyncQuery.startQuery(kToken, mContext, mNumber, this, null);
+ mLooper.loop();
+ }
+
+ // Quit the Looper on the 1st callback
+ // (EVENT_EMERGENCY_NUMBER). There is another message
+ // (EVENT_END_OF_QUEUE) that will never be delivered because
+ // the test has exited. The corresponding stack trace
+ // "Handler{xxxxx} sending message to a Handler on a dead
+ // thread" can be ignored.
+ public void onQueryComplete(int token, Object cookie, CallerInfo info) {
+ mAsyncCompleted = true;
+ mInfo = info;
+ mLooper.quit();
+ }
+ }
+
+ /**
+ * Fail if mInfo does not contain a valid emergency CallerInfo instance.
+ */
+ private void assertIsValidEmergencyCallerInfo() throws Exception {
+ assertTrue(mInfo.isEmergencyNumber());
+
+ // For emergency caller info, phoneNumber should be set to the
+ // string emergency_call_dialog_number_for_display and the
+ // photoResource should be set to the picture_emergency drawable.
+ assertEquals(kEmergencyNumber, mInfo.phoneNumber);
+ assertEquals(com.android.internal.R.drawable.picture_emergency, mInfo.photoResource);
+
+ // The name should be null
+ assertNull(mInfo.name);
+ assertEquals(0, mInfo.namePresentation);
+ assertNull(mInfo.cnapName);
+ assertEquals(0, mInfo.numberPresentation);
+
+ assertFalse(mInfo.contactExists);
+ assertEquals(0, mInfo.person_id);
+ assertFalse(mInfo.needUpdate);
+ assertNull(mInfo.contactRefUri);
+
+ assertNull(mInfo.phoneLabel);
+ assertEquals(0, mInfo.numberType);
+ assertNull(mInfo.numberLabel);
+
+ assertNull(mInfo.contactRingtoneUri);
+ assertFalse(mInfo.shouldSendToVoicemail);
+
+ assertNull(mInfo.cachedPhoto);
+ assertFalse(mInfo.isCachedPhotoCurrent);
+ }
+}
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
index 1263204..706c27e 100644
--- a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
@@ -36,27 +36,18 @@
extern ANPCanvasInterfaceV0 gCanvasI;
extern ANPLogInterfaceV0 gLogI;
extern ANPPaintInterfaceV0 gPaintI;
-extern ANPSurfaceInterfaceV0 gSurfaceI;
extern ANPTypefaceInterfaceV0 gTypefaceI;
///////////////////////////////////////////////////////////////////////////////
-EventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) {
+EventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) { }
- // initialize the drawing surface
- m_surfaceReady = false;
- m_surface = gSurfaceI.newRasterSurface(inst, kRGB_565_ANPBitmapFormat, false);
- if(!m_surface)
- gLogI.log(inst, kError_ANPLogType, "----%p Unable to create Raster surface", inst);
-}
+EventPlugin::~EventPlugin() { }
-EventPlugin::~EventPlugin() {
- gSurfaceI.deleteSurface(m_surface);
-}
+void EventPlugin::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) {
-void EventPlugin::drawPlugin(int surfaceWidth, int surfaceHeight) {
-
- gLogI.log(inst(), kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)", inst(), surfaceWidth, surfaceHeight);
+ gLogI.log(inst(), kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)",
+ inst(), bitmap.width, bitmap.height);
// get the plugin's dimensions according to the DOM
PluginObject *obj = (PluginObject*) inst()->pdata;
@@ -64,8 +55,8 @@
const int H = obj->window->height;
// compute the current zoom level
- const float zoomFactorW = static_cast<float>(surfaceWidth) / W;
- const float zoomFactorH = static_cast<float>(surfaceHeight) / H;
+ const float zoomFactorW = static_cast<float>(bitmap.width) / W;
+ const float zoomFactorH = static_cast<float>(bitmap.height) / H;
// check to make sure the zoom level is uniform
if (zoomFactorW + .01 < zoomFactorH && zoomFactorW - .01 > zoomFactorH)
@@ -76,15 +67,16 @@
const int fontSize = (int)(zoomFactorW * 16);
const int leftMargin = (int)(zoomFactorW * 10);
- // lock the surface
- ANPBitmap bitmap;
- if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, NULL)) {
- gLogI.log(inst(), kError_ANPLogType, " ------ %p unable to lock the plugin", inst());
- return;
- }
-
- // create a canvas
+ // create and clip a canvas
ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
+
+ ANPRectF clipR;
+ clipR.left = clip.left;
+ clipR.top = clip.top;
+ clipR.right = clip.right;
+ clipR.bottom = clip.bottom;
+ gCanvasI.clipRect(canvas, &clipR);
+
gCanvasI.drawColor(canvas, 0xFFFFFFFF);
// configure the paint
@@ -106,10 +98,9 @@
const char c[] = "Browser Test Plugin";
gCanvasI.drawText(canvas, c, sizeof(c)-1, leftMargin, -fm.fTop, paint);
- // clean up variables and unlock the surface
+ // clean up variables
gPaintI.deletePaint(paint);
gCanvasI.deleteCanvas(canvas);
- gSurfaceI.unlock(m_surface);
}
void EventPlugin::printToDiv(const char* text, int length) {
@@ -149,23 +140,16 @@
int16 EventPlugin::handleEvent(const ANPEvent* evt) {
switch (evt->eventType) {
- case kDraw_ANPEventType:
- gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request draw events", inst());
- break;
- case kSurface_ANPEventType:
- switch (evt->data.surface.action) {
- case kCreated_ANPSurfaceAction:
- m_surfaceReady = true;
+
+ case kDraw_ANPEventType: {
+ switch (evt->data.draw.model) {
+ case kBitmap_ANPDrawingModel:
+ drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip);
return 1;
- case kDestroyed_ANPSurfaceAction:
- m_surfaceReady = false;
- return 1;
- case kChanged_ANPSurfaceAction:
- drawPlugin(evt->data.surface.data.changed.width,
- evt->data.surface.data.changed.height);
- return 1;
+ default:
+ break; // unknown drawing model
}
- break;
+ }
case kLifecycle_ANPEventType:
switch (evt->data.lifecycle.action) {
case kOnLoad_ANPLifecycleAction: {
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.h b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
index 73dd6ea..88b7c9d 100644
--- a/tests/BrowserTestPlugin/jni/event/EventPlugin.h
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
@@ -35,11 +35,8 @@
virtual int16 handleEvent(const ANPEvent* evt);
private:
- void drawPlugin(int surfaceWidth, int surfaceHeight);
+ void drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip);
void printToDiv(const char* text, int length);
-
- bool m_surfaceReady;
- ANPSurface* m_surface;
};
#endif // eventPlugin__DEFINED
diff --git a/tests/BrowserTestPlugin/jni/main.cpp b/tests/BrowserTestPlugin/jni/main.cpp
index 056ec4d..e3ad4a7 100644
--- a/tests/BrowserTestPlugin/jni/main.cpp
+++ b/tests/BrowserTestPlugin/jni/main.cpp
@@ -65,7 +65,6 @@
ANPLogInterfaceV0 gLogI;
ANPPaintInterfaceV0 gPaintI;
ANPPathInterfaceV0 gPathI;
-ANPSurfaceInterfaceV0 gSurfaceI;
ANPSystemInterfaceV0 gSystemI;
ANPTypefaceInterfaceV0 gTypefaceI;
ANPWindowInterfaceV0 gWindowI;
@@ -105,16 +104,10 @@
uint32_t size;
ANPInterface* i;
} gPairs[] = {
- { kAudioTrackInterfaceV0_ANPGetValue, sizeof(gSoundI), &gSoundI },
- { kBitmapInterfaceV0_ANPGetValue, sizeof(gBitmapI), &gBitmapI },
{ kCanvasInterfaceV0_ANPGetValue, sizeof(gCanvasI), &gCanvasI },
{ kLogInterfaceV0_ANPGetValue, sizeof(gLogI), &gLogI },
{ kPaintInterfaceV0_ANPGetValue, sizeof(gPaintI), &gPaintI },
- { kPathInterfaceV0_ANPGetValue, sizeof(gPathI), &gPathI },
- { kSurfaceInterfaceV0_ANPGetValue, sizeof(gSurfaceI), &gSurfaceI },
- { kSystemInterfaceV0_ANPGetValue, sizeof(gSystemI), &gSystemI },
{ kTypefaceInterfaceV0_ANPGetValue, sizeof(gTypefaceI), &gTypefaceI },
- { kWindowInterfaceV0_ANPGetValue, sizeof(gWindowI), &gWindowI },
};
for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
gPairs[i].i->inSize = gPairs[i].size;
@@ -156,7 +149,7 @@
}
// select the drawing model
- ANPDrawingModel model = kSurface_ANPDrawingModel;
+ ANPDrawingModel model = kBitmap_ANPDrawingModel;
// notify the plugin API of the drawing model we wish to use. This must be
// done prior to creating certain subPlugin objects (e.g. surfaceViews)
diff --git a/tests/DumpRenderTree/assets/run_page_cycler.py b/tests/DumpRenderTree/assets/run_page_cycler.py
index 4a68d72..7dd4a88 100755
--- a/tests/DumpRenderTree/assets/run_page_cycler.py
+++ b/tests/DumpRenderTree/assets/run_page_cycler.py
@@ -88,8 +88,15 @@
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)
+ (adb_output, err) = subprocess.Popen(
+ shell_cmd_str, shell=True,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ if not os.path.isfile(os.path.join(results_dir, "load_test_result.txt")):
+ logging.error("Failed to pull result file.")
+ logging.error("adb stdout:")
+ logging.error(adb_output)
+ logging.error("adb stderr:")
+ logging.error(err)
logging.info("Results are stored under: " + results_dir + "/load_test_result.txt\n")
if '__main__' == __name__:
diff --git a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
index 1ba9d66a..dc959f5 100644
--- a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -188,9 +188,9 @@
previousResults[3] = new ContentProviderResult(103);
ContentValues expectedValues = new ContentValues(values);
- expectedValues.put("a1", "103");
- expectedValues.put("a2", "101");
- expectedValues.put("a3", "102");
+ expectedValues.put("a1", (long) 103);
+ expectedValues.put("a2", (long) 101);
+ expectedValues.put("a3", (long) 102);
ContentProviderOperation op1 = ContentProviderOperation.newInsert(sTestUri1)
.withValues(values)