summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/Activity.java4
-rw-r--r--core/java/android/app/ActivityThread.java28
-rw-r--r--core/java/android/app/ApplicationContext.java32
-rw-r--r--core/java/android/app/SearchDialog.java22
-rw-r--r--core/java/android/app/SearchManager.java23
-rw-r--r--core/java/android/app/SuggestionsAdapter.java135
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java6
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java45
-rw-r--r--core/java/android/bluetooth/BluetoothUuid.java22
-rw-r--r--core/java/android/bluetooth/IBluetooth.aidl1
-rw-r--r--core/java/android/content/Context.java51
-rw-r--r--core/java/android/content/ContextWrapper.java10
-rw-r--r--core/java/android/content/Intent.java81
-rw-r--r--core/java/android/content/SyncManager.java32
-rw-r--r--core/java/android/content/SyncStatusInfo.java3
-rw-r--r--core/java/android/content/SyncStorageEngine.java13
-rw-r--r--core/java/android/content/res/CompatibilityInfo.java19
-rw-r--r--core/java/android/hardware/Camera.java94
-rw-r--r--core/java/android/os/BatteryManager.java67
-rw-r--r--core/java/android/os/BatteryStats.java12
-rw-r--r--core/java/android/preference/VolumePreference.java3
-rw-r--r--core/java/android/provider/Calendar.java1
-rw-r--r--core/java/android/provider/ContactsContract.java395
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/android/server/BluetoothEventLoop.java39
-rw-r--r--core/java/android/server/BluetoothService.java144
-rw-r--r--core/java/android/text/format/Formatter.java35
-rw-r--r--core/java/android/view/WindowManager.java18
-rw-r--r--core/java/android/view/WindowManagerPolicy.java17
-rw-r--r--core/java/android/webkit/BrowserFrame.java8
-rw-r--r--core/java/android/webkit/CallbackProxy.java11
-rwxr-xr-xcore/java/android/webkit/GeolocationPermissions.java147
-rw-r--r--core/java/android/webkit/GoogleLocationSettingManager.java88
-rw-r--r--core/java/android/webkit/PluginManager.java126
-rw-r--r--core/java/android/webkit/ValueCallback.java29
-rw-r--r--core/java/android/webkit/WebChromeClient.java4
-rw-r--r--core/java/android/webkit/WebSettings.java53
-rw-r--r--core/java/android/webkit/WebStorage.java263
-rw-r--r--core/java/android/webkit/WebTextView.java9
-rw-r--r--core/java/android/webkit/WebView.java118
-rw-r--r--core/java/android/webkit/WebViewCore.java134
-rw-r--r--core/java/android/widget/FasttrackBadgeWidget.java18
-rw-r--r--core/java/android/widget/ScrollView.java15
-rw-r--r--core/java/android/widget/TextView.java41
-rw-r--r--core/java/com/android/internal/backup/BackupConstants.java26
-rw-r--r--core/java/com/android/internal/backup/IBackupTransport.aidl63
-rw-r--r--core/java/com/android/internal/backup/LocalTransport.java56
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java78
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java23
-rw-r--r--core/java/com/android/internal/widget/ContactHeaderWidget.java21
-rw-r--r--core/java/com/android/internal/widget/RotarySelector.java289
-rw-r--r--core/java/com/google/android/mms/pdu/GenericPdu.java21
-rw-r--r--core/java/com/google/android/mms/pdu/PduComposer.java48
-rw-r--r--core/java/com/google/android/mms/pdu/ReadRecInd.java21
-rw-r--r--core/java/com/google/android/mms/pdu/SendReq.java21
-rw-r--r--core/jni/android_hardware_Camera.cpp24
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp54
-rw-r--r--core/jni/android_server_BluetoothService.cpp104
-rw-r--r--core/res/res/anim/activity_close_enter.xml2
-rw-r--r--core/res/res/anim/activity_close_exit.xml2
-rw-r--r--core/res/res/anim/activity_open_enter.xml2
-rw-r--r--core/res/res/anim/activity_open_exit.xml2
-rw-r--r--core/res/res/anim/dialog_enter.xml5
-rw-r--r--core/res/res/anim/dialog_exit.xml6
-rw-r--r--core/res/res/anim/recent_enter.xml10
-rw-r--r--core/res/res/anim/recent_exit.xml15
-rw-r--r--core/res/res/anim/task_open_exit.xml3
-rw-r--r--core/res/res/anim/translucent_enter.xml4
-rw-r--r--core/res/res/anim/translucent_exit.xml4
-rw-r--r--core/res/res/anim/wallpaper_close_enter.xml14
-rw-r--r--core/res/res/anim/wallpaper_close_exit.xml17
-rw-r--r--core/res/res/anim/wallpaper_open_enter.xml17
-rw-r--r--core/res/res/anim/wallpaper_open_exit.xml14
-rw-r--r--core/res/res/drawable-hdpi/dark_header.9.pngbin203 -> 170 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_bright.9.pngbin268 -> 116 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.pngbin287 -> 120 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_dark.9.pngbin285 -> 118 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.pngbin289 -> 120 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_vertical_bright.9.pngbin109 -> 116 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_vertical_bright_opaque.9.png (renamed from core/res/res/drawable/divider_vertical_bright_opaque.9.png)bin120 -> 120 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_vertical_dark.9.pngbin0 -> 118 bytes
-rw-r--r--core/res/res/drawable-hdpi/divider_vertical_dark_opaque.9.png (renamed from core/res/res/drawable/divider_vertical_dark_opaque.9.png)bin120 -> 120 bytes
-rw-r--r--core/res/res/drawable-hdpi/fasttrack_badge.9.pngbin0 -> 709 bytes
-rw-r--r--core/res/res/drawable-hdpi/fasttrack_badge_pressed.9.pngbin0 -> 670 bytes
-rw-r--r--core/res/res/drawable-hdpi/fasttrack_badge_small.9.pngbin0 -> 627 bytes
-rw-r--r--core/res/res/drawable-hdpi/fasttrack_badge_small_pressed.9.pngbin0 -> 633 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_aggregated.pngbin0 -> 883 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_ringer_off.pngbin0 -> 1378 bytes
-rw-r--r--core/res/res/drawable-hdpi/ic_lock_ringer_on.pngbin0 -> 1757 bytes
-rw-r--r--core/res/res/drawable-hdpi/light_header.9.pngbin202 -> 174 bytes
-rw-r--r--core/res/res/drawable-mdpi/dark_header.9.pngbin161 -> 125 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_vertical_bright_opaque.9.pngbin0 -> 120 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_vertical_dark.9.png (renamed from core/res/res/drawable/divider_vertical_dark.9.png)bin121 -> 121 bytes
-rw-r--r--core/res/res/drawable-mdpi/divider_vertical_dark_opaque.9.pngbin0 -> 120 bytes
-rw-r--r--core/res/res/drawable-mdpi/fasttrack_badge.9.pngbin0 -> 651 bytes
-rw-r--r--core/res/res/drawable-mdpi/fasttrack_badge_pressed.9.pngbin0 -> 650 bytes
-rw-r--r--core/res/res/drawable-mdpi/fasttrack_badge_small.9.pngbin0 -> 609 bytes
-rw-r--r--core/res/res/drawable-mdpi/fasttrack_badge_small_pressed.9.pngbin0 -> 605 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_aggregated.pngbin0 -> 671 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_ringer_off.pngbin0 -> 906 bytes
-rw-r--r--core/res/res/drawable-mdpi/ic_lock_ringer_on.pngbin0 -> 977 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge.xml (renamed from core/res/res/drawable/fasttrack_badge_dark.xml)4
-rw-r--r--core/res/res/drawable/fasttrack_badge_dark_normal.9.pngbin624 -> 0 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_dark_pressed.9.pngbin846 -> 0 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_light_normal.9.pngbin824 -> 0 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_light_pressed.9.pngbin831 -> 0 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_middle_large.xml28
-rw-r--r--core/res/res/drawable/fasttrack_badge_middle_large_normal.9.pngbin612 -> 0 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_middle_large_pressed.9.pngbin834 -> 0 bytes
-rw-r--r--core/res/res/drawable/fasttrack_badge_small.xml (renamed from core/res/res/drawable/fasttrack_badge_light.xml)4
-rw-r--r--core/res/res/layout/contact_header.xml20
-rw-r--r--core/res/res/layout/keyguard_screen_rotary_unlock.xml10
-rw-r--r--core/res/res/layout/tab_indicator.xml4
-rw-r--r--core/res/res/values/attrs.xml34
-rw-r--r--core/res/res/values/colors.xml4
-rw-r--r--core/res/res/values/config.xml24
-rw-r--r--core/res/res/values/public.xml7
-rw-r--r--core/res/res/values/strings.xml103
-rw-r--r--core/res/res/values/styles.xml40
-rw-r--r--core/res/res/values/themes.xml9
-rw-r--r--core/res/res/xml/power_profile.xml15
121 files changed, 2753 insertions, 936 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a86fe90..4561899 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -790,8 +790,8 @@ public class Activity extends ContextThemeWrapper
* @see #onPostCreate
*/
protected void onCreate(Bundle savedInstanceState) {
- mVisibleFromClient = mWindow.getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowNoDisplay, true);
+ mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowNoDisplay, false);
mCalled = true;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8142d1a..6acd665 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1765,6 +1765,7 @@ public final class ActivityThread {
public static final int CREATE_BACKUP_AGENT = 128;
public static final int DESTROY_BACKUP_AGENT = 129;
public static final int SUICIDE = 130;
+ public static final int REMOVE_PROVIDER = 131;
String codeToString(int code) {
if (localLOGV) {
switch (code) {
@@ -1799,6 +1800,7 @@ public final class ActivityThread {
case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
case SUICIDE: return "SUICIDE";
+ case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
}
}
return "(unknown)";
@@ -1911,9 +1913,10 @@ public final class ActivityThread {
handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
break;
case SUICIDE:
- {
- Process.killProcess(Process.myPid());
- }
+ Process.killProcess(Process.myPid());
+ break;
+ case REMOVE_PROVIDER:
+ completeRemoveProvider((IContentProvider)msg.obj);
break;
}
}
@@ -4029,15 +4032,28 @@ public final class ActivityThread {
} else {
prc.count--;
if(prc.count == 0) {
- mProviderRefCountMap.remove(jBinder);
- //invoke removeProvider to dereference provider
- removeProviderLocked(provider);
+ // Schedule the actual remove asynchronously, since we
+ // don't know the context this will be called in.
+ Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
+ mH.sendMessage(msg);
} //end if
} //end else
} //end synchronized
return true;
}
+ final void completeRemoveProvider(IContentProvider provider) {
+ IBinder jBinder = provider.asBinder();
+ synchronized(mProviderMap) {
+ ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
+ if(prc != null && prc.count == 0) {
+ mProviderRefCountMap.remove(jBinder);
+ //invoke removeProvider to dereference provider
+ removeProviderLocked(provider);
+ }
+ }
+ }
+
public final void removeProviderLocked(IContentProvider provider) {
if (provider == null) {
return;
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index dc8d873..afafe64 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -659,6 +659,38 @@ class ApplicationContext extends Context {
}
@Override
+ public void sendStickyOrderedBroadcast(Intent intent,
+ BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData,
+ Bundle initialExtras) {
+ IIntentReceiver rd = null;
+ if (resultReceiver != null) {
+ if (mPackageInfo != null) {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = mPackageInfo.getReceiverDispatcher(
+ resultReceiver, getOuterContext(), scheduler,
+ mMainThread.getInstrumentation(), false);
+ } else {
+ if (scheduler == null) {
+ scheduler = mMainThread.getHandler();
+ }
+ rd = new ActivityThread.PackageInfo.ReceiverDispatcher(
+ resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+ }
+ }
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ ActivityManagerNative.getDefault().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, rd,
+ initialCode, initialData, initialExtras, null,
+ true, true);
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
public void removeStickyBroadcast(Intent intent) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
if (resolvedType != null) {
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index d05c9ab..a2c95f4 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -736,7 +736,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
return false;
}
- if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+ if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() == 0) {
+ event.startTracking();
// Consume search key for later use.
return true;
}
@@ -1143,7 +1144,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
String query = mSearchAutoComplete.getText().toString();
String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
Intent intent = createIntent(action, null, null, query, null,
- actionKey, actionMsg);
+ actionKey, actionMsg, null);
// Allow GlobalSearch to log and create shortcut for searches launched by
// the search button, enter key or an action key.
if (mGlobalSearchMode) {
@@ -1181,7 +1182,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// report back about the click
if (mGlobalSearchMode) {
// in global search mode, do it via cursor
- mSuggestionsAdapter.callCursorOnClick(c, position);
+ mSuggestionsAdapter.callCursorOnClick(c, position, actionKey, actionMsg);
} else if (intent != null
&& mPreviousComponents != null
&& !mPreviousComponents.isEmpty()) {
@@ -1218,7 +1219,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction());
cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString());
cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME,
- intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY));
+ intent.getComponent().flattenToShortString());
// ensure the icons will work for global search
cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
@@ -1578,9 +1579,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
+ String mode = mGlobalSearchMode ? SearchManager.MODE_GLOBAL_SEARCH_SUGGESTION : null;
return createIntent(action, dataUri, extraData, query, componentName, actionKey,
- actionMsg);
+ actionMsg, mode);
} catch (RuntimeException e ) {
int rowNum;
try { // be really paranoid now
@@ -1606,13 +1608,18 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
* or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
* @param actionMsg The message for the action key that was pressed,
* or <code>null</code> if none.
+ * @param mode The search mode, one of the acceptable values for
+ * {@link SearchManager#SEARCH_MODE}, or {@code null}.
* @return The intent.
*/
private Intent createIntent(String action, Uri data, String extraData, String query,
- String componentName, int actionKey, String actionMsg) {
+ String componentName, int actionKey, String actionMsg, String mode) {
// Now build the Intent
Intent intent = new Intent(action);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ // We need CLEAR_TOP to avoid reusing an old task that has other activities
+ // on top of the one we want.
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if (data != null) {
intent.setData(data);
}
@@ -1633,6 +1640,9 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
intent.putExtra(SearchManager.ACTION_KEY, actionKey);
intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
}
+ if (mode != null) {
+ intent.putExtra(SearchManager.SEARCH_MODE, mode);
+ }
// Only allow 3rd-party intents from GlobalSearch
if (!mGlobalSearchMode) {
intent.setComponent(mSearchable.getSearchActivity());
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 3a14f6f..f0876f4 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1289,6 +1289,25 @@ public class SearchManager
public final static String SOURCE = "source";
/**
+ * Intent extra data key: Use {@link android.content.Intent#getBundleExtra
+ * content.Intent.getBundleExtra(SEARCH_MODE)} to get the search mode used
+ * to launch the intent.
+ * The only current value for this is {@link #MODE_GLOBAL_SEARCH_SUGGESTION}.
+ *
+ * @hide
+ */
+ public final static String SEARCH_MODE = "search_mode";
+
+ /**
+ * Value for the {@link #SEARCH_MODE} key.
+ * This is used if the intent was launched by clicking a suggestion in global search
+ * mode (Quick Search Box).
+ *
+ * @hide
+ */
+ public static final String MODE_GLOBAL_SEARCH_SUGGESTION = "global_search_suggestion";
+
+ /**
* Intent extra data key: Use this key with Intent.ACTION_SEARCH and
* {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
* to obtain the keycode that the user used to trigger this query. It will be zero if the
@@ -1343,6 +1362,10 @@ public class SearchManager
= "DialogCursorProtocol.CLICK.sendPosition";
public final static String CLICK_SEND_MAX_DISPLAY_POS
= "DialogCursorProtocol.CLICK.sendDisplayPosition";
+ public final static String CLICK_SEND_ACTION_KEY
+ = "DialogCursorProtocol.CLICK.sendActionKey";
+ public final static String CLICK_SEND_ACTION_MSG
+ = "DialogCursorProtocol.CLICK.sendActionMsg";
public final static String CLICK_RECEIVE_SELECTED_POS
= "DialogCursorProtocol.CLICK.receiveSelectedPosition";
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 4f9531e..9234a9c 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -26,7 +26,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.database.Cursor;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
@@ -37,6 +36,7 @@ import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
+import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Filter;
@@ -47,7 +47,6 @@ import android.widget.TextView;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.util.List;
import java.util.WeakHashMap;
/**
@@ -290,12 +289,16 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
* @param cursor The cursor
* @param position The position that was clicked.
*/
- void callCursorOnClick(Cursor cursor, int position) {
+ void callCursorOnClick(Cursor cursor, int position, int actionKey, String actionMsg) {
if (!mGlobalSearchMode) return;
- final Bundle request = new Bundle(3);
+ final Bundle request = new Bundle(5);
request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
+ if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
+ request.putInt(DialogCursorProtocol.CLICK_SEND_ACTION_KEY, actionKey);
+ request.putString(DialogCursorProtocol.CLICK_SEND_ACTION_MSG, actionMsg);
+ }
final Bundle response = cursor.respond(request);
mMaxDisplayed = -1;
mListItemToSelect = response.getInt(
@@ -569,69 +572,91 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
if (drawableId == null || drawableId.length() == 0 || "0".equals(drawableId)) {
return null;
}
-
- // First, check the cache.
- Drawable.ConstantState cached = mOutsideDrawablesCache.get(drawableId);
- if (cached != null) {
- if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + drawableId);
- return cached.newDrawable(mProviderContext.getResources());
- }
-
- Drawable drawable = null;
try {
- // Not cached, try using it as a plain resource ID in the provider's context.
+ // First, see if it's just an integer
int resourceId = Integer.parseInt(drawableId);
+ // It's an int, look for it in the cache
+ String drawableUri = ContentResolver.SCHEME_ANDROID_RESOURCE
+ + "://" + mProviderContext.getPackageName() + "/" + resourceId;
+ // Must use URI as cache key, since ints are app-specific
+ Drawable drawable = checkIconCache(drawableUri);
+ if (drawable != null) {
+ return drawable;
+ }
+ // Not cached, find it by resource ID
drawable = mProviderContext.getResources().getDrawable(resourceId);
+ // Stick it in the cache, using the URI as key
+ storeInIconCache(drawableUri, drawable);
+ return drawable;
} catch (NumberFormatException nfe) {
- // The id was not an integer resource id, use it as a URI
- try {
- Uri uri = Uri.parse(drawableId);
- String scheme = uri.getScheme();
- if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
- // Load drawables through Resources, to get the source density information
- OpenResourceIdResult r =
- mProviderContext.getContentResolver().getResourceId(uri);
- try {
- drawable = r.r.getDrawable(r.id);
- } catch (Resources.NotFoundException ex) {
- throw new FileNotFoundException("Resource does not exist: " + uri);
- }
- } else {
- // Let the ContentResolver handle content and file URIs.
- InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
- if (stream == null) {
- throw new FileNotFoundException("Failed to open " + uri);
- }
- try {
- drawable = Drawable.createFromStream(stream, null);
- } finally {
- try {
- stream.close();
- } catch (IOException ex) {
- Log.e(LOG_TAG, "Error closing icon stream for " + uri, ex);
- }
- }
- }
- } catch (FileNotFoundException fnfe) {
- Log.w(LOG_TAG, "Icon not found: " + drawableId + ", " + fnfe.getMessage());
- // drawable = null;
+ // It's not an integer, use it as a URI
+ Drawable drawable = checkIconCache(drawableId);
+ if (drawable != null) {
+ return drawable;
}
+ Uri uri = Uri.parse(drawableId);
+ drawable = getDrawable(uri);
+ storeInIconCache(drawableId, drawable);
+ return drawable;
} catch (Resources.NotFoundException nfe) {
+ // It was an integer, but it couldn't be found, bail out
Log.w(LOG_TAG, "Icon resource not found: " + drawableId);
- // drawable = null;
+ return null;
}
+ }
- if (drawable == null) {
- if (DBG) Log.d(LOG_TAG, "Didn't find icon: " + drawableId);
- } else {
- if (DBG) {
- Log.d(LOG_TAG, "Found icon: " + drawableId);
+ /**
+ * Gets a drawable by URI, without using the cache.
+ *
+ * @return A drawable, or {@code null} if the drawable could not be loaded.
+ */
+ private Drawable getDrawable(Uri uri) {
+ try {
+ String scheme = uri.getScheme();
+ if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+ // Load drawables through Resources, to get the source density information
+ OpenResourceIdResult r =
+ mProviderContext.getContentResolver().getResourceId(uri);
+ try {
+ return r.r.getDrawable(r.id);
+ } catch (Resources.NotFoundException ex) {
+ throw new FileNotFoundException("Resource does not exist: " + uri);
+ }
+ } else {
+ // Let the ContentResolver handle content and file URIs.
+ InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
+ if (stream == null) {
+ throw new FileNotFoundException("Failed to open " + uri);
+ }
+ try {
+ return Drawable.createFromStream(stream, null);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException ex) {
+ Log.e(LOG_TAG, "Error closing icon stream for " + uri, ex);
+ }
+ }
}
- // Cache it so we don't do this lookup again
- mOutsideDrawablesCache.put(drawableId, drawable.getConstantState());
+ } catch (FileNotFoundException fnfe) {
+ Log.w(LOG_TAG, "Icon not found: " + uri + ", " + fnfe.getMessage());
+ return null;
}
+ }
- return drawable;
+ private Drawable checkIconCache(String resourceUri) {
+ Drawable.ConstantState cached = mOutsideDrawablesCache.get(resourceUri);
+ if (cached == null) {
+ return null;
+ }
+ if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + resourceUri);
+ return cached.newDrawable();
+ }
+
+ private void storeInIconCache(String resourceUri, Drawable drawable) {
+ if (drawable != null) {
+ mOutsideDrawablesCache.put(resourceUri, drawable.getConstantState());
+ }
}
/**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 96a927b..1fc22fe 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -573,6 +573,7 @@ public final class BluetoothAdapter {
/**
* Validate a Bluetooth address, such as "00:43:A8:23:10:F0"
+ * <p>Alphabetic characters must be uppercase to be valid.
*
* @param address Bluetooth address as string
* @return true if the address is valid, false otherwise
@@ -586,8 +587,9 @@ public final class BluetoothAdapter {
switch (i % 3) {
case 0:
case 1:
- if (Character.digit(c, 16) != -1) {
- break; // hex character, OK
+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
+ // hex character, OK
+ break;
}
return false;
case 2:
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index f81ba73..b52a822 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -28,6 +28,7 @@ import android.util.Log;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.util.UUID;
/**
* Represents a remote Bluetooth device.
@@ -226,6 +227,20 @@ public final class BluetoothDevice implements Parcelable {
public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
/**
+ * Broadcast Action: This intent is used to broadcast the {@link UUID}
+ * wrapped as a {@link ParcelUuid} of the remote device after it has been
+ * fetched. This intent is sent only when the UUIDs of the remote device
+ * are requested to be fetched using Service Discovery Protocol
+ * <p> Always contains the extra field {@link #EXTRA_DEVICE}
+ * <p> Always contains the extra filed {@link #EXTRA_UUID}
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_UUID =
+ "android.bleutooth.device.action.UUID";
+
+ /**
* Broadcast Action: Indicates a failure to retrieve the name of a remote
* device.
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
@@ -292,6 +307,15 @@ public final class BluetoothDevice implements Parcelable {
* @hide */
public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
+ /**
+ * Used as an extra field in {@link #ACTION_UUID} intents,
+ * Contains the {@link ParcelUuid}s of the remote device which is a parcelable
+ * version of {@link UUID}.
+ * @hide
+ */
+ public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+
+
private static IBluetooth sService; /* Guarenteed constant after first object constructed */
private final String mAddress;
@@ -507,6 +531,27 @@ public final class BluetoothDevice implements Parcelable {
return null;
}
+ /**
+ * Perform a SDP query on the remote device to get the UUIDs
+ * supported. This API is asynchronous and an Intent is sent,
+ * with the UUIDs supported by the remote end. If there is an error
+ * in getting the SDP records or if the process takes a long time,
+ * an Intent is sent with the UUIDs that is currently present in the
+ * cache. Clients should use the {@link getUuids} to get UUIDs
+ * is SDP is not to be performed.
+ *
+ * @return False if the sanity check fails, True if the process
+ * of initiating an ACL connection to the remote device
+ * was started.
+ * @hide
+ */
+ public boolean fetchUuidsWithSdp() {
+ try {
+ return sService.fetchRemoteUuidsWithSdp(mAddress);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
/** @hide */
public int getServiceChannel(ParcelUuid uuid) {
try {
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 409c744..24ad06a 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -83,6 +83,12 @@ public final class BluetoothUuid {
* @param uuid
*/
public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
+ if ((uuidArray == null || uuidArray.length == 0) && uuid == null)
+ return true;
+
+ if (uuidArray == null)
+ return false;
+
for (ParcelUuid element: uuidArray) {
if (element.equals(uuid)) return true;
}
@@ -98,7 +104,14 @@ public final class BluetoothUuid {
*/
public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
if (uuidA == null && uuidB == null) return true;
- if (uuidA == null || uuidB == null) return false;
+
+ if (uuidA == null) {
+ return uuidB.length == 0 ? true : false;
+ }
+
+ if (uuidB == null) {
+ return uuidA.length == 0 ? true : false;
+ }
HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
for (ParcelUuid uuid: uuidB) {
@@ -117,7 +130,12 @@ public final class BluetoothUuid {
*/
public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
if (uuidA == null && uuidB == null) return true;
- if (uuidA == null || uuidB == null) return false;
+
+ if (uuidA == null) {
+ return uuidB.length == 0 ? true : false;
+ }
+
+ if (uuidB == null) return true;
HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
for (ParcelUuid uuid: uuidB) {
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 04c8ec9..203a61d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -53,6 +53,7 @@ interface IBluetooth
String getRemoteName(in String address);
int getRemoteClass(in String address);
ParcelUuid[] getRemoteUuids(in String address);
+ boolean fetchRemoteUuidsWithSdp(in String address);
int getRemoteServiceChannel(in String address,in ParcelUuid uuid);
boolean setPin(in String address, in byte[] pin);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a3c4f9a..fe4665e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -657,8 +657,7 @@ public abstract class Context {
* supplying your own BroadcastReceiver when calling, which will be
* treated as a final receiver at the end of the broadcast -- its
* {@link BroadcastReceiver#onReceive} method will be called with
- * the result values collected from the other receivers. If you use
- * an <var>resultReceiver</var> with this method, then the broadcast will
+ * the result values collected from the other receivers. The broadcast will
* be serialized in the same way as calling
* {@link #sendOrderedBroadcast(Intent, String)}.
*
@@ -689,6 +688,7 @@ public abstract class Context {
* @see #sendBroadcast(Intent, String)
* @see #sendOrderedBroadcast(Intent, String)
* @see #sendStickyBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
* @see android.content.BroadcastReceiver
* @see #registerReceiver
* @see android.app.Activity#RESULT_OK
@@ -715,8 +715,55 @@ public abstract class Context {
* be re-broadcast to future receivers.
*
* @see #sendBroadcast(Intent)
+ * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
*/
public abstract void sendStickyBroadcast(Intent intent);
+
+ /**
+ * Version of {@link #sendStickyBroadcast} that allows you to
+ * receive data back from the broadcast. This is accomplished by
+ * supplying your own BroadcastReceiver when calling, which will be
+ * treated as a final receiver at the end of the broadcast -- its
+ * {@link BroadcastReceiver#onReceive} method will be called with
+ * the result values collected from the other receivers. The broadcast will
+ * be serialized in the same way as calling
+ * {@link #sendOrderedBroadcast(Intent, String)}.
+ *
+ * <p>Like {@link #sendBroadcast(Intent)}, this method is
+ * asynchronous; it will return before
+ * resultReceiver.onReceive() is called. Note that the sticky data
+ * stored is only the data you initially supply to the broadcast, not
+ * the result of any changes made by the receivers.
+ *
+ * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast.
+ * @param resultReceiver Your own BroadcastReceiver to treat as the final
+ * receiver of the broadcast.
+ * @param scheduler A custom Handler with which to schedule the
+ * resultReceiver callback; if null it will be
+ * scheduled in the Context's main thread.
+ * @param initialCode An initial value for the result code. Often
+ * Activity.RESULT_OK.
+ * @param initialData An initial value for the result data. Often
+ * null.
+ * @param initialExtras An initial value for the result extras. Often
+ * null.
+ *
+ * @see #sendBroadcast(Intent)
+ * @see #sendBroadcast(Intent, String)
+ * @see #sendOrderedBroadcast(Intent, String)
+ * @see #sendStickyBroadcast(Intent)
+ * @see android.content.BroadcastReceiver
+ * @see #registerReceiver
+ * @see android.app.Activity#RESULT_OK
+ */
+ public abstract void sendStickyOrderedBroadcast(Intent intent,
+ BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData,
+ Bundle initialExtras);
+
/**
* Remove the data previously sent with {@link #sendStickyBroadcast},
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index d580c47..1b34320 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -288,6 +288,16 @@ public class ContextWrapper extends Context {
}
@Override
+ public void sendStickyOrderedBroadcast(
+ Intent intent, BroadcastReceiver resultReceiver,
+ Handler scheduler, int initialCode, String initialData,
+ Bundle initialExtras) {
+ mBase.sendStickyOrderedBroadcast(intent,
+ resultReceiver, scheduler, initialCode,
+ initialData, initialExtras);
+ }
+
+ @Override
public void removeStickyBroadcast(Intent intent) {
mBase.removeStickyBroadcast(intent);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1359761..5fb5768 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1352,14 +1352,20 @@ public class Intent implements Parcelable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
/**
- * Broadcast Action: The charging state, or charge level of the battery has
- * changed.
+ * Broadcast Action: This is a <em>sticky broadcast</em> containing the
+ * charging state, level, and other information about the battery.
+ * See {@link android.os.BatteryManager} for documentation on the
+ * contents of the Intent.
*
* <p class="note">
* You can <em>not</em> receive this through components declared
* in manifests, only by explicitly registering for it with
* {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
- * Context.registerReceiver()}.
+ * Context.registerReceiver()}. See {@link #ACTION_BATTERY_LOW},
+ * {@link #ACTION_BATTERY_OKAY}, {@link #ACTION_POWER_CONNECTED},
+ * and {@link #ACTION_POWER_DISCONNECTED} for distinct battery-related
+ * broadcasts that are sent and can be received through manifest
+ * receivers.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -1434,7 +1440,8 @@ public class Intent implements Parcelable {
*/
public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
/**
- * Broadcast Action: Indicates low memory condition on the device
+ * Broadcast Action: A sticky broadcast that indicates low memory
+ * condition on the device
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -1711,6 +1718,18 @@ public class Intent implements Parcelable {
"android.intent.action.REBOOT";
/**
+ * Broadcast Action: A sticky broadcast indicating the phone was docked
+ * or undocked. Includes the extra
+ * field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
+ * This is intended for monitoring the current dock state.
+ * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
+ * or {@link #CATEGORY_DESK_DOCK} instead.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DOCK_EVENT =
+ "android.intent.action.DOCK_EVENT";
+
+ /**
* Broadcast Action: a remote intent is to be broadcasted.
*
* A remote intent is used for remote RPC between devices. The remote intent
@@ -1720,6 +1739,7 @@ public class Intent implements Parcelable {
* does not trust intent broadcasts from arbitrary intent senders, it should require
* the sender to hold certain permissions so only trusted sender's broadcast will be
* let through.
+ * @hide
*/
public static final String ACTION_REMOTE_INTENT =
"android.intent.action.REMOTE_INTENT";
@@ -1865,7 +1885,7 @@ public class Intent implements Parcelable {
"android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
/**
* An activity to run when device is inserted into a car dock.
- * Used with {@link #ACTION_MAIN} to launch an activity.
+ * Used with {@link #ACTION_MAIN} to launch an activity.
* To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead.
*/
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -1878,16 +1898,6 @@ public class Intent implements Parcelable {
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
- /**
- * Broadcast Action: The phone was docked or undocked. Includes the extra
- * field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
- * This is intended for monitoring the current dock state.
- * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
- * or {@link #CATEGORY_DESK_DOCK} instead.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
-
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard extra data keys.
@@ -2046,6 +2056,12 @@ public class Intent implements Parcelable {
public static final int EXTRA_DOCK_STATE_CAR = 2;
/**
+ * Boolean that can be supplied as meta-data with a dock activity, to
+ * indicate that the dock should take over the home key when it is active.
+ */
+ public static final String METADATA_DOCK_HOME = "android.dock_home";
+
+ /**
* Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
* the bug report.
*
@@ -2308,6 +2324,18 @@ public class Intent implements Parcelable {
*/
public static final int FLAG_ACTIVITY_REORDER_TO_FRONT = 0X00020000;
/**
+ * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
+ * this flag will prevent the system from applying an activity transition
+ * animation to go to the next activity state. This doesn't mean an
+ * animation will never run -- if another activity change happens that doesn't
+ * specify this flag before the activity started here is displayed, then
+ * that transition will be used. This this flag can be put to good use
+ * when you are going to do a series of activity operations but the
+ * animation seen by the user shouldn't be driven by the first activity
+ * change but rather a later one.
+ */
+ public static final int FLAG_ACTIVITY_NO_ANIMATION = 0X00010000;
+ /**
* If set, when sending a broadcast only registered receivers will be
* called -- no BroadcastReceiver components will be launched.
*/
@@ -2521,6 +2549,7 @@ public class Intent implements Parcelable {
*
* @param uri The URI to turn into an Intent.
* @param flags Additional processing flags. Either 0 or
+ * {@link #URI_INTENT_SCHEME}.
*
* @return Intent The newly created Intent object.
*
@@ -2654,24 +2683,24 @@ public class Intent implements Parcelable {
int i = uri.lastIndexOf('#');
if (i >= 0) {
- Uri data = null;
String action = null;
- if (i > 0) {
- data = Uri.parse(uri.substring(0, i));
- }
+ final int intentFragmentStart = i;
+ boolean isIntentFragment = false;
i++;
if (uri.regionMatches(i, "action(", 0, 7)) {
+ isIntentFragment = true;
i += 7;
int j = uri.indexOf(')', i);
action = uri.substring(i, j);
i = j + 1;
}
- intent = new Intent(action, data);
+ intent = new Intent(action);
if (uri.regionMatches(i, "categories(", 0, 11)) {
+ isIntentFragment = true;
i += 11;
int j = uri.indexOf(')', i);
while (i < j) {
@@ -2686,6 +2715,7 @@ public class Intent implements Parcelable {
}
if (uri.regionMatches(i, "type(", 0, 5)) {
+ isIntentFragment = true;
i += 5;
int j = uri.indexOf(')', i);
intent.mType = uri.substring(i, j);
@@ -2693,6 +2723,7 @@ public class Intent implements Parcelable {
}
if (uri.regionMatches(i, "launchFlags(", 0, 12)) {
+ isIntentFragment = true;
i += 12;
int j = uri.indexOf(')', i);
intent.mFlags = Integer.decode(uri.substring(i, j)).intValue();
@@ -2700,6 +2731,7 @@ public class Intent implements Parcelable {
}
if (uri.regionMatches(i, "component(", 0, 10)) {
+ isIntentFragment = true;
i += 10;
int j = uri.indexOf(')', i);
int sep = uri.indexOf('!', i);
@@ -2712,6 +2744,7 @@ public class Intent implements Parcelable {
}
if (uri.regionMatches(i, "extras(", 0, 7)) {
+ isIntentFragment = true;
i += 7;
final int closeParen = uri.indexOf(')', i);
@@ -2783,6 +2816,12 @@ public class Intent implements Parcelable {
}
}
+ if (isIntentFragment) {
+ intent.mData = Uri.parse(uri.substring(0, intentFragmentStart));
+ } else {
+ intent.mData = Uri.parse(uri);
+ }
+
if (intent.mAction == null) {
// By default, if no action is specified, then use VIEW.
intent.mAction = ACTION_VIEW;
@@ -3572,7 +3611,7 @@ public class Intent implements Parcelable {
}
} else {
ResolveInfo info = pm.resolveActivity(
- this, PackageManager.MATCH_DEFAULT_ONLY);
+ this, PackageManager.MATCH_DEFAULT_ONLY | flags);
if (info != null) {
ai = info.activityInfo;
}
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 7859d5a..80613d8 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -514,7 +514,7 @@ class SyncManager implements OnAccountsUpdatedListener {
public SyncStorageEngine getSyncStorageEngine() {
return mSyncStorageEngine;
}
-
+
private void ensureAlarmService() {
if (mAlarmService == null) {
mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
@@ -1125,7 +1125,7 @@ class SyncManager implements OnAccountsUpdatedListener {
tobj.set(time);
return tobj.format("%Y-%m-%d %H:%M:%S");
}
-
+
protected void dumpSyncState(PrintWriter pw, StringBuilder sb) {
pw.print("sync enabled: "); pw.println(isSyncEnabled());
pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
@@ -1219,13 +1219,13 @@ class SyncManager implements OnAccountsUpdatedListener {
= mSyncStorageEngine.getAuthority(status.authorityId);
if (authority != null) {
Account curAccount = authority.account;
-
+
if (processedAccounts.contains(curAccount)) {
continue;
}
-
+
processedAccounts.add(curAccount);
-
+
pw.print(" Account "); pw.print(authority.account.name);
pw.print(" "); pw.print(authority.account.type);
pw.println(":");
@@ -1271,7 +1271,7 @@ class SyncManager implements OnAccountsUpdatedListener {
pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
pw.print('s');
}
-
+
private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) {
pw.print("Success ("); pw.print(ds.successCount);
if (ds.successCount > 0) {
@@ -1285,7 +1285,7 @@ class SyncManager implements OnAccountsUpdatedListener {
}
pw.println(")");
}
-
+
protected void dumpSyncHistory(PrintWriter pw, StringBuilder sb) {
SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics();
if (dses != null && dses[0] != null) {
@@ -1295,18 +1295,18 @@ class SyncManager implements OnAccountsUpdatedListener {
int today = dses[0].day;
int i;
SyncStorageEngine.DayStats ds;
-
+
// Print each day in the current week.
for (i=1; i<=6 && i < dses.length; i++) {
ds = dses[i];
if (ds == null) break;
int delta = today-ds.day;
if (delta > 6) break;
-
+
pw.print(" Day-"); pw.print(delta); pw.print(": ");
dumpDayStatistic(pw, ds);
}
-
+
// Aggregate all following days into weeks and print totals.
int weekDay = today;
while (i < dses.length) {
@@ -1321,7 +1321,7 @@ class SyncManager implements OnAccountsUpdatedListener {
int delta = weekDay-ds.day;
if (delta > 6) break;
i++;
-
+
if (aggr == null) {
aggr = new SyncStorageEngine.DayStats(weekDay);
}
@@ -1336,7 +1336,7 @@ class SyncManager implements OnAccountsUpdatedListener {
}
}
}
-
+
ArrayList<SyncStorageEngine.SyncHistoryItem> items
= mSyncStorageEngine.getSyncHistory();
if (items != null && items.size() > 0) {
@@ -2132,7 +2132,8 @@ class SyncManager implements OnAccountsUpdatedListener {
final long now = System.currentTimeMillis();
EventLog.writeEvent(2720, syncOperation.authority,
- SyncStorageEngine.EVENT_START, source);
+ SyncStorageEngine.EVENT_START, source,
+ syncOperation.account.name.hashCode());
return mSyncStorageEngine.insertStartSyncEvent(
syncOperation.account, syncOperation.authority, now, source);
@@ -2141,7 +2142,8 @@ class SyncManager implements OnAccountsUpdatedListener {
public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
int upstreamActivity, int downstreamActivity, long elapsedTime) {
EventLog.writeEvent(2720, syncOperation.authority,
- SyncStorageEngine.EVENT_STOP, syncOperation.syncSource);
+ SyncStorageEngine.EVENT_STOP, syncOperation.syncSource,
+ syncOperation.account.name.hashCode());
mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime, resultMessage,
downstreamActivity, upstreamActivity);
@@ -2173,7 +2175,7 @@ class SyncManager implements OnAccountsUpdatedListener {
syncOperation.pendingOperation = op;
add(syncOperation, op);
}
-
+
if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(true /* check the DB */);
}
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index 6687fcb..b8fda03 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -38,6 +38,7 @@ public class SyncStatusInfo implements Parcelable {
public String lastFailureMesg;
public long initialFailureTime;
public boolean pending;
+ public boolean initialize;
SyncStatusInfo(int authorityId) {
this.authorityId = authorityId;
@@ -73,6 +74,7 @@ public class SyncStatusInfo implements Parcelable {
parcel.writeString(lastFailureMesg);
parcel.writeLong(initialFailureTime);
parcel.writeInt(pending ? 1 : 0);
+ parcel.writeInt(initialize ? 1 : 0);
}
SyncStatusInfo(Parcel parcel) {
@@ -94,6 +96,7 @@ public class SyncStatusInfo implements Parcelable {
lastFailureMesg = parcel.readString();
initialFailureTime = parcel.readLong();
pending = parcel.readInt() != 0;
+ initialize = parcel.readInt() != 0;
}
public static final Creator<SyncStatusInfo> CREATOR = new Creator<SyncStatusInfo>() {
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index f251984..fbdd5ae 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -346,16 +346,6 @@ public class SyncStorageEngine extends Handler {
}
}
}
- // Inform the backup manager about a data change
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- if (ibm != null) {
- try {
- ibm.dataChanged("com.android.providers.settings");
- } catch (RemoteException e) {
- // Try again later
- }
- }
}
public boolean getSyncAutomatically(Account account, String providerName) {
@@ -521,6 +511,9 @@ public class SyncStorageEngine extends Handler {
SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
status.pending = true;
+ status.initialize = op.extras != null &&
+ op.extras.containsKey(ContentResolver.SYNC_EXTRAS_INITIALIZE) &&
+ op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE);
}
reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 50faf57..11c67cc 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -274,6 +274,25 @@ public class CompatibilityInfo {
* Apply translation to the canvas that is necessary to draw the content.
*/
public void translateCanvas(Canvas canvas) {
+ if (applicationScale == 1.5f) {
+ /* When we scale for compatibility, we can put our stretched
+ bitmaps and ninepatches on exacty 1/2 pixel boundaries,
+ which can give us inconsistent drawing due to imperfect
+ float precision in the graphics engine's inverse matrix.
+
+ As a work-around, we translate by a tiny amount to avoid
+ landing on exact pixel centers and boundaries, giving us
+ the slop we need to draw consistently.
+
+ This constant is meant to resolve to 1/255 after it is
+ scaled by 1.5 (applicationScale). Note, this is just a guess
+ as to what is small enough not to create its own artifacts,
+ and big enough to avoid the precision problems. Feel free
+ to experiment with smaller values as you choose.
+ */
+ final float tinyOffset = 2.0f / (3 * 255);
+ canvas.translate(tinyOffset, tinyOffset);
+ }
canvas.scale(applicationScale, applicationScale);
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 13effe0..5f1a3c5 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -137,7 +137,6 @@ public class Camera {
*
* @throws IOException if the method fails.
*
- * FIXME: Unhide after approval
* @hide
*/
public native final void reconnect() throws IOException;
@@ -150,25 +149,20 @@ public class Camera {
* Camera object is locked. Locking it again from the same process will
* have no effect. Attempting to lock it from another process if it has
* not been unlocked will fail.
- * Returns 0 if lock was successful.
*
- * FIXME: Unhide after approval
- * @hide
+ * @throws RuntimeException if the method fails.
*/
- public native final int lock();
+ public native final void lock();
/**
* Unlock the camera to allow another process to access it. To save
* setup/teardown time, a client of Camera can pass an initialized Camera
* object to another process. This method is used to unlock the Camera
* object before handing off the Camera object to the other process.
-
- * Returns 0 if unlock was successful.
*
- * FIXME: Unhide after approval
- * @hide
+ * @throws RuntimeException if the method fails.
*/
- public native final int unlock();
+ public native final void unlock();
/**
* Sets the SurfaceHolder to be used for a picture preview. If the surface
@@ -363,10 +357,12 @@ public class Camera {
/**
* Starts auto-focus function and registers a callback function to run when
- * camera is focused. Only valid after startPreview() has been called. If
- * the camera does not support auto-focus, it is a no-op and {@link
- * AutoFocusCallback#onAutoFocus(boolean, Camera)} callback will be called
- * immediately.
+ * camera is focused. Only valid after startPreview() has been called.
+ * Applications should call {@link
+ * android.hardware.Camera.Parameters#getFocusMode()} to determine if this
+ * method should be called. If the camera does not support auto-focus, it is
+ * a no-op and {@link AutoFocusCallback#onAutoFocus(boolean, Camera)}
+ * callback will be called immediately.
* <p>If your application should not be installed
* on devices without auto-focus, you must declare that your application
* uses auto-focus with the
@@ -604,6 +600,7 @@ public class Camera {
private static final String KEY_ANTIBANDING = "antibanding";
private static final String KEY_SCENE_MODE = "scene-mode";
private static final String KEY_FLASH_MODE = "flash-mode";
+ private static final String KEY_FOCUS_MODE = "focus-mode";
// Parameter key suffix for supported values.
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -652,6 +649,10 @@ public class Camera {
* Flash will be fired in red-eye reduction mode.
*/
public static final String FLASH_MODE_RED_EYE = "red-eye";
+ /**
+ * Constant emission of light. This can be used for video recording.
+ */
+ public static final String FLASH_MODE_VIDEO_LIGHT = "video-light";
// Values for scene mode settings.
public static final String SCENE_MODE_AUTO = "auto";
@@ -670,9 +671,29 @@ public class Camera {
public static final String SCENE_MODE_PARTY = "party";
public static final String SCENE_MODE_CANDLELIGHT = "candlelight";
+ // Values for focus mode settings.
+ /**
+ * Auto-focus mode.
+ */
+ public static final String FOCUS_MODE_AUTO = "auto";
+ /**
+ * Focus is set at infinity. Applications should not call
+ * {@link #autoFocus(AutoFocusCallback)} in this mode.
+ */
+ public static final String FOCUS_MODE_INFINITY = "infinity";
+ public static final String FOCUS_MODE_MACRO = "macro";
+ /**
+ * Focus is fixed. The camera is always in this mode if the focus is not
+ * adjustable. If the camera has auto-focus, this mode can fix the
+ * focus, which is usually at hyperfocal distance. Applications should
+ * not call {@link #autoFocus(AutoFocusCallback)} in this mode.
+ */
+ public static final String FOCUS_MODE_FIXED = "fixed";
+
// Formats for setPreviewFormat and setPictureFormat.
private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp";
+ private static final String PIXEL_FORMAT_YUV422I = "yuv422i-yuyv";
private static final String PIXEL_FORMAT_RGB565 = "rgb565";
private static final String PIXEL_FORMAT_JPEG = "jpeg";
@@ -957,7 +978,13 @@ public class Camera {
*/
public List<Integer> getSupportedPreviewFormats() {
String str = get(KEY_PREVIEW_FORMAT + SUPPORTED_VALUES_SUFFIX);
- return splitInt(str);
+ ArrayList<Integer> formats = new ArrayList<Integer>();
+ for (String s : split(str)) {
+ int f = pixelFormatForCameraFormat(s);
+ if (f == PixelFormat.UNKNOWN) continue;
+ formats.add(f);
+ }
+ return formats;
}
/**
@@ -1036,6 +1063,7 @@ public class Camera {
switch(pixel_format) {
case PixelFormat.YCbCr_422_SP: return PIXEL_FORMAT_YUV422SP;
case PixelFormat.YCbCr_420_SP: return PIXEL_FORMAT_YUV420SP;
+ case PixelFormat.YCbCr_422_I: return PIXEL_FORMAT_YUV422I;
case PixelFormat.RGB_565: return PIXEL_FORMAT_RGB565;
case PixelFormat.JPEG: return PIXEL_FORMAT_JPEG;
default: return null;
@@ -1052,6 +1080,9 @@ public class Camera {
if (format.equals(PIXEL_FORMAT_YUV420SP))
return PixelFormat.YCbCr_420_SP;
+ if (format.equals(PIXEL_FORMAT_YUV422I))
+ return PixelFormat.YCbCr_422_I;
+
if (format.equals(PIXEL_FORMAT_RGB565))
return PixelFormat.RGB_565;
@@ -1290,6 +1321,39 @@ public class Camera {
return split(str);
}
+ /**
+ * Gets the current focus mode setting.
+ *
+ * @return one of FOCUS_MODE_XXX string constant. If the camera does not
+ * support auto-focus, this should return {@link
+ * #FOCUS_MODE_FIXED}. If the focus mode is not FOCUS_MODE_FIXED
+ * or {@link #FOCUS_MODE_INFINITY}, applications should call
+ * {@link #autoFocus(AutoFocusCallback)} to start the focus.
+ */
+ public String getFocusMode() {
+ return get(KEY_FOCUS_MODE);
+ }
+
+ /**
+ * Sets the focus mode.
+ *
+ * @param value FOCUS_MODE_XXX string constants.
+ */
+ public void setFocusMode(String value) {
+ set(KEY_FOCUS_MODE, value);
+ }
+
+ /**
+ * Gets the supported focus modes.
+ *
+ * @return a List of FOCUS_MODE_XXX string constants. null if focus mode
+ * setting is not supported.
+ */
+ public List<String> getSupportedFocusModes() {
+ String str = get(KEY_FOCUS_MODE + SUPPORTED_VALUES_SUFFIX);
+ return split(str);
+ }
+
// Splits a comma delimited string to an ArrayList of String.
// Return null if the passing string is null or the size is 0.
private ArrayList<String> split(String str) {
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 8f1a756..44b73c5 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -18,10 +18,73 @@ package android.os;
/**
* The BatteryManager class contains strings and constants used for values
- * in the ACTION_BATTERY_CHANGED Intent.
+ * in the {@link android.content.Intent#ACTION_BATTERY_CHANGED} Intent.
*/
public class BatteryManager {
-
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current status constant.
+ */
+ public static final String EXTRA_STATUS = "status";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current health constant.
+ */
+ public static final String EXTRA_HEALTH = "health";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * boolean indicating whether a battery is present.
+ */
+ public static final String EXTRA_PRESENT = "present";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer field containing the current battery level, from 0 to
+ * {@link #EXTRA_SCALE}.
+ */
+ public static final String EXTRA_LEVEL = "level";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the maximum battery level.
+ */
+ public static final String EXTRA_SCALE = "scale";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the resource ID of a small status bar icon
+ * indicating the current battery state.
+ */
+ public static final String EXTRA_ICON_SMALL = "icon-small";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer indicating whether the device is plugged in to a power
+ * source; 0 means it is on battery, other constants are different
+ * types of power sources.
+ */
+ public static final String EXTRA_PLUGGED = "plugged";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current battery voltage level.
+ */
+ public static final String EXTRA_VOLTAGE = "voltage";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * integer containing the current battery temperature.
+ */
+ public static final String EXTRA_TEMPERATURE = "temperature";
+
+ /**
+ * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+ * String describing the technology of the current battery.
+ */
+ public static final String EXTRA_TECHNOLOGY = "technology";
+
// values for "status" field in the ACTION_BATTERY_CHANGED Intent
public static final int BATTERY_STATUS_UNKNOWN = 1;
public static final int BATTERY_STATUS_CHARGING = 2;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e203fd5..a49a27a0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -314,6 +314,15 @@ public abstract class BatteryStats implements Parcelable {
* @return foreground cpu time in microseconds
*/
public abstract long getForegroundTime(int which);
+
+ /**
+ * Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
+ * @param speedStep the index of the CPU speed. This is not the actual speed of the
+ * CPU.
+ * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+ * @see BatteryStats#getCpuSpeedSteps()
+ */
+ public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
}
/**
@@ -573,6 +582,9 @@ public abstract class BatteryStats implements Parcelable {
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
+ /** Returns the number of different speeds that the CPU can run at */
+ public abstract int getCpuSpeedSteps();
+
private final static void formatTimeRaw(StringBuilder out, long seconds) {
long days = seconds / (60 * 60 * 24);
if (days != 0) {
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index b337d28..a264594 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -121,6 +121,9 @@ public class VolumePreference extends SeekBarPreference implements
if (mSeekBarVolumizer != null) {
Dialog dialog = getDialog();
if (dialog != null && dialog.isShowing()) {
+ View view = dialog.getWindow().getDecorView()
+ .findViewById(com.android.internal.R.id.seekbar);
+ if (view != null) view.setOnKeyListener(null);
// Stopped while dialog was showing, revert changes
mSeekBarVolumizer.revertVolume();
}
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 1de971b..f046cef 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -110,6 +110,7 @@ public final class Calendar {
public static final int EDITOR_ACCESS = 600;
/** Full access to the calendar */
public static final int OWNER_ACCESS = 700;
+ /** Domain admin */
public static final int ROOT_ACCESS = 800;
/**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 93ee3ba..3df228d 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -410,7 +410,8 @@ public final class ContactsContract {
private AggregationSuggestions() {}
/**
- * The directory twig for this sub-table
+ * The directory twig for this sub-table. The URI can be followed by an optional
+ * type-to-filter, similar to {@link Contacts#CONTENT_FILTER_URI}.
*/
public static final String CONTENT_DIRECTORY = "suggestions";
}
@@ -677,12 +678,20 @@ public final class ContactsContract {
}
/**
+ * Combines all columns returned by {@link Data} table queries.
+ */
+ private interface DataColumnsWithJoins extends BaseColumns, DataColumns, RawContactsColumns,
+ ContactsColumns, ContactOptionsColumns {
+
+ }
+
+ /**
* Constants for the data table, which contains data points tied to a raw contact.
* For example, a phone number or email address. Each row in this table contains a type
* definition and some generic columns. Each data type can define the meaning for each of
* the generic columns.
*/
- public static final class Data implements BaseColumns, DataColumns {
+ public final static class Data implements DataColumnsWithJoins {
/**
* This utility class cannot be instantiated
*/
@@ -892,32 +901,9 @@ public final class ContactsContract {
public static final String PACKAGE_COMMON = "common";
/**
- * Columns common across the specific types.
- */
- private interface BaseCommonColumns {
- /**
- * The package name to use when creating {@link Resources} objects for
- * this data row. This value is only designed for use when building user
- * interfaces, and should not be used to infer the owner.
- */
- public static final String RES_PACKAGE = "res_package";
-
- /**
- * The MIME type of the item represented by this row.
- */
- public static final String MIMETYPE = "mimetype";
-
- /**
- * The {@link RawContacts#_ID} that this data belongs to.
- */
- public static final String RAW_CONTACT_ID = "raw_contact_id";
- }
-
- /**
* The base types that all "Typed" data kinds support.
*/
public interface BaseTypes {
-
/**
* A custom type. The custom label should be supplied by user.
*/
@@ -927,96 +913,96 @@ public final class ContactsContract {
/**
* Columns common across the specific types.
*/
- private interface CommonColumns extends BaseTypes{
+ private interface CommonColumns extends BaseTypes {
/**
- * The type of data, for example Home or Work.
- * <P>Type: INTEGER</P>
+ * The data for the contact method.
+ * <P>Type: TEXT</P>
*/
- public static final String TYPE = "data1";
+ public static final String DATA = DataColumns.DATA1;
/**
- * The data for the contact method.
- * <P>Type: TEXT</P>
+ * The type of data, for example Home or Work.
+ * <P>Type: INTEGER</P>
*/
- public static final String DATA = "data2";
+ public static final String TYPE = DataColumns.DATA2;
/**
* The user defined label for the the contact method.
* <P>Type: TEXT</P>
*/
- public static final String LABEL = "data3";
+ public static final String LABEL = DataColumns.DATA3;
}
/**
* Parts of the name.
*/
- public static final class StructuredName implements BaseCommonColumns {
+ public static final class StructuredName implements DataColumnsWithJoins {
private StructuredName() {}
/** MIME type used when storing this in data table. */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
/**
+ * The name that should be used to display the contact.
+ * <i>Unstructured component of the name should be consistent with
+ * its structured representation.</i>
+ * <p>
+ * Type: TEXT
+ */
+ public static final String DISPLAY_NAME = DATA1;
+
+ /**
* The given name for the contact.
* <P>Type: TEXT</P>
*/
- public static final String GIVEN_NAME = "data1";
+ public static final String GIVEN_NAME = DATA2;
/**
* The family name for the contact.
* <P>Type: TEXT</P>
*/
- public static final String FAMILY_NAME = "data2";
+ public static final String FAMILY_NAME = DATA3;
/**
* The contact's honorific prefix, e.g. "Sir"
* <P>Type: TEXT</P>
*/
- public static final String PREFIX = "data3";
+ public static final String PREFIX = DATA4;
/**
* The contact's middle name
* <P>Type: TEXT</P>
*/
- public static final String MIDDLE_NAME = "data4";
+ public static final String MIDDLE_NAME = DATA5;
/**
* The contact's honorific suffix, e.g. "Jr"
*/
- public static final String SUFFIX = "data5";
+ public static final String SUFFIX = DATA6;
/**
* The phonetic version of the given name for the contact.
* <P>Type: TEXT</P>
*/
- public static final String PHONETIC_GIVEN_NAME = "data6";
+ public static final String PHONETIC_GIVEN_NAME = DATA7;
/**
* The phonetic version of the additional name for the contact.
* <P>Type: TEXT</P>
*/
- public static final String PHONETIC_MIDDLE_NAME = "data7";
+ public static final String PHONETIC_MIDDLE_NAME = DATA8;
/**
* The phonetic version of the family name for the contact.
* <P>Type: TEXT</P>
*/
- public static final String PHONETIC_FAMILY_NAME = "data8";
-
- /**
- * The name that should be used to display the contact.
- * <i>Unstructured component of the name should be consistent with
- * its structured representation.</i>
- * <p>
- * Type: TEXT
- */
- public static final String DISPLAY_NAME = "data9";
+ public static final String PHONETIC_FAMILY_NAME = DATA9;
}
/**
* A nickname.
*/
- public static final class Nickname implements CommonColumns, BaseCommonColumns {
+ public static final class Nickname implements DataColumnsWithJoins, CommonColumns {
private Nickname() {}
/** MIME type used when storing this in data table. */
@@ -1037,7 +1023,7 @@ public final class ContactsContract {
/**
* Common data definition for telephone numbers.
*/
- public static final class Phone implements BaseCommonColumns, CommonColumns {
+ public static final class Phone implements DataColumnsWithJoins, CommonColumns {
private Phone() {}
/** MIME type used when storing this in data table. */
@@ -1093,43 +1079,85 @@ public final class ContactsContract {
*/
public static final String NUMBER = DATA;
+ /**
+ * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
+ */
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label, CharSequence[] labelArray) {
- CharSequence display = "";
-
- if (type != Phone.TYPE_CUSTOM) {
- CharSequence[] labels = labelArray != null? labelArray
- : context.getResources().getTextArray(
- com.android.internal.R.array.phoneTypes);
- try {
- display = labels[type - 1];
- } catch (ArrayIndexOutOfBoundsException e) {
- display = labels[Phone.TYPE_CUSTOM];
- }
- } else {
- if (!TextUtils.isEmpty(label)) {
- display = label;
- }
- }
- return display;
+ return getTypeLabel(context.getResources(), type, label);
}
+ /**
+ * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
+ */
+ @Deprecated
public static final CharSequence getDisplayLabel(Context context, int type,
CharSequence label) {
- return getDisplayLabel(context, type, label, null);
+ return getTypeLabel(context.getResources(), type, label);
+ }
+
+ /**
+ * Return the string resource that best describes the given
+ * {@link CommonColumns#TYPE}. Will always return a valid resource.
+ */
+ public static final int getTypeLabelResource(int type) {
+ switch (type) {
+ case TYPE_HOME: return com.android.internal.R.string.phoneTypeHome;
+ case TYPE_MOBILE: return com.android.internal.R.string.phoneTypeMobile;
+ case TYPE_WORK: return com.android.internal.R.string.phoneTypeWork;
+ case TYPE_FAX_WORK: return com.android.internal.R.string.phoneTypeFaxWork;
+ case TYPE_FAX_HOME: return com.android.internal.R.string.phoneTypeFaxHome;
+ case TYPE_PAGER: return com.android.internal.R.string.phoneTypePager;
+ case TYPE_OTHER: return com.android.internal.R.string.phoneTypeOther;
+ case TYPE_CALLBACK: return com.android.internal.R.string.phoneTypeCallback;
+ case TYPE_CAR: return com.android.internal.R.string.phoneTypeCar;
+ case TYPE_COMPANY_MAIN: return com.android.internal.R.string.phoneTypeCompanyMain;
+ case TYPE_ISDN: return com.android.internal.R.string.phoneTypeIsdn;
+ case TYPE_MAIN: return com.android.internal.R.string.phoneTypeMain;
+ case TYPE_OTHER_FAX: return com.android.internal.R.string.phoneTypeOtherFax;
+ case TYPE_RADIO: return com.android.internal.R.string.phoneTypeRadio;
+ case TYPE_TELEX: return com.android.internal.R.string.phoneTypeTelex;
+ case TYPE_TTY_TDD: return com.android.internal.R.string.phoneTypeTtyTdd;
+ case TYPE_WORK_MOBILE: return com.android.internal.R.string.phoneTypeWorkMobile;
+ case TYPE_WORK_PAGER: return com.android.internal.R.string.phoneTypeWorkPager;
+ case TYPE_ASSISTANT: return com.android.internal.R.string.phoneTypeAssistant;
+ case TYPE_MMS: return com.android.internal.R.string.phoneTypeMms;
+ default: return com.android.internal.R.string.phoneTypeCustom;
+ }
+ }
+
+ /**
+ * Return a {@link CharSequence} that best describes the given type,
+ * possibly substituting the given {@link CommonColumns#LABEL} value
+ * for {@link BaseTypes#TYPE_CUSTOM}.
+ */
+ public static final CharSequence getTypeLabel(Resources res, int type,
+ CharSequence label) {
+ if ((type == TYPE_CUSTOM || type == TYPE_ASSISTANT) && !TextUtils.isEmpty(label)) {
+ return label;
+ } else {
+ final int labelRes = getTypeLabelResource(type);
+ return res.getText(labelRes);
+ }
}
}
/**
* Common data definition for email addresses.
*/
- public static final class Email implements BaseCommonColumns, CommonColumns {
+ public static final class Email implements DataColumnsWithJoins, CommonColumns {
private Email() {}
/** MIME type used when storing this in data table. */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2";
/**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of email addresses.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2";
+
+ /**
* The content:// style URI for all data records of the
* {@link Email#CONTENT_ITEM_TYPE} MIME type, combined with the
* associated raw contact and aggregate contact data.
@@ -1145,9 +1173,6 @@ public final class ContactsContract {
public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
"lookup");
- @Deprecated
- public static final Uri CONTENT_FILTER_EMAIL_URI = CONTENT_LOOKUP_URI;
-
/**
* The content:// style URL for email lookup using a filter. The filter returns
* records of MIME type {@link Email#CONTENT_ITEM_TYPE}. The filter is applied
@@ -1166,13 +1191,42 @@ public final class ContactsContract {
* The display name for the email address
* <P>Type: TEXT</P>
*/
- public static final String DISPLAY_NAME = "data4";
+ public static final String DISPLAY_NAME = DATA4;
+
+ /**
+ * Return the string resource that best describes the given
+ * {@link CommonColumns#TYPE}. Will always return a valid resource.
+ */
+ public static final int getTypeLabelResource(int type) {
+ switch (type) {
+ case TYPE_HOME: return com.android.internal.R.string.emailTypeHome;
+ case TYPE_WORK: return com.android.internal.R.string.emailTypeWork;
+ case TYPE_OTHER: return com.android.internal.R.string.emailTypeOther;
+ case TYPE_MOBILE: return com.android.internal.R.string.emailTypeMobile;
+ default: return com.android.internal.R.string.emailTypeCustom;
+ }
+ }
+
+ /**
+ * Return a {@link CharSequence} that best describes the given type,
+ * possibly substituting the given {@link CommonColumns#LABEL} value
+ * for {@link BaseTypes#TYPE_CUSTOM}.
+ */
+ public static final CharSequence getTypeLabel(Resources res, int type,
+ CharSequence label) {
+ if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+ return label;
+ } else {
+ final int labelRes = getTypeLabelResource(type);
+ return res.getText(labelRes);
+ }
+ }
}
/**
* Common data definition for postal addresses.
*/
- public static final class StructuredPostal implements BaseCommonColumns, CommonColumns {
+ public static final class StructuredPostal implements DataColumnsWithJoins, CommonColumns {
private StructuredPostal() {
}
@@ -1211,7 +1265,7 @@ public final class ContactsContract {
* <p>
* Type: TEXT
*/
- public static final String STREET = "data6";
+ public static final String STREET = DATA4;
/**
* Covers actual P.O. boxes, drawers, locked bags, etc. This is
@@ -1219,7 +1273,7 @@ public final class ContactsContract {
* <p>
* Type: TEXT
*/
- public static final String POBOX = "data7";
+ public static final String POBOX = DATA5;
/**
* This is used to disambiguate a street address when a city
@@ -1229,7 +1283,7 @@ public final class ContactsContract {
* <p>
* Type: TEXT
*/
- public static final String NEIGHBORHOOD = "data8";
+ public static final String NEIGHBORHOOD = DATA6;
/**
* Can be city, village, town, borough, etc. This is the postal town
@@ -1237,7 +1291,7 @@ public final class ContactsContract {
* <p>
* Type: TEXT
*/
- public static final String CITY = "data9";
+ public static final String CITY = DATA7;
/**
* A state, province, county (in Ireland), Land (in Germany),
@@ -1245,7 +1299,7 @@ public final class ContactsContract {
* <p>
* Type: TEXT
*/
- public static final String REGION = "data11";
+ public static final String REGION = DATA8;
/**
* Postal code. Usually country-wide, but sometimes specific to the
@@ -1253,20 +1307,48 @@ public final class ContactsContract {
* <p>
* Type: TEXT
*/
- public static final String POSTCODE = "data12";
+ public static final String POSTCODE = DATA9;
/**
* The name or code of the country.
* <p>
* Type: TEXT
*/
- public static final String COUNTRY = "data13";
+ public static final String COUNTRY = DATA10;
+
+ /**
+ * Return the string resource that best describes the given
+ * {@link CommonColumns#TYPE}. Will always return a valid resource.
+ */
+ public static final int getTypeLabelResource(int type) {
+ switch (type) {
+ case TYPE_HOME: return com.android.internal.R.string.postalTypeHome;
+ case TYPE_WORK: return com.android.internal.R.string.postalTypeWork;
+ case TYPE_OTHER: return com.android.internal.R.string.postalTypeOther;
+ default: return com.android.internal.R.string.postalTypeCustom;
+ }
+ }
+
+ /**
+ * Return a {@link CharSequence} that best describes the given type,
+ * possibly substituting the given {@link CommonColumns#LABEL} value
+ * for {@link BaseTypes#TYPE_CUSTOM}.
+ */
+ public static final CharSequence getTypeLabel(Resources res, int type,
+ CharSequence label) {
+ if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+ return label;
+ } else {
+ final int labelRes = getTypeLabelResource(type);
+ return res.getText(labelRes);
+ }
+ }
}
/**
* Common data definition for IM addresses.
*/
- public static final class Im implements BaseCommonColumns, CommonColumns {
+ public static final class Im implements DataColumnsWithJoins, CommonColumns {
private Im() {}
/** MIME type used when storing this in data table. */
@@ -1282,9 +1364,9 @@ public final class ContactsContract {
* column is {@link #PROTOCOL_CUSTOM}, the {@link #CUSTOM_PROTOCOL}
* should contain the name of the custom protocol.
*/
- public static final String PROTOCOL = "data5";
+ public static final String PROTOCOL = DATA5;
- public static final String CUSTOM_PROTOCOL = "data6";
+ public static final String CUSTOM_PROTOCOL = DATA6;
/*
* The predefined IM protocol types.
@@ -1299,12 +1381,74 @@ public final class ContactsContract {
public static final int PROTOCOL_ICQ = 6;
public static final int PROTOCOL_JABBER = 7;
public static final int PROTOCOL_NETMEETING = 8;
+
+ /**
+ * Return the string resource that best describes the given
+ * {@link CommonColumns#TYPE}. Will always return a valid resource.
+ */
+ public static final int getTypeLabelResource(int type) {
+ switch (type) {
+ case TYPE_HOME: return com.android.internal.R.string.imTypeHome;
+ case TYPE_WORK: return com.android.internal.R.string.imTypeWork;
+ case TYPE_OTHER: return com.android.internal.R.string.imTypeOther;
+ default: return com.android.internal.R.string.imTypeCustom;
+ }
+ }
+
+ /**
+ * Return a {@link CharSequence} that best describes the given type,
+ * possibly substituting the given {@link CommonColumns#LABEL} value
+ * for {@link BaseTypes#TYPE_CUSTOM}.
+ */
+ public static final CharSequence getTypeLabel(Resources res, int type,
+ CharSequence label) {
+ if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+ return label;
+ } else {
+ final int labelRes = getTypeLabelResource(type);
+ return res.getText(labelRes);
+ }
+ }
+
+ /**
+ * Return the string resource that best describes the given
+ * {@link Im#PROTOCOL}. Will always return a valid resource.
+ */
+ public static final int getProtocolLabelResource(int type) {
+ switch (type) {
+ case PROTOCOL_AIM: return com.android.internal.R.string.imProtocolAim;
+ case PROTOCOL_MSN: return com.android.internal.R.string.imProtocolMsn;
+ case PROTOCOL_YAHOO: return com.android.internal.R.string.imProtocolYahoo;
+ case PROTOCOL_SKYPE: return com.android.internal.R.string.imProtocolSkype;
+ case PROTOCOL_QQ: return com.android.internal.R.string.imProtocolQq;
+ case PROTOCOL_GOOGLE_TALK: return com.android.internal.R.string.imProtocolGoogleTalk;
+ case PROTOCOL_ICQ: return com.android.internal.R.string.imProtocolIcq;
+ case PROTOCOL_JABBER: return com.android.internal.R.string.imProtocolJabber;
+ case PROTOCOL_NETMEETING: return com.android.internal.R.string.imProtocolNetMeeting;
+ default: return com.android.internal.R.string.imProtocolCustom;
+ }
+ }
+
+ /**
+ * Return a {@link CharSequence} that best describes the given
+ * protocol, possibly substituting the given
+ * {@link #CUSTOM_PROTOCOL} value for {@link #PROTOCOL_CUSTOM}.
+ */
+ public static final CharSequence getProtocolLabel(Resources res, int type,
+ CharSequence label) {
+ if (type == PROTOCOL_CUSTOM && !TextUtils.isEmpty(label)) {
+ return label;
+ } else {
+ final int labelRes = getProtocolLabelResource(type);
+ return res.getText(labelRes);
+ }
+ }
}
/**
* Common data definition for organizations.
*/
- public static final class Organization implements BaseCommonColumns, CommonColumns {
+ public static final class Organization implements DataColumnsWithJoins, CommonColumns {
private Organization() {}
/** MIME type used when storing this in data table. */
@@ -1323,37 +1467,64 @@ public final class ContactsContract {
* The position title at this company as the user entered it.
* <P>Type: TEXT</P>
*/
- public static final String TITLE = "data4";
+ public static final String TITLE = DATA4;
/**
* The department at this company as the user entered it.
* <P>Type: TEXT</P>
*/
- public static final String DEPARTMENT = "data5";
+ public static final String DEPARTMENT = DATA5;
/**
* The job description at this company as the user entered it.
* <P>Type: TEXT</P>
*/
- public static final String JOB_DESCRIPTION = "data6";
+ public static final String JOB_DESCRIPTION = DATA6;
/**
* The symbol of this company as the user entered it.
* <P>Type: TEXT</P>
*/
- public static final String SYMBOL = "data7";
+ public static final String SYMBOL = DATA7;
/**
* The phonetic name of this company as the user entered it.
* <P>Type: TEXT</P>
*/
- public static final String PHONETIC_NAME = "data8";
+ public static final String PHONETIC_NAME = DATA8;
+
+ /**
+ * Return the string resource that best describes the given
+ * {@link CommonColumns#TYPE}. Will always return a valid resource.
+ */
+ public static final int getTypeLabelResource(int type) {
+ switch (type) {
+ case TYPE_WORK: return com.android.internal.R.string.orgTypeWork;
+ case TYPE_OTHER: return com.android.internal.R.string.orgTypeOther;
+ default: return com.android.internal.R.string.orgTypeCustom;
+ }
+ }
+
+ /**
+ * Return a {@link CharSequence} that best describes the given type,
+ * possibly substituting the given {@link CommonColumns#LABEL} value
+ * for {@link BaseTypes#TYPE_CUSTOM}.
+ */
+ public static final CharSequence getTypeLabel(Resources res, int type,
+ CharSequence label) {
+ if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+ return label;
+ } else {
+ final int labelRes = getTypeLabelResource(type);
+ return res.getText(labelRes);
+ }
+ }
}
/**
* Common data definition for miscellaneous information.
*/
- public static final class Miscellaneous implements BaseCommonColumns {
+ public static final class Miscellaneous implements DataColumnsWithJoins {
private Miscellaneous() {}
/** MIME type used when storing this in data table. */
@@ -1363,19 +1534,19 @@ public final class ContactsContract {
* The birthday as the user entered it.
* <P>Type: TEXT</P>
*/
- public static final String BIRTHDAY = "data1";
+ public static final String BIRTHDAY = DATA1;
/**
* The nickname as the user entered it.
* <P>Type: TEXT</P>
*/
- public static final String NICKNAME = "data2";
+ public static final String NICKNAME = DATA2;
}
/**
* Common data definition for relations.
*/
- public static final class Relation implements BaseCommonColumns, CommonColumns {
+ public static final class Relation implements DataColumnsWithJoins, CommonColumns {
private Relation() {}
/** MIME type used when storing this in data table. */
@@ -1406,7 +1577,7 @@ public final class ContactsContract {
/**
* Common data definition for events.
*/
- public static final class Event implements BaseCommonColumns, CommonColumns {
+ public static final class Event implements DataColumnsWithJoins, CommonColumns {
private Event() {}
/** MIME type used when storing this in data table. */
@@ -1425,7 +1596,7 @@ public final class ContactsContract {
/**
* Photo of the contact.
*/
- public static final class Photo implements BaseCommonColumns {
+ public static final class Photo implements DataColumnsWithJoins {
private Photo() {}
/** MIME type used when storing this in data table. */
@@ -1437,13 +1608,13 @@ public final class ContactsContract {
* <p>
* Type: BLOB
*/
- public static final String PHOTO = "data1";
+ public static final String PHOTO = DATA15;
}
/**
* Notes about the contact.
*/
- public static final class Note implements BaseCommonColumns {
+ public static final class Note implements DataColumnsWithJoins {
private Note() {}
/** MIME type used when storing this in data table. */
@@ -1453,13 +1624,13 @@ public final class ContactsContract {
* The note text.
* <P>Type: TEXT</P>
*/
- public static final String NOTE = "data1";
+ public static final String NOTE = DATA1;
}
/**
* Group Membership.
*/
- public static final class GroupMembership implements BaseCommonColumns {
+ public static final class GroupMembership implements DataColumnsWithJoins {
private GroupMembership() {}
/** MIME type used when storing this in data table. */
@@ -1471,7 +1642,7 @@ public final class ContactsContract {
* this or {@link #GROUP_SOURCE_ID} must be set when inserting a row.
* <P>Type: INTEGER</P>
*/
- public static final String GROUP_ROW_ID = "data1";
+ public static final String GROUP_ROW_ID = DATA1;
/**
* The sourceid of the group that this group membership refers to. Exactly one of
@@ -1484,7 +1655,7 @@ public final class ContactsContract {
/**
* Website related to the contact.
*/
- public static final class Website implements BaseCommonColumns, CommonColumns {
+ public static final class Website implements DataColumnsWithJoins, CommonColumns {
private Website() {}
/** MIME type used when storing this in data table. */
@@ -1502,7 +1673,7 @@ public final class ContactsContract {
* The website URL string.
* <P>Type: TEXT</P>
*/
- public static final String URL = "data1";
+ public static final String URL = DATA;
}
}
@@ -1672,24 +1843,12 @@ public final class ContactsContract {
*/
public static final int TYPE_KEEP_TOGETHER = 1;
- @Deprecated
- public static final int TYPE_KEEP_IN = 1;
-
/**
* Makes sure that the specified raw contacts are NOT included in the same
* aggregate contact.
*/
public static final int TYPE_KEEP_SEPARATE = 2;
- @Deprecated
- public static final int TYPE_KEEP_OUT = 2;
-
- @Deprecated
- public static final String CONTACT_ID = "contact_id";
-
- @Deprecated
- public static final String RAW_CONTACT_ID = "raw_contact_id";
-
/**
* A reference to the {@link RawContacts#_ID} of the raw contact that the rule applies to.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1d41df2..6cf8db6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2406,7 +2406,6 @@ public final class Settings {
WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
WIFI_NUM_ALLOWED_CHANNELS,
WIFI_NUM_OPEN_NETWORKS_KEPT,
- BACKGROUND_DATA,
};
/**
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index ba53307..f3bc3a6 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -247,7 +247,6 @@ class BluetoothEventLoop {
addDevice(address, properties);
}
}
- mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
return;
}
@@ -266,8 +265,8 @@ class BluetoothEventLoop {
}
String name = propValues[0];
if (name.equals("Name")) {
- Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
- intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
+ Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+ intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, propValues[1]);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mBluetoothService.setProperty(name, propValues[1]);
} else if (name.equals("Pairable") || name.equals("Discoverable")) {
@@ -330,6 +329,9 @@ class BluetoothEventLoop {
Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
return;
}
+ if (DBG) {
+ log("Device property changed:" + address + "property:" + name);
+ }
BluetoothDevice device = mAdapter.getRemoteDevice(address);
if (name.equals("Name")) {
Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
@@ -366,6 +368,11 @@ class BluetoothEventLoop {
uuid = str.toString();
}
mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
+
+ // UUIDs have changed, query remote service channel and update cache.
+ mBluetoothService.updateDeviceServiceChannelCache(address);
+
+ mBluetoothService.sendUuidIntent(address);
} else if (name.equals("Paired")) {
if (propValues[1].equals("true")) {
mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
@@ -396,6 +403,9 @@ class BluetoothEventLoop {
mBluetoothService.cancelPairingUserInput(address);
return null;
}
+ // Set state to BONDING, for incoming connections it will be set here.
+ // For outgoing connections, it gets set when call createBond.
+ mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
return address;
}
@@ -453,8 +463,9 @@ class BluetoothEventLoop {
String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
if (address == null) return;
- if (mBluetoothService.getBondState().getBondState(address) ==
- BluetoothDevice.BOND_BONDING) {
+ String pendingOutgoingAddress =
+ mBluetoothService.getBondState().getPendingOutgoingBonding();
+ if (address.equals(pendingOutgoingAddress)) {
// we initiated the bonding
BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
@@ -528,6 +539,24 @@ class BluetoothEventLoop {
return;
}
+ private void onDiscoverServicesResult(String deviceObjectPath, boolean result) {
+ String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+ // We don't parse the xml here, instead just query Bluez for the properties.
+ if (result) {
+ mBluetoothService.updateRemoteDevicePropertiesCache(address);
+ }
+ mBluetoothService.sendUuidIntent(address);
+ }
+
+ private void onCreateDeviceResult(String address, boolean result) {
+ if (DBG) {
+ log("Result of onCreateDeviceResult:" + result);
+ }
+ if (!result) {
+ mBluetoothService.sendUuidIntent(address);
+ }
+ }
+
private void onRestartRequired() {
if (mBluetoothService.isEnabled()) {
Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index c0e4f34..e5b20bd 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -28,6 +28,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetooth;
import android.bluetooth.ParcelUuid;
import android.content.BroadcastReceiver;
@@ -76,10 +77,18 @@ public class BluetoothService extends IBluetooth.Stub {
private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
private static final int MESSAGE_FINISH_DISABLE = 2;
+ private static final int MESSAGE_UUID_INTENT = 3;
+
+ // The timeout used to sent the UUIDs Intent
+ // This timeout should be greater than the page timeout
+ private static final int UUID_INTENT_DELAY = 6000;
private final Map<String, String> mAdapterProperties;
private final HashMap <String, Map<String, String>> mDeviceProperties;
+ private final HashMap <String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
+ private final ArrayList <String> mUuidIntentTracker;
+
static {
classInitNative();
}
@@ -104,6 +113,9 @@ public class BluetoothService extends IBluetooth.Stub {
mIsDiscovering = false;
mAdapterProperties = new HashMap<String, String>();
mDeviceProperties = new HashMap<String, Map<String,String>>();
+
+ mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
+ mUuidIntentTracker = new ArrayList<String>();
registerForAirplaneMode();
}
@@ -291,6 +303,11 @@ public class BluetoothService extends IBluetooth.Stub {
case MESSAGE_FINISH_DISABLE:
finishDisable(msg.arg1 != 0);
break;
+ case MESSAGE_UUID_INTENT:
+ String address = (String)msg.obj;
+ if (address != null)
+ sendUuidIntent(address);
+ break;
}
}
};
@@ -414,6 +431,18 @@ public class BluetoothService extends IBluetooth.Stub {
new ArrayList<String>(Arrays.asList(
"Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3"));
+ // If this is an outgoing connection, store the address.
+ // There can be only 1 pending outgoing connection at a time,
+ private String mPendingOutgoingBonding;
+
+ private synchronized void setPendingOutgoingBonding(String address) {
+ mPendingOutgoingBonding = address;
+ }
+
+ public synchronized String getPendingOutgoingBonding() {
+ return mPendingOutgoingBonding;
+ }
+
public synchronized void loadBondState() {
if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
return;
@@ -444,6 +473,15 @@ public class BluetoothService extends IBluetooth.Stub {
if (oldState == state) {
return;
}
+
+ // Check if this was an pending outgoing bonding.
+ // If yes, reset the state.
+ if (oldState == BluetoothDevice.BOND_BONDING) {
+ if (address.equals(mPendingOutgoingBonding)) {
+ mPendingOutgoingBonding = null;
+ }
+ }
+
if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
reason + ")");
Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
@@ -766,8 +804,7 @@ public class BluetoothService extends IBluetooth.Stub {
}
address = address.toUpperCase();
- String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING);
- if (bonding.length > 0 && !bonding[0].equals(address)) {
+ if (mBondState.getPendingOutgoingBonding() != null) {
log("Ignoring createBond(): another device is bonding");
// a different device is currently bonding, fail
return false;
@@ -785,7 +822,9 @@ public class BluetoothService extends IBluetooth.Stub {
return false;
}
+ mBondState.setPendingOutgoingBonding(address);
mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
+
return true;
}
@@ -845,16 +884,22 @@ public class BluetoothService extends IBluetooth.Stub {
// Query for remote device properties, again.
// We will need to reload the cache when we switch Bluetooth on / off
// or if we crash.
- String[] propValues = getRemoteDeviceProperties(address);
- if (propValues != null) {
- addRemoteDeviceProperties(address, propValues);
+ if (updateRemoteDevicePropertiesCache(address))
return getRemoteDeviceProperty(address, property);
- }
}
Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
return null;
}
+ /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
+ String[] propValues = getRemoteDeviceProperties(address);
+ if (propValues != null) {
+ addRemoteDeviceProperties(address, propValues);
+ return true;
+ }
+ return false;
+ }
+
/* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
/*
* We get a DeviceFound signal every time RSSI changes or name changes.
@@ -889,6 +934,10 @@ public class BluetoothService extends IBluetooth.Stub {
propertyValues.put(name, newValue);
}
mDeviceProperties.put(address, propertyValues);
+
+ // We have added a new remote device or updated its properties.
+ // Also update the serviceChannel cache.
+ updateDeviceServiceChannelCache(address);
}
/* package */ void removeRemoteDeviceProperties(String address) {
@@ -976,6 +1025,10 @@ public class BluetoothService extends IBluetooth.Stub {
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
return null;
}
+ return getUuidFromCache(address);
+ }
+
+ private ParcelUuid[] getUuidFromCache(String address) {
String value = getRemoteDeviceProperty(address, "UUIDs");
if (value == null) return null;
@@ -990,6 +1043,36 @@ public class BluetoothService extends IBluetooth.Stub {
return uuids;
}
+ public synchronized boolean fetchRemoteUuidsWithSdp(String address) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ return false;
+ }
+
+ if (mUuidIntentTracker.contains(address)) {
+ // An SDP query for this address is already in progress
+ return true;
+ }
+
+ boolean ret;
+ if (getBondState(address) == BluetoothDevice.BOND_BONDED) {
+ String path = getObjectPathFromAddress(address);
+ if (path == null) return false;
+
+ // Use an empty string for the UUID pattern
+ ret = discoverServicesNative(path, "");
+ } else {
+ ret = createDeviceNative(address);
+ }
+
+ mUuidIntentTracker.add(address);
+
+ Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
+ message.obj = address;
+ mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
+ return ret;
+ }
+
/**
* Gets the rfcomm channel associated with the UUID.
*
@@ -997,14 +1080,23 @@ public class BluetoothService extends IBluetooth.Stub {
* @param uuid ParcelUuid of the service attribute
*
* @return rfcomm channel associated with the service attribute
+ * -1 on error
*/
public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
if (!BluetoothAdapter.checkBluetoothAddress(address)) {
return BluetoothDevice.ERROR;
}
- return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
- 0x0004);
+ // Check if we are recovering from a crash.
+ if (mDeviceProperties.isEmpty()) {
+ if (!updateRemoteDevicePropertiesCache(address))
+ return -1;
+ }
+
+ Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
+ if (value != null && value.containsKey(uuid))
+ return value.get(uuid);
+ return -1;
}
public synchronized boolean setPin(String address, byte[] pin) {
@@ -1083,6 +1175,27 @@ public class BluetoothService extends IBluetooth.Stub {
return cancelPairingUserInputNative(address, data.intValue());
}
+ public void updateDeviceServiceChannelCache(String address) {
+ ParcelUuid[] deviceUuids = getRemoteUuids(address);
+ // We are storing the rfcomm channel numbers only for the uuids
+ // we are interested in.
+ int channel;
+ ParcelUuid[] interestedUuids = {BluetoothUuid.Handsfree,
+ BluetoothUuid.HSP,
+ BluetoothUuid.ObexObjectPush};
+
+ Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
+ for (ParcelUuid uuid: interestedUuids) {
+ if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
+ channel =
+ getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
+ 0x0004);
+ value.put(uuid, channel);
+ }
+ }
+ mDeviceServiceChannelCache.put(address, value);
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -1121,6 +1234,18 @@ public class BluetoothService extends IBluetooth.Stub {
Settings.System.AIRPLANE_MODE_ON, 0) == 1;
}
+ /* Broadcast the Uuid intent */
+ /*package*/ synchronized void sendUuidIntent(String address) {
+ ParcelUuid[] uuid = getUuidFromCache(address);
+ Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
+ intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+ intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
+ mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+
+ if (mUuidIntentTracker.contains(address))
+ mUuidIntentTracker.remove(address);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
@@ -1284,4 +1409,7 @@ public class BluetoothService extends IBluetooth.Stub {
private native boolean setPairingConfirmationNative(String address, boolean confirm,
int nativeData);
private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value);
+ private native boolean createDeviceNative(String address);
+ private native boolean discoverServicesNative(String objectPath, String pattern);
+
}
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 367b26c..baaa3ce 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -32,6 +32,18 @@ public final class Formatter {
* @return formated string with the number
*/
public static String formatFileSize(Context context, long number) {
+ return formatFileSize(context, number, false);
+ }
+
+ /**
+ * Like {@link #formatFileSize}, but trying to generate shorter numbers
+ * (showing fewer digits of precisin).
+ */
+ public static String formatShortFileSize(Context context, long number) {
+ return formatFileSize(context, number, true);
+ }
+
+ private static String formatFileSize(Context context, long number, boolean shorter) {
if (context == null) {
return "";
}
@@ -58,13 +70,24 @@ public final class Formatter {
suffix = com.android.internal.R.string.petabyteShort;
result = result / 1024;
}
- if (result < 100) {
- String value = String.format("%.2f", result);
- return context.getResources().
- getString(com.android.internal.R.string.fileSizeSuffix,
- value, context.getString(suffix));
+ String value;
+ if (result < 1) {
+ value = String.format("%.2f", result);
+ } else if (result < 10) {
+ if (shorter) {
+ value = String.format("%.1f", result);
+ } else {
+ value = String.format("%.2f", result);
+ }
+ } else if (result < 100) {
+ if (shorter) {
+ value = String.format("%.0f", result);
+ } else {
+ value = String.format("%.2f", result);
+ }
+ } else {
+ value = String.format("%.0f", result);
}
- String value = String.format("%.0f", result);
return context.getResources().
getString(com.android.internal.R.string.fileSizeSuffix,
value, context.getString(suffix));
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f67c4aa..396e380 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -488,7 +488,10 @@ public interface WindowManager extends ViewManager {
* is locked. This will let application windows take precedence over
* key guard or any other lock screens. Can be used with
* {@link #FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
- * directly before showing the key guard window
+ * directly before showing the key guard window. Can be used with
+ * {@link #FLAG_DISMISS_KEYGUARD} to automatically fully dismisss
+ * non-secure keyguards. This flag only applies to the top-most
+ * full-screen window.
*/
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
@@ -506,6 +509,19 @@ public interface WindowManager extends ViewManager {
* up the device) to turn the screen on. */
public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
+ /** Window flag: when set the window will cause the keyguard to
+ * be dismissed, only if it is not a secure lock keyguard. Because such
+ * a keyguard is not needed for security, it will never re-appear if
+ * the user navigates to another window (in contrast to
+ * {@link #FLAG_SHOW_WHEN_LOCKED}, which will only temporarily
+ * hide both secure and non-secure keyguards but ensure they reappear
+ * when the user moves to another UI that doesn't hide them).
+ * If the keyguard is currently active and is secure (requires an
+ * unlock pattern) than the user will still need to confirm it before
+ * seeing this window, unless {@link #FLAG_SHOW_WHEN_LOCKED} has
+ * also been set. */
+ public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
+
/** Window flag: special flag to limit the size of the window to be
* original size ([320x480] x density). Used to create window for applications
* running under compatibility mode.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 45ff27e..1923743 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -314,7 +314,9 @@ public interface WindowManagerPolicy {
public boolean showLw(boolean doAnimation);
}
- /** No transition happening. */
+ /** Not set up for a transition. */
+ public final int TRANSIT_UNSET = 0;
+ /** No animation for transition. */
public final int TRANSIT_NONE = 0;
/** Window has been added to the screen. */
public final int TRANSIT_ENTER = 1;
@@ -600,11 +602,18 @@ public interface WindowManagerPolicy {
* returned, all windows given to layoutWindow() <em>must</em> have had a
* frame assigned.
*
- * @return Return true if layout state may have changed (so that another
- * layout will be performed).
+ * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT}
+ * and {@link #FINISH_LAYOUT_REDO_CONFIG}.
*/
- public boolean finishLayoutLw();
+ public int finishLayoutLw();
+ /** Layout state may have changed (so another layout will be performed) */
+ static final int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
+ /** Configuration state may have changed */
+ static final int FINISH_LAYOUT_REDO_CONFIG = 0x0002;
+ /** Wallpaper may need to move */
+ static final int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
+
/**
* Called when animation of the windows is about to start.
*
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index dbddb2e..e233a02 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -605,8 +605,8 @@ class BrowserFrame extends Handler {
}
// Called by JNI when an apple-touch-icon attribute was found.
- private void didReceiveTouchIconUrl(String url) {
- mCallbackProxy.onReceivedTouchIconUrl(url);
+ private void didReceiveTouchIconUrl(String url, boolean precomposed) {
+ mCallbackProxy.onReceivedTouchIconUrl(url, precomposed);
}
/**
@@ -707,6 +707,10 @@ class BrowserFrame extends Handler {
return value.string.toString();
}
+ private float density() {
+ return mContext.getResources().getDisplayMetrics().density;
+ }
+
//==========================================================================
// native functions
//==========================================================================
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index b051675..1ec769b 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -249,7 +249,7 @@ class CallbackProxy extends Handler {
case RECEIVED_TOUCH_ICON_URL:
if (mWebChromeClient != null) {
mWebChromeClient.onReceivedTouchIconUrl(mWebView,
- (String) msg.obj);
+ (String) msg.obj, msg.arg1 == 1);
}
break;
@@ -1065,19 +1065,22 @@ class CallbackProxy extends Handler {
sendMessage(obtainMessage(RECEIVED_ICON, icon));
}
- /* package */ void onReceivedTouchIconUrl(String url) {
+ /* package */ void onReceivedTouchIconUrl(String url, boolean precomposed) {
// We should have a current item but we do not want to crash so check
// for null.
WebHistoryItem i = mBackForwardList.getCurrentItem();
if (i != null) {
- i.setTouchIconUrl(url);
+ if (precomposed || i.getTouchIconUrl() != null) {
+ i.setTouchIconUrl(url);
+ }
}
// Do an unsynchronized quick check to avoid posting if no callback has
// been set.
if (mWebChromeClient == null) {
return;
}
- sendMessage(obtainMessage(RECEIVED_TOUCH_ICON_URL, url));
+ sendMessage(obtainMessage(RECEIVED_TOUCH_ICON_URL,
+ precomposed ? 1 : 0, 0, url));
}
public void onReceivedTitle(String title) {
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index e985ccc..c0cac01 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -19,10 +19,9 @@ package android.webkit;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
@@ -47,15 +46,13 @@ public final class GeolocationPermissions {
private static GeolocationPermissions sInstance;
private Handler mHandler;
+ private Handler mUIHandler;
// Members used to transfer the origins and permissions between threads.
private Set<String> mOrigins;
private boolean mAllowed;
private Set<String> mOriginsToClear;
private Set<String> mOriginsToAllow;
- private static Lock mLock = new ReentrantLock();
- private static boolean mUpdated;
- private static Condition mUpdatedCondition = mLock.newCondition();
// Message ids
static final int GET_ORIGINS = 0;
@@ -64,6 +61,15 @@ public final class GeolocationPermissions {
static final int ALLOW = 3;
static final int CLEAR_ALL = 4;
+ // Message ids on the UI thread
+ static final int RETURN_ORIGINS = 0;
+ static final int RETURN_ALLOWED = 1;
+
+ private static final String ORIGINS = "origins";
+ private static final String ORIGIN = "origin";
+ private static final String CALLBACK = "callback";
+ private static final String ALLOWED = "allowed";
+
/**
* Gets the singleton instance of the class.
*/
@@ -75,22 +81,62 @@ public final class GeolocationPermissions {
}
/**
+ * Creates the UI message handler. Must be called on the UI thread.
+ */
+ public void createUIHandler() {
+ if (mUIHandler == null) {
+ mUIHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ // Runs on the UI thread.
+ switch (msg.what) {
+ case RETURN_ORIGINS: {
+ Map values = (Map) msg.obj;
+ Set origins = (Set) values.get(ORIGINS);
+ ValueCallback<Set> callback = (ValueCallback<Set>) values.get(CALLBACK);
+ callback.onReceiveValue(origins);
+ } break;
+ case RETURN_ALLOWED: {
+ Map values = (Map) msg.obj;
+ Boolean allowed = (Boolean) values.get(ALLOWED);
+ ValueCallback<Boolean> callback = (ValueCallback<Boolean>) values.get(CALLBACK);
+ callback.onReceiveValue(allowed);
+ } break;
+ }
+ }
+ };
+ }
+ }
+
+ /**
* Creates the message handler. Must be called on the WebKit thread.
*/
public void createHandler() {
- mLock.lock();
if (mHandler == null) {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Runs on the WebKit thread.
switch (msg.what) {
- case GET_ORIGINS:
+ case GET_ORIGINS: {
getOriginsImpl();
- break;
- case GET_ALLOWED:
- getAllowedImpl((String) msg.obj);
- break;
+ ValueCallback callback = (ValueCallback) msg.obj;
+ Set origins = new HashSet(mOrigins);
+ Map values = new HashMap<String, Object>();
+ values.put(CALLBACK, callback);
+ values.put(ORIGINS, origins);
+ postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
+ } break;
+ case GET_ALLOWED: {
+ Map values = (Map) msg.obj;
+ String origin = (String) values.get(ORIGIN);
+ ValueCallback callback = (ValueCallback) values.get(CALLBACK);
+ getAllowedImpl(origin);
+ Map retValues = new HashMap<String, Object>();
+ retValues.put(CALLBACK, callback);
+ retValues.put(ALLOWED, new Boolean(mAllowed));
+ postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues));
+ } break;
case CLEAR:
nativeClear((String) msg.obj);
break;
@@ -115,7 +161,6 @@ public final class GeolocationPermissions {
}
}
}
- mLock.unlock();
}
/**
@@ -127,29 +172,31 @@ public final class GeolocationPermissions {
}
/**
+ * Utility function to send a message to the handler on the UI thread
+ */
+ private void postUIMessage(Message msg) {
+ if (mUIHandler != null) {
+ mUIHandler.sendMessage(msg);
+ }
+ }
+
+ /**
* Gets the set of origins for which Geolocation permissions are stored.
* Note that we represent the origins as strings. These are created using
* WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
* (Database, Geolocation etc) do so, it's safe to match up origins for the
* purposes of displaying UI.
*/
- public Set getOrigins() {
- // Called on the UI thread.
- Set origins = null;
- mLock.lock();
- try {
- mUpdated = false;
- postMessage(Message.obtain(null, GET_ORIGINS));
- while (!mUpdated) {
- mUpdatedCondition.await();
+ public void getOrigins(ValueCallback<Set> callback) {
+ if (callback != null) {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ getOriginsImpl();
+ Set origins = new HashSet(mOrigins);
+ callback.onReceiveValue(origins);
+ } else {
+ postMessage(Message.obtain(null, GET_ORIGINS, callback));
}
- origins = mOrigins;
- } catch (InterruptedException e) {
- Log.e(TAG, "Exception while waiting for update", e);
- } finally {
- mLock.unlock();
}
- return origins;
}
/**
@@ -157,33 +204,29 @@ public final class GeolocationPermissions {
*/
private void getOriginsImpl() {
// Called on the WebKit thread.
- mLock.lock();
mOrigins = nativeGetOrigins();
- mUpdated = true;
- mUpdatedCondition.signal();
- mLock.unlock();
}
/**
* Gets the permission state for the specified origin.
*/
- public boolean getAllowed(String origin) {
- // Called on the UI thread.
- boolean allowed = false;
- mLock.lock();
- try {
- mUpdated = false;
- postMessage(Message.obtain(null, GET_ALLOWED, origin));
- while (!mUpdated) {
- mUpdatedCondition.await();
- }
- allowed = mAllowed;
- } catch (InterruptedException e) {
- Log.e(TAG, "Exception while waiting for update", e);
- } finally {
- mLock.unlock();
+ public void getAllowed(String origin, ValueCallback<Boolean> callback) {
+ if (callback == null) {
+ return;
+ }
+ if (origin == null) {
+ callback.onReceiveValue(null);
+ return;
+ }
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ getAllowedImpl(origin);
+ callback.onReceiveValue(new Boolean(mAllowed));
+ } else {
+ Map values = new HashMap<String, Object>();
+ values.put(ORIGIN, origin);
+ values.put(CALLBACK, callback);
+ postMessage(Message.obtain(null, GET_ALLOWED, values));
}
- return allowed;
}
/**
@@ -191,11 +234,7 @@ public final class GeolocationPermissions {
*/
private void getAllowedImpl(String origin) {
// Called on the WebKit thread.
- mLock.lock();
mAllowed = nativeGetAllowed(origin);
- mUpdated = true;
- mUpdatedCondition.signal();
- mLock.unlock();
}
/**
@@ -205,7 +244,6 @@ public final class GeolocationPermissions {
*/
public void clear(String origin) {
// Called on the UI thread.
- mLock.lock();
if (mHandler == null) {
if (mOriginsToClear == null) {
mOriginsToClear = new HashSet<String>();
@@ -217,7 +255,6 @@ public final class GeolocationPermissions {
} else {
postMessage(Message.obtain(null, CLEAR, origin));
}
- mLock.unlock();
}
/**
@@ -227,7 +264,6 @@ public final class GeolocationPermissions {
*/
public void allow(String origin) {
// Called on the UI thread.
- mLock.lock();
if (mHandler == null) {
if (mOriginsToAllow == null) {
mOriginsToAllow = new HashSet<String>();
@@ -239,7 +275,6 @@ public final class GeolocationPermissions {
} else {
postMessage(Message.obtain(null, ALLOW, origin));
}
- mLock.unlock();
}
/**
diff --git a/core/java/android/webkit/GoogleLocationSettingManager.java b/core/java/android/webkit/GoogleLocationSettingManager.java
index fe7fce6..1b6e77c 100644
--- a/core/java/android/webkit/GoogleLocationSettingManager.java
+++ b/core/java/android/webkit/GoogleLocationSettingManager.java
@@ -35,8 +35,6 @@ import java.util.HashSet;
* @hide pending API council review
*/
class GoogleLocationSettingManager {
- // The application context.
- private Context mContext;
// The observer used to listen to the system setting.
private GoogleLocationSettingObserver mSettingObserver;
@@ -48,6 +46,8 @@ class GoogleLocationSettingManager {
// by the browser.
private final static String LAST_READ_USE_LOCATION_FOR_SERVICES =
"lastReadUseLocationForServices";
+ // The Browser package name.
+ private static final String BROWSER_PACKAGE_NAME = "com.android.browser";
// The Google origins we consider.
private static HashSet<String> sGoogleOrigins;
static {
@@ -57,38 +57,72 @@ class GoogleLocationSettingManager {
sGoogleOrigins.add("http://www.google.co.uk");
}
- GoogleLocationSettingManager(Context context) {
- mContext = context;
+ private static GoogleLocationSettingManager sGoogleLocationSettingManager = null;
+ private static int sRefCount = 0;
+
+ static GoogleLocationSettingManager getInstance() {
+ if (sGoogleLocationSettingManager == null) {
+ sGoogleLocationSettingManager = new GoogleLocationSettingManager();
+ }
+ return sGoogleLocationSettingManager;
}
+ private GoogleLocationSettingManager() {}
+
/**
* Starts the manager. Checks whether the setting has changed and
* installs an observer to listen for future changes.
*/
- public void start() {
- maybeApplySetting();
-
+ public void start(Context context) {
+ // Are we running in the browser?
+ if (context == null || !BROWSER_PACKAGE_NAME.equals(context.getPackageName())) {
+ return;
+ }
+ // Increase the refCount
+ sRefCount++;
+ // Are we already registered?
+ if (mSettingObserver != null) {
+ return;
+ }
+ // Read and apply the settings if needed.
+ maybeApplySetting(context);
+ // Register to receive notifications when the system settings change.
mSettingObserver = new GoogleLocationSettingObserver();
- mSettingObserver.observe();
+ mSettingObserver.observe(context);
}
/**
+ * Stops the manager.
+ */
+ public void stop() {
+ // Are we already registered?
+ if (mSettingObserver == null) {
+ return;
+ }
+ if (--sRefCount == 0) {
+ mSettingObserver.doNotObserve();
+ mSettingObserver = null;
+ }
+ }
+ /**
* Checks to see if the system setting has changed and if so,
* updates the Geolocation permissions accordingly.
+ * @param the Application context
*/
- private void maybeApplySetting() {
- int setting = getSystemSetting();
- if (settingChanged(setting)) {
+ private void maybeApplySetting(Context context) {
+ int setting = getSystemSetting(context);
+ if (settingChanged(setting, context)) {
applySetting(setting);
}
}
/**
* Gets the current system setting for 'Use location for Google services'.
+ * @param the Application context
* @return The system setting.
*/
- private int getSystemSetting() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
+ private int getSystemSetting(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.USE_LOCATION_FOR_SERVICES,
sSystemSettingFalse);
}
@@ -97,12 +131,13 @@ class GoogleLocationSettingManager {
* Determines whether the supplied setting has changed from the last
* value read by the browser.
* @param setting The setting.
+ * @param the Application context
* @return Whether the setting has changed from the last value read
* by the browser.
*/
- private boolean settingChanged(int setting) {
+ private boolean settingChanged(int setting, Context context) {
SharedPreferences preferences =
- PreferenceManager.getDefaultSharedPreferences(mContext);
+ PreferenceManager.getDefaultSharedPreferences(context);
// Default to false. If the system setting is false the first time it is ever read by the
// browser, there's nothing to do.
int lastReadSetting = sSystemSettingFalse;
@@ -137,20 +172,35 @@ class GoogleLocationSettingManager {
* This class implements an observer to listen for changes to the
* system setting.
*/
- class GoogleLocationSettingObserver extends ContentObserver {
+ private class GoogleLocationSettingObserver extends ContentObserver {
+ private Context mContext;
+
GoogleLocationSettingObserver() {
super(new Handler());
}
- void observe() {
- ContentResolver resolver = mContext.getContentResolver();
+ void observe(Context context) {
+ if (mContext != null) {
+ return;
+ }
+ ContentResolver resolver = context.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.USE_LOCATION_FOR_SERVICES), false, this);
+ mContext = context;
+ }
+
+ void doNotObserve() {
+ if (mContext == null) {
+ return;
+ }
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ mContext = null;
}
@Override
public void onChange(boolean selfChange) {
- maybeApplySetting();
+ maybeApplySetting(mContext);
}
}
}
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
index 32eea5f..766bd75 100644
--- a/core/java/android/webkit/PluginManager.java
+++ b/core/java/android/webkit/PluginManager.java
@@ -63,8 +63,11 @@ public class PluginManager {
private final Context mContext;
+ private ArrayList<PackageInfo> mPackageInfoCache;
+
private PluginManager(Context context) {
mContext = context;
+ mPackageInfoCache = new ArrayList<PackageInfo>();
}
public static synchronized PluginManager getInstance(Context context) {
@@ -92,65 +95,94 @@ public class PluginManager {
}
String[] getPluginDirectories() {
+
ArrayList<String> directories = new ArrayList<String>();
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
PLUGIN_ACTION), PackageManager.GET_SERVICES);
- for (ResolveInfo info : plugins) {
- ServiceInfo serviceInfo = info.serviceInfo;
- if (serviceInfo == null) {
- Log.w(LOGTAG, "Ignore bad plugin");
- continue;
- }
- PackageInfo pkgInfo;
- try {
- pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
- PackageManager.GET_PERMISSIONS
- | PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName);
- continue;
- }
- if (pkgInfo == null) {
- continue;
- }
- String directory = pkgInfo.applicationInfo.dataDir + "/lib";
- if (directories.contains(directory)) {
- continue;
- }
- String permissions[] = pkgInfo.requestedPermissions;
- if (permissions == null) {
- continue;
- }
- boolean permissionOk = false;
- for (String permit : permissions) {
- if (PLUGIN_PERMISSION.equals(permit)) {
- permissionOk = true;
+
+ synchronized(mPackageInfoCache) {
+
+ // clear the list of existing packageInfo objects
+ mPackageInfoCache.clear();
+
+ for (ResolveInfo info : plugins) {
+ ServiceInfo serviceInfo = info.serviceInfo;
+ if (serviceInfo == null) {
+ Log.w(LOGTAG, "Ignore bad plugin");
+ continue;
+ }
+ PackageInfo pkgInfo;
+ try {
+ pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
+ PackageManager.GET_PERMISSIONS
+ | PackageManager.GET_SIGNATURES);
+ } catch (NameNotFoundException e) {
+ Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName);
+ continue;
+ }
+ if (pkgInfo == null) {
+ continue;
+ }
+ String directory = pkgInfo.applicationInfo.dataDir + "/lib";
+ if (directories.contains(directory)) {
+ continue;
+ }
+ String permissions[] = pkgInfo.requestedPermissions;
+ if (permissions == null) {
+ continue;
+ }
+ boolean permissionOk = false;
+ for (String permit : permissions) {
+ if (PLUGIN_PERMISSION.equals(permit)) {
+ permissionOk = true;
+ break;
+ }
+ }
+ if (!permissionOk) {
+ continue;
+ }
+ Signature signatures[] = pkgInfo.signatures;
+ if (signatures == null) {
+ continue;
+ }
+ boolean signatureMatch = false;
+ for (Signature signature : signatures) {
+ // TODO: check signature against Google provided one
+ signatureMatch = true;
break;
}
+ if (!signatureMatch) {
+ continue;
+ }
+ mPackageInfoCache.add(pkgInfo);
+ directories.add(directory);
}
- if (!permissionOk) {
- continue;
- }
- Signature signatures[] = pkgInfo.signatures;
- if (signatures == null) {
- continue;
- }
- boolean signatureMatch = false;
- for (Signature signature : signatures) {
- // TODO: check signature against Google provided one
- signatureMatch = true;
- break;
- }
- if (!signatureMatch) {
- continue;
- }
- directories.add(directory);
}
return directories.toArray(new String[directories.size()]);
}
+ String getPluginsAPKName(String pluginLib) {
+
+ // basic error checking on input params
+ if (pluginLib == null || pluginLib.length() == 0) {
+ return null;
+ }
+
+ // must be synchronized to ensure the consistency of the cache
+ synchronized(mPackageInfoCache) {
+ for (PackageInfo pkgInfo : mPackageInfoCache) {
+ if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) {
+ return pkgInfo.packageName;
+ }
+ }
+ }
+
+ // if no apk was found then return null
+ return null;
+ }
+
String getPluginSharedDataDirectory() {
return mContext.getDir("plugins", 0).getPath();
}
diff --git a/core/java/android/webkit/ValueCallback.java b/core/java/android/webkit/ValueCallback.java
new file mode 100644
index 0000000..d8c5cdc
--- /dev/null
+++ b/core/java/android/webkit/ValueCallback.java
@@ -0,0 +1,29 @@
+/*
+ * 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 android.webkit;
+
+/**
+ * A callback interface used to returns values asynchronously
+ *
+ * @hide pending council approval
+ */
+public interface ValueCallback<T> {
+ /**
+ * Invoked when we have the result
+ */
+ public void onReceiveValue(T value);
+};
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 0e08514..1ae1d85 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -48,9 +48,11 @@ public class WebChromeClient {
* Notify the host application of the url for an apple-touch-icon.
* @param view The WebView that initiated the callback.
* @param url The icon url.
+ * @param precomposed True if the url is for a precomposed touch icon.
* @hide pending council approval
*/
- public void onReceivedTouchIconUrl(WebView view, String url) {}
+ public void onReceivedTouchIconUrl(WebView view, String url,
+ boolean precomposed) {}
/**
* A callback interface used by the host application to notify
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 196bbd7..0cfcb95 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
@@ -189,9 +190,11 @@ public class WebSettings {
private boolean mAllowFileAccess = true;
private boolean mLoadWithOverviewMode = false;
- // Manages interaction of the system setting 'Location & security - Share
- // with Google' and the browser.
- static GoogleLocationSettingManager sGoogleLocationSettingManager;
+ // private WebSettings, not accessible by the host activity
+ static private int mDoubleTapToastCount = 3;
+
+ private static final String PREF_FILE = "WebViewSettings";
+ private static final String DOUBLE_TAP_TOAST_COUNT = "double_tap_toast_count";
// Class to handle messages before WebCore is ready.
private class EventHandler {
@@ -199,6 +202,8 @@ public class WebSettings {
static final int SYNC = 0;
// Message id for setting priority
static final int PRIORITY = 1;
+ // Message id for writing double-tap toast count
+ static final int SET_DOUBLE_TAP_TOAST_COUNT = 2;
// Actual WebCore thread handler
private Handler mHandler;
@@ -224,6 +229,16 @@ public class WebSettings {
setRenderPriority();
break;
}
+
+ case SET_DOUBLE_TAP_TOAST_COUNT: {
+ SharedPreferences.Editor editor = mContext
+ .getSharedPreferences(PREF_FILE,
+ Context.MODE_PRIVATE).edit();
+ editor.putInt(DOUBLE_TAP_TOAST_COUNT,
+ mDoubleTapToastCount);
+ editor.commit();
+ break;
+ }
}
}
};
@@ -1311,6 +1326,19 @@ public class WebSettings {
}
}
+ int getDoubleTapToastCount() {
+ return mDoubleTapToastCount;
+ }
+
+ void setDoubleTapToastCount(int count) {
+ if (mDoubleTapToastCount != count) {
+ mDoubleTapToastCount = count;
+ // write the settings in the non-UI thread
+ mEventHandler.sendMessage(Message.obtain(null,
+ EventHandler.SET_DOUBLE_TAP_TOAST_COUNT));
+ }
+ }
+
/**
* Transfer messages from the queue to the new WebCoreThread. Called from
* WebCore thread.
@@ -1321,13 +1349,28 @@ public class WebSettings {
if (DebugFlags.WEB_SETTINGS) {
junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
}
- sGoogleLocationSettingManager = new GoogleLocationSettingManager(mContext);
- sGoogleLocationSettingManager.start();
+
+ GoogleLocationSettingManager.getInstance().start(mContext);
+
+ SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE,
+ Context.MODE_PRIVATE);
+ if (mDoubleTapToastCount > 0) {
+ mDoubleTapToastCount = sp.getInt(DOUBLE_TAP_TOAST_COUNT,
+ mDoubleTapToastCount);
+ }
nativeSync(frame.mNativeFrame);
mSyncPending = false;
mEventHandler.createHandler();
}
+ /**
+ * Let the Settings object know that our owner is being destroyed.
+ */
+ /*package*/
+ synchronized void onDestroyed() {
+ GoogleLocationSettingManager.getInstance().stop();
+ }
+
private int pin(int size) {
// FIXME: 72 is just an arbitrary max text size value.
if (size < 1) {
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index ae560fb..0022248 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -20,9 +20,8 @@ import android.os.Handler;
import android.os.Message;
import android.util.Log;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.Collection;
+import java.util.Map;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -51,28 +50,41 @@ public final class WebStorage {
// Global instance of a WebStorage
private static WebStorage sWebStorage;
- // We keep the origins, quotas and usages as member values
- // that we protect via a lock and update in syncValues().
- // This is needed to transfer this data across threads.
- private static Lock mLock = new ReentrantLock();
- private static Condition mUpdateCondition = mLock.newCondition();
- private static boolean mUpdateAvailable;
-
// Message ids
static final int UPDATE = 0;
static final int SET_QUOTA_ORIGIN = 1;
static final int DELETE_ORIGIN = 2;
static final int DELETE_ALL = 3;
+ static final int GET_ORIGINS = 4;
+ static final int GET_USAGE_ORIGIN = 5;
+ static final int GET_QUOTA_ORIGIN = 6;
+
+ // Message ids on the UI thread
+ static final int RETURN_ORIGINS = 0;
+ static final int RETURN_USAGE_ORIGIN = 1;
+ static final int RETURN_QUOTA_ORIGIN = 2;
+
+ private static final String ORIGINS = "origins";
+ private static final String ORIGIN = "origin";
+ private static final String CALLBACK = "callback";
+ private static final String USAGE = "usage";
+ private static final String QUOTA = "quota";
- private Set <String> mOrigins;
- private HashMap <String, Long> mQuotas = new HashMap<String, Long>();
- private HashMap <String, Long> mUsages = new HashMap<String, Long>();
+ private Map <String, Origin> mOrigins;
private Handler mHandler = null;
+ private Handler mUIHandler = null;
- private static class Origin {
+ static class Origin {
String mOrigin = null;
long mQuota = 0;
+ long mUsage = 0;
+
+ public Origin(String origin, long quota, long usage) {
+ mOrigin = origin;
+ mQuota = quota;
+ mUsage = usage;
+ }
public Origin(String origin, long quota) {
mOrigin = origin;
@@ -90,11 +102,49 @@ public final class WebStorage {
public long getQuota() {
return mQuota;
}
+
+ public long getUsage() {
+ return mUsage;
+ }
+ }
+
+ /**
+ * @hide
+ * Message handler, UI side
+ */
+ public void createUIHandler() {
+ if (mUIHandler == null) {
+ mUIHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case RETURN_ORIGINS: {
+ Map values = (Map) msg.obj;
+ Map origins = (Map) values.get(ORIGINS);
+ ValueCallback<Map> callback = (ValueCallback<Map>) values.get(CALLBACK);
+ callback.onReceiveValue(origins);
+ } break;
+
+ case RETURN_USAGE_ORIGIN: {
+ Map values = (Map) msg.obj;
+ ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
+ callback.onReceiveValue((Long)values.get(USAGE));
+ } break;
+
+ case RETURN_QUOTA_ORIGIN: {
+ Map values = (Map) msg.obj;
+ ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
+ callback.onReceiveValue((Long)values.get(QUOTA));
+ } break;
+ }
+ }
+ };
+ }
}
/**
* @hide
- * Message handler
+ * Message handler, webcore side
*/
public void createHandler() {
if (mHandler == null) {
@@ -117,6 +167,46 @@ public final class WebStorage {
nativeDeleteAllData();
break;
+ case GET_ORIGINS: {
+ syncValues();
+ ValueCallback callback = (ValueCallback) msg.obj;
+ Map origins = new HashMap(mOrigins);
+ Map values = new HashMap<String, Object>();
+ values.put(CALLBACK, callback);
+ values.put(ORIGINS, origins);
+ postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
+ } break;
+
+ case GET_USAGE_ORIGIN: {
+ syncValues();
+ Map values = (Map) msg.obj;
+ String origin = (String) values.get(ORIGIN);
+ ValueCallback callback = (ValueCallback) values.get(CALLBACK);
+ Origin website = mOrigins.get(origin);
+ Map retValues = new HashMap<String, Object>();
+ retValues.put(CALLBACK, callback);
+ if (website != null) {
+ long usage = website.getUsage();
+ retValues.put(USAGE, new Long(usage));
+ }
+ postUIMessage(Message.obtain(null, RETURN_USAGE_ORIGIN, retValues));
+ } break;
+
+ case GET_QUOTA_ORIGIN: {
+ syncValues();
+ Map values = (Map) msg.obj;
+ String origin = (String) values.get(ORIGIN);
+ ValueCallback callback = (ValueCallback) values.get(CALLBACK);
+ Origin website = mOrigins.get(origin);
+ Map retValues = new HashMap<String, Object>();
+ retValues.put(CALLBACK, callback);
+ if (website != null) {
+ long quota = website.getQuota();
+ retValues.put(QUOTA, new Long(quota));
+ }
+ postUIMessage(Message.obtain(null, RETURN_QUOTA_ORIGIN, retValues));
+ } break;
+
case UPDATE:
syncValues();
break;
@@ -126,82 +216,91 @@ public final class WebStorage {
}
}
+ /*
+ * When calling getOrigins(), getUsageForOrigin() and getQuotaForOrigin(),
+ * we need to get the values from webcore, but we cannot block while doing so
+ * as we used to do, as this could result in a full deadlock (other webcore
+ * messages received while we are still blocked here, see http://b/2127737).
+ *
+ * We have to do everything asynchronously, by providing a callback function.
+ * We post a message on the webcore thread (mHandler) that will get the result
+ * from webcore, and we post it back on the UI thread (using mUIHandler).
+ * We can then use the callback function to return the value.
+ */
+
/**
* @hide
* Returns a list of origins having a database
*/
- public Set getOrigins() {
- Set ret = null;
- mLock.lock();
- try {
- mUpdateAvailable = false;
- update();
- while (!mUpdateAvailable) {
- mUpdateCondition.await();
+ public void getOrigins(ValueCallback<Map> callback) {
+ if (callback != null) {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ syncValues();
+ callback.onReceiveValue(mOrigins);
+ } else {
+ postMessage(Message.obtain(null, GET_ORIGINS, callback));
}
- ret = mOrigins;
- } catch (InterruptedException e) {
- Log.e(TAG, "Exception while waiting on the updated origins", e);
- } finally {
- mLock.unlock();
}
- return ret;
+ }
+
+ /**
+ * Returns a list of origins having a database
+ * should only be called from WebViewCore.
+ */
+ Collection<Origin> getOriginsSync() {
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ update();
+ return mOrigins.values();
+ }
+ return null;
}
/**
* @hide
* Returns the use for a given origin
*/
- public long getUsageForOrigin(String origin) {
- long ret = 0;
+ public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
+ if (callback == null) {
+ return;
+ }
if (origin == null) {
- return ret;
+ callback.onReceiveValue(null);
+ return;
}
- mLock.lock();
- try {
- mUpdateAvailable = false;
- update();
- while (!mUpdateAvailable) {
- mUpdateCondition.await();
- }
- Long usage = mUsages.get(origin);
- if (usage != null) {
- ret = usage.longValue();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Exception while waiting on the updated origins", e);
- } finally {
- mLock.unlock();
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ syncValues();
+ Origin website = mOrigins.get(origin);
+ callback.onReceiveValue(new Long(website.getUsage()));
+ } else {
+ HashMap values = new HashMap<String, Object>();
+ values.put(ORIGIN, origin);
+ values.put(CALLBACK, callback);
+ postMessage(Message.obtain(null, GET_USAGE_ORIGIN, values));
}
- return ret;
}
/**
* @hide
* Returns the quota for a given origin
*/
- public long getQuotaForOrigin(String origin) {
- long ret = 0;
+ public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
+ if (callback == null) {
+ return;
+ }
if (origin == null) {
- return ret;
+ callback.onReceiveValue(null);
+ return;
}
- mLock.lock();
- try {
- mUpdateAvailable = false;
- update();
- while (!mUpdateAvailable) {
- mUpdateCondition.await();
- }
- Long quota = mQuotas.get(origin);
- if (quota != null) {
- ret = quota.longValue();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Exception while waiting on the updated origins", e);
- } finally {
- mLock.unlock();
+ if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+ syncValues();
+ Origin website = mOrigins.get(origin);
+ callback.onReceiveValue(new Long(website.getUsage()));
+ } else {
+ HashMap values = new HashMap<String, Object>();
+ values.put(ORIGIN, origin);
+ values.put(CALLBACK, callback);
+ postMessage(Message.obtain(null, GET_QUOTA_ORIGIN, values));
}
- return ret;
}
/**
@@ -256,6 +355,15 @@ public final class WebStorage {
}
/**
+ * Utility function to send a message to the handler on the UI thread
+ */
+ private void postUIMessage(Message msg) {
+ if (mUIHandler != null) {
+ mUIHandler.sendMessage(msg);
+ }
+ }
+
+ /**
* @hide
* Get the global instance of WebStorage.
* @return A single instance of WebStorage.
@@ -284,21 +392,14 @@ public final class WebStorage {
* set the local values with the current ones
*/
private void syncValues() {
- mLock.lock();
- Set tmp = nativeGetOrigins();
- mOrigins = new HashSet<String>();
- mQuotas.clear();
- mUsages.clear();
- Iterator<String> iter = tmp.iterator();
- while (iter.hasNext()) {
- String origin = iter.next();
- mOrigins.add(origin);
- mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
- mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
+ Set<String> tmp = nativeGetOrigins();
+ mOrigins = new HashMap<String, Origin>();
+ for (String origin : tmp) {
+ Origin website = new Origin(origin,
+ nativeGetUsageForOrigin(origin),
+ nativeGetQuotaForOrigin(origin));
+ mOrigins.put(origin, website);
}
- mUpdateAvailable = true;
- mUpdateCondition.signal();
- mLock.unlock();
}
// Native functions
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 39a2470..1a65ce8 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -448,8 +448,13 @@ import java.util.ArrayList;
int initialScrollX = Touch.getInitialScrollX(this, buffer);
int initialScrollY = Touch.getInitialScrollY(this, buffer);
super.onTouchEvent(event);
- if (Math.abs(mScrollX - initialScrollX) > slop
- || Math.abs(mScrollY - initialScrollY) > slop) {
+ int dx = Math.abs(mScrollX - initialScrollX);
+ int dy = Math.abs(mScrollY - initialScrollY);
+ // Use a smaller slop when checking to see if we've moved far enough
+ // to scroll the text, because experimentally, slop has shown to be
+ // to big for the case of a small textfield.
+ int smallerSlop = slop/2;
+ if (dx > smallerSlop || dy > smallerSlop) {
if (mWebView != null) {
mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7e8ba8f..51c5e1f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -420,6 +420,7 @@ public class WebView extends AbsoluteLayout
private static final int STD_SPEED = 480; // pixels per second
// time for the longest scroll animation
private static final int MAX_DURATION = 750; // milliseconds
+ private static final int SLIDE_TITLE_DURATION = 500; // milliseconds
private Scroller mScroller;
private boolean mWrapContent;
@@ -1781,12 +1782,22 @@ public class WebView extends AbsoluteLayout
}
/**
+ * Given a distance in view space, convert it to content space. Note: this
+ * does not reflect translation, just scaling, so this should not be called
+ * with coordinates, but should be called for dimensions like width or
+ * height.
+ */
+ private int viewToContentDimension(int d) {
+ return Math.round(d * mInvActualScale);
+ }
+
+ /**
* Given an x coordinate in view space, convert it to content space. Also
* may be used for absolute heights (such as for the WebTextView's
* textSize, which is unaffected by the height of the title bar).
*/
/*package*/ int viewToContentX(int x) {
- return Math.round(x * mInvActualScale);
+ return viewToContentDimension(x);
}
/**
@@ -1795,7 +1806,7 @@ public class WebView extends AbsoluteLayout
* embedded into the WebView.
*/
/*package*/ int viewToContentY(int y) {
- return viewToContentX(y - getTitleHeight());
+ return viewToContentDimension(y - getTitleHeight());
}
/**
@@ -1810,7 +1821,7 @@ public class WebView extends AbsoluteLayout
/**
* Given an x coordinate in content space, convert it to view
- * space. Also used for absolute heights.
+ * space.
*/
/*package*/ int contentToViewX(int x) {
return contentToViewDimension(x);
@@ -2000,7 +2011,7 @@ public class WebView extends AbsoluteLayout
getGlobalVisibleRect(r, p);
r.offset(-p.x, -p.y);
if (mFindIsUp) {
- r.bottom -= FIND_HEIGHT;
+ r.bottom -= mFindHeight;
}
}
@@ -2072,9 +2083,6 @@ public class WebView extends AbsoluteLayout
}
}
- // Make sure this stays in sync with the actual height of the FindDialog.
- private static final int FIND_HEIGHT = 79;
-
@Override
protected int computeVerticalScrollRange() {
if (mDrawHistory) {
@@ -2305,7 +2313,11 @@ public class WebView extends AbsoluteLayout
* that were found.
*/
public int findAll(String find) {
- mFindIsUp = true;
+ if (mFindIsUp == false) {
+ recordNewContentSize(mContentWidth, mContentHeight + mFindHeight,
+ false);
+ mFindIsUp = true;
+ }
int result = nativeFindAll(find.toLowerCase(), find.toUpperCase());
invalidate();
return result;
@@ -2314,6 +2326,7 @@ public class WebView extends AbsoluteLayout
// Used to know whether the find dialog is open. Affects whether
// or not we draw the highlights for matches.
private boolean mFindIsUp;
+ private int mFindHeight;
/**
* Return the first substring consisting of the address of a physical
@@ -2369,7 +2382,11 @@ public class WebView extends AbsoluteLayout
* Clear the highlighting surrounding text matches created by findAll.
*/
public void clearMatches() {
- mFindIsUp = false;
+ if (mFindIsUp) {
+ recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
+ false);
+ mFindIsUp = false;
+ }
nativeSetFindIsDown();
// Now that the dialog has been removed, ensure that we scroll to a
// location that is not beyond the end of the page.
@@ -2378,6 +2395,16 @@ public class WebView extends AbsoluteLayout
}
/**
+ * @hide
+ */
+ public void setFindDialogHeight(int height) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "setFindDialogHeight height=" + height);
+ }
+ mFindHeight = height;
+ }
+
+ /**
* Query the document to see if it contains any image references. The
* message object will be dispatched with arg1 being set to 1 if images
* were found and 0 if the document does not reference any images.
@@ -2419,7 +2446,6 @@ public class WebView extends AbsoluteLayout
private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) {
return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
}
-
// helper to pin the scrollTo parameters (already in view coordinates)
// returns true if the scroll was changed
private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) {
@@ -2431,15 +2457,6 @@ public class WebView extends AbsoluteLayout
if ((dx | dy) == 0) {
return false;
}
- // By this point we have added in the title bar's height. If the site
- // is trying to scroll to the top of the page, scroll it to the top
- // of the WebView including showing the title bar.
- // mobile sites prefer to scroll to (0, 1), thus the + 1 below
- if (getVisibleTitleHeight() > 0 && x == 0
- && y <= getTitleHeight() + 1) {
- y = 0;
- animate = false;
- }
if (animate) {
// Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
mScroller.startScroll(mScrollX, mScrollY, dx, dy,
@@ -2498,10 +2515,31 @@ public class WebView extends AbsoluteLayout
// saved scroll position, it is ok to skip this.
return false;
}
- int vx = contentToViewX(cx);
- int vy = contentToViewY(cy);
+ int vx;
+ int vy;
+ if ((cx | cy) == 0) {
+ // If the page is being scrolled to (0,0), do not add in the title
+ // bar's height, and simply scroll to (0,0). (The only other work
+ // in contentToView_ is to multiply, so this would not change 0.)
+ vx = 0;
+ vy = 0;
+ } else {
+ vx = contentToViewX(cx);
+ vy = contentToViewY(cy);
+ }
// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
// vx + " " + vy + "]");
+ // Some mobile sites attempt to scroll the title bar off the page by
+ // scrolling to (0,1). If we are at the top left corner of the
+ // page, assume this is an attempt to scroll off the title bar, and
+ // animate the title bar off screen slowly enough that the user can see
+ // it.
+ if (cx == 0 && cy == 1 && mScrollX == 0 && mScrollY == 0) {
+ pinScrollTo(vx, vy, true, SLIDE_TITLE_DURATION);
+ // Since we are animating, we have not yet reached the desired
+ // scroll position. Do not return true to request another attempt
+ return false;
+ }
pinScrollTo(vx, vy, false, 0);
// If the request was to scroll to a negative coordinate, treat it as if
// it was a request to scroll to 0
@@ -3732,6 +3770,13 @@ public class WebView extends AbsoluteLayout
&& !mZoomButtonsController.isVisible()
&& mMinZoomScale < mMaxZoomScale) {
mZoomButtonsController.setVisible(true);
+ int count = settings.getDoubleTapToastCount();
+ if (mInZoomOverview && count > 0) {
+ settings.setDoubleTapToastCount(--count);
+ Toast.makeText(mContext,
+ com.android.internal.R.string.double_tap_toast,
+ Toast.LENGTH_LONG).show();
+ }
}
}
@@ -4410,7 +4455,10 @@ public class WebView extends AbsoluteLayout
return;
}
mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContentX(x),
- viewToContentY(y));
+ // Since this position is relative to the top of the text input
+ // field, we do not need to take the title bar's height into
+ // consideration.
+ viewToContentDimension(y));
}
/**
@@ -4504,7 +4552,8 @@ public class WebView extends AbsoluteLayout
mZoomCenterY = mLastTouchY;
mInZoomOverview = !mInZoomOverview;
// remove the zoom control after double tap
- if (getSettings().getBuiltInZoomControls()) {
+ WebSettings settings = getSettings();
+ if (settings.getBuiltInZoomControls()) {
if (mZoomButtonsController.isVisible()) {
mZoomButtonsController.setVisible(false);
}
@@ -4516,7 +4565,10 @@ public class WebView extends AbsoluteLayout
mZoomControls.hide();
}
}
+ settings.setDoubleTapToastCount(0);
if (mInZoomOverview) {
+ // Force the titlebar fully reveal in overview mode
+ if (mScrollY < getTitleHeight()) mScrollY = 0;
zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth);
} else {
// mLastTouchX and mLastTouchY are the point in the current viewport
@@ -4816,7 +4868,7 @@ public class WebView extends AbsoluteLayout
/ draw.mMinPrefWidth;
mMinZoomScaleFixed = false;
} else {
- mMinZoomScale = mDefaultScale;
+ mMinZoomScale = restoreState.mDefaultScale;
mMinZoomScaleFixed = true;
}
} else {
@@ -4833,22 +4885,13 @@ public class WebView extends AbsoluteLayout
mMaxZoomScale = restoreState.mMaxScale;
}
setNewZoomScale(mLastScale, false);
- if (getTitleHeight() != 0 && restoreState.mScrollX == 0
- && restoreState.mScrollY == 0) {
- // If there is a title bar, and the page is being
- // restored to (0,0), do not scroll the title bar
- // off the page.
- abortAnimation();
- scrollTo(0,0);
- } else {
- setContentScrollTo(restoreState.mScrollX,
- restoreState.mScrollY);
- }
+ setContentScrollTo(restoreState.mScrollX,
+ restoreState.mScrollY);
if (useWideViewport
&& settings.getLoadWithOverviewMode()) {
if (restoreState.mViewScale == 0
|| (restoreState.mMobileSite
- && mMinZoomScale < mDefaultScale)) {
+ && mMinZoomScale < restoreState.mDefaultScale)) {
mInZoomOverview = true;
}
}
@@ -4865,7 +4908,8 @@ public class WebView extends AbsoluteLayout
final boolean updateLayout = viewSize.x == mLastWidthSent
&& viewSize.y == mLastHeightSent;
recordNewContentSize(draw.mWidthHeight.x,
- draw.mWidthHeight.y, updateLayout);
+ draw.mWidthHeight.y
+ + (mFindIsUp ? mFindHeight : 0), updateLayout);
if (DebugFlags.WEB_VIEW) {
Rect b = draw.mInvalRegion.getBounds();
Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index d4142bb..ce45373 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.DrawFilter;
import android.graphics.Paint;
@@ -37,6 +38,7 @@ import android.view.SurfaceView;
import android.view.View;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -100,6 +102,15 @@ final class WebViewCore {
private boolean mViewportUserScalable = true;
+ /*
+ * range is from 70 to 400.
+ * 0 is a special value means device-dpi. The default scale factor will be
+ * always 100.
+ * -1 means undefined. The default scale factor will be
+ * WebView.DEFAULT_SCALE_PERCENT.
+ */
+ private int mViewportDensityDpi = -1;
+
private int mRestoredScale = 0;
private int mRestoredScreenWidthScale = 0;
private int mRestoredX = 0;
@@ -153,8 +164,10 @@ final class WebViewCore {
// The WebIconDatabase needs to be initialized within the UI thread so
// just request the instance here.
WebIconDatabase.getInstance();
- // Create the WebStorage singleton
- WebStorage.getInstance();
+ // Create the WebStorage singleton and the UI handler
+ WebStorage.getInstance().createUIHandler();
+ // Create the UI handler for GeolocationPermissions
+ GeolocationPermissions.getInstance().createUIHandler();
// Send a message to initialize the WebViewCore.
Message init = sWebCoreHandler.obtainMessage(
WebCoreThread.INITIALIZE, this);
@@ -841,6 +854,7 @@ final class WebViewCore {
synchronized (WebViewCore.this) {
mBrowserFrame.destroy();
mBrowserFrame = null;
+ mSettings.onDestroyed();
mNativeClass = 0;
}
break;
@@ -1510,13 +1524,14 @@ final class WebViewCore {
// callbacks. Computes the sum of database quota for all origins.
private long getUsedQuota() {
WebStorage webStorage = WebStorage.getInstance();
- Set<String> origins = webStorage.getOrigins();
+ Collection<WebStorage.Origin> origins = webStorage.getOriginsSync();
+
if (origins == null) {
return 0;
}
long usedQuota = 0;
- for (String origin : origins) {
- usedQuota += webStorage.getQuotaForOrigin(origin);
+ for (WebStorage.Origin website : origins) {
+ usedQuota += website.getQuota();
}
return usedQuota;
}
@@ -1539,6 +1554,7 @@ final class WebViewCore {
float mMaxScale;
float mViewScale;
float mTextWrapScale;
+ float mDefaultScale;
int mScrollX;
int mScrollY;
boolean mMobileSite;
@@ -1842,47 +1858,48 @@ final class WebViewCore {
// set the viewport settings from WebKit
setViewportSettingsFromNative();
- // adjust the default scale to match the density
- if (WebView.DEFAULT_SCALE_PERCENT != 100) {
- float adjust = (float) WebView.DEFAULT_SCALE_PERCENT / 100.0f;
- if (mViewportInitialScale > 0) {
- mViewportInitialScale *= adjust;
- }
- if (mViewportMinimumScale > 0) {
- mViewportMinimumScale *= adjust;
- }
- if (mViewportMaximumScale > 0) {
- mViewportMaximumScale *= adjust;
+ // adjust the default scale to match the densityDpi
+ float adjust = 1.0f;
+ if (mViewportDensityDpi == -1) {
+ if (WebView.DEFAULT_SCALE_PERCENT != 100) {
+ adjust = WebView.DEFAULT_SCALE_PERCENT / 100.0f;
}
+ } else if (mViewportDensityDpi > 0) {
+ adjust = (float) mContext.getResources().getDisplayMetrics().densityDpi
+ / mViewportDensityDpi;
+ }
+ int defaultScale = (int) (adjust * 100);
+
+ if (mViewportInitialScale > 0) {
+ mViewportInitialScale *= adjust;
+ }
+ if (mViewportMinimumScale > 0) {
+ mViewportMinimumScale *= adjust;
+ }
+ if (mViewportMaximumScale > 0) {
+ mViewportMaximumScale *= adjust;
}
// infer the values if they are not defined.
if (mViewportWidth == 0) {
if (mViewportInitialScale == 0) {
- mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
+ mViewportInitialScale = defaultScale;
}
}
if (mViewportUserScalable == false) {
- mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
- mViewportMinimumScale = WebView.DEFAULT_SCALE_PERCENT;
- mViewportMaximumScale = WebView.DEFAULT_SCALE_PERCENT;
+ mViewportInitialScale = defaultScale;
+ mViewportMinimumScale = defaultScale;
+ mViewportMaximumScale = defaultScale;
}
- if (mViewportMinimumScale > mViewportInitialScale) {
- if (mViewportInitialScale == 0) {
- mViewportInitialScale = mViewportMinimumScale;
- } else {
- mViewportMinimumScale = mViewportInitialScale;
- }
+ if (mViewportMinimumScale > mViewportInitialScale
+ && mViewportInitialScale != 0) {
+ mViewportMinimumScale = mViewportInitialScale;
}
- if (mViewportMaximumScale > 0) {
- if (mViewportMaximumScale < mViewportInitialScale) {
- mViewportMaximumScale = mViewportInitialScale;
- } else if (mViewportInitialScale == 0) {
- mViewportInitialScale = mViewportMaximumScale;
- }
+ if (mViewportMaximumScale > 0
+ && mViewportMaximumScale < mViewportInitialScale) {
+ mViewportMaximumScale = mViewportInitialScale;
}
- if (mViewportWidth < 0
- && mViewportInitialScale == WebView.DEFAULT_SCALE_PERCENT) {
+ if (mViewportWidth < 0 && mViewportInitialScale == defaultScale) {
mViewportWidth = 0;
}
@@ -1899,7 +1916,7 @@ final class WebViewCore {
// we call WebView method from WebCore thread. But not perfect
// reference is better than no reference.
webViewWidth = mWebView.getViewWidth();
- viewportWidth = webViewWidth * 100 / WebView.DEFAULT_SCALE_PERCENT;
+ viewportWidth = (int) (webViewWidth / adjust);
if (viewportWidth == 0) {
Log.w(LOGTAG, "Can't get the viewWidth after the first layout");
}
@@ -1909,6 +1926,7 @@ final class WebViewCore {
mRestoreState = new RestoreState();
mRestoreState.mMinScale = mViewportMinimumScale / 100.0f;
mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f;
+ mRestoreState.mDefaultScale = adjust;
mRestoreState.mScrollX = mRestoredX;
mRestoreState.mScrollY = mRestoredY;
mRestoreState.mMobileSite = (0 == mViewportWidth);
@@ -1930,8 +1948,7 @@ final class WebViewCore {
mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
(float) webViewWidth / mViewportWidth;
} else {
- mRestoreState.mTextWrapScale =
- WebView.DEFAULT_SCALE_PERCENT / 100.0f;
+ mRestoreState.mTextWrapScale = adjust;
// 0 will trigger WebView to turn on zoom overview mode
mRestoreState.mViewScale = 0;
}
@@ -2075,22 +2092,49 @@ final class WebViewCore {
}
}
- // PluginWidget functions for creating SurfaceViews for the Surface drawing
- // model.
- private ViewManager.ChildView createSurface(String packageName, String className,
+ // called by JNI. PluginWidget function to launch an activity and overlays
+ // the activity with the View provided by the plugin class.
+ private void startFullScreenPluginActivity(String libName, String clsName, int npp) {
+ if (mWebView == null) {
+ return;
+ }
+
+ String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName);
+ if (pkgName == null) {
+ Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK");
+ return;
+ }
+
+ Intent intent = new Intent("android.intent.webkit.PLUGIN");
+ intent.putExtra(PluginActivity.INTENT_EXTRA_PACKAGE_NAME, pkgName);
+ intent.putExtra(PluginActivity.INTENT_EXTRA_CLASS_NAME, clsName);
+ intent.putExtra(PluginActivity.INTENT_EXTRA_NPP_INSTANCE, npp);
+ mWebView.getContext().startActivity(intent);
+ }
+
+ // called by JNI. PluginWidget functions for creating an embedded View for
+ // the surface drawing model.
+ private ViewManager.ChildView createSurface(String libName, String clsName,
int npp, int x, int y, int width, int height) {
if (mWebView == null) {
return null;
}
- PluginStub stub = PluginUtil.getPluginStub(mWebView.getContext(), packageName, className);
+
+ String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName);
+ if (pkgName == null) {
+ Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK");
+ return null;
+ }
+
+ PluginStub stub =PluginUtil.getPluginStub(mWebView.getContext(),pkgName, clsName);
if (stub == null) {
- Log.e(LOGTAG, "Unable to find plugin class (" + className +
- ") in the apk (" + packageName + ")");
+ Log.e(LOGTAG, "Unable to find plugin class (" + clsName +
+ ") in the apk (" + pkgName + ")");
return null;
}
-
+
View pluginView = stub.getEmbeddedView(npp, mWebView.getContext());
-
+
ViewManager.ChildView view = mWebView.mViewManager.createView();
view.mView = pluginView;
view.attachView(x, y, width, height);
diff --git a/core/java/android/widget/FasttrackBadgeWidget.java b/core/java/android/widget/FasttrackBadgeWidget.java
index 9d2307f..8c8e054 100644
--- a/core/java/android/widget/FasttrackBadgeWidget.java
+++ b/core/java/android/widget/FasttrackBadgeWidget.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.database.Cursor;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.FastTrack;
@@ -46,6 +47,7 @@ public class FasttrackBadgeWidget extends ImageView implements OnClickListener {
private String mContactPhone;
private int mMode;
private QueryHandler mQueryHandler;
+ private Drawable mBadgeBackground;
protected String[] mExcludeMimes = null;
@@ -91,6 +93,8 @@ public class FasttrackBadgeWidget extends ImageView implements OnClickListener {
a.recycle();
init();
+
+ mBadgeBackground = getBackground();
}
private void init() {
@@ -108,6 +112,17 @@ public class FasttrackBadgeWidget extends ImageView implements OnClickListener {
*/
public void assignContactUri(Uri contactUri) {
mContactUri = contactUri;
+ mContactEmail = null;
+ mContactPhone = null;
+ onContactUriChanged();
+ }
+
+ private void onContactUriChanged() {
+ if (mContactUri == null && mContactEmail == null && mContactPhone == null) {
+ setBackgroundDrawable(null);
+ } else {
+ setBackgroundDrawable(mBadgeBackground);
+ }
}
/**
@@ -127,6 +142,7 @@ public class FasttrackBadgeWidget extends ImageView implements OnClickListener {
EMAIL_LOOKUP_PROJECTION, null, null, null);
} else {
mContactUri = null;
+ onContactUriChanged();
}
}
@@ -147,6 +163,7 @@ public class FasttrackBadgeWidget extends ImageView implements OnClickListener {
PHONE_LOOKUP_PROJECTION, null, null, null);
} else {
mContactUri = null;
+ onContactUriChanged();
}
}
@@ -237,6 +254,7 @@ public class FasttrackBadgeWidget extends ImageView implements OnClickListener {
}
mContactUri = lookupUri;
+ onContactUriChanged();
if (trigger && lookupUri != null) {
// Found contact, so trigger track
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 703cd8e..31c7814 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -743,7 +743,7 @@ public class ScrollView extends FrameLayout {
final int maxJump = getMaxScrollAmount();
- if (nextFocused != null && isWithinDeltaOfScreen(nextFocused, maxJump)) {
+ if (nextFocused != null && isWithinDeltaOfScreen(nextFocused, maxJump, getHeight())) {
nextFocused.getDrawingRect(mTempRect);
offsetDescendantRectToMyCoords(nextFocused, mTempRect);
int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
@@ -792,19 +792,19 @@ public class ScrollView extends FrameLayout {
* screen.
*/
private boolean isOffScreen(View descendant) {
- return !isWithinDeltaOfScreen(descendant, 0);
+ return !isWithinDeltaOfScreen(descendant, 0, getHeight());
}
/**
* @return whether the descendant of this scroll view is within delta
* pixels of being on the screen.
*/
- private boolean isWithinDeltaOfScreen(View descendant, int delta) {
+ private boolean isWithinDeltaOfScreen(View descendant, int delta, int height) {
descendant.getDrawingRect(mTempRect);
offsetDescendantRectToMyCoords(descendant, mTempRect);
return (mTempRect.bottom + delta) >= getScrollY()
- && (mTempRect.top - delta) <= (getScrollY() + getHeight());
+ && (mTempRect.top - delta) <= (getScrollY() + height);
}
/**
@@ -1124,9 +1124,10 @@ public class ScrollView extends FrameLayout {
if (null == currentFocused || this == currentFocused)
return;
- final int maxJump = mBottom - mTop;
-
- if (isWithinDeltaOfScreen(currentFocused, maxJump)) {
+ // If the currently-focused view was visible on the screen when the
+ // screen was at the old height, then scroll the screen to make that
+ // view visible with the new screen height.
+ if (isWithinDeltaOfScreen(currentFocused, 0, oldh)) {
currentFocused.getDrawingRect(mTempRect);
offsetDescendantRectToMyCoords(currentFocused, mTempRect);
int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2e3364b..3c61c1c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2874,26 +2874,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @attr ref android.R.styleable#TextView_inputType
*/
public void setInputType(int type) {
+ final boolean wasPassword = isPasswordInputType(mInputType);
+ final boolean wasVisiblePassword = isVisiblePasswordInputType(mInputType);
setInputType(type, false);
- final int variation = type&(EditorInfo.TYPE_MASK_CLASS
- |EditorInfo.TYPE_MASK_VARIATION);
- final boolean isPassword = variation
- == (EditorInfo.TYPE_CLASS_TEXT
- |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ final boolean isPassword = isPasswordInputType(type);
+ final boolean isVisiblePassword = isVisiblePasswordInputType(type);
boolean forceUpdate = false;
if (isPassword) {
setTransformationMethod(PasswordTransformationMethod.getInstance());
setTypefaceByIndex(MONOSPACE, 0);
- } else if (mTransformation == PasswordTransformationMethod.getInstance()) {
- // We need to clean up if we were previously in password mode.
- if (variation != (EditorInfo.TYPE_CLASS_TEXT
- |EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)) {
- setTypefaceByIndex(-1, -1);
- }
- forceUpdate = true;
- } else if (variation == (EditorInfo.TYPE_CLASS_TEXT
- |EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)) {
+ } else if (isVisiblePassword) {
setTypefaceByIndex(MONOSPACE, 0);
+ } else if (wasPassword || wasVisiblePassword) {
+ // not in password mode, clean up typeface and transformation
+ setTypefaceByIndex(-1, -1);
+ if (mTransformation == PasswordTransformationMethod.getInstance()) {
+ forceUpdate = true;
+ }
}
boolean multiLine = (type&(EditorInfo.TYPE_MASK_CLASS
@@ -2913,6 +2910,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (imm != null) imm.restartInput(this);
}
+ private boolean isPasswordInputType(int inputType) {
+ final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS
+ | EditorInfo.TYPE_MASK_VARIATION);
+ return variation
+ == (EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+ }
+
+ private boolean isVisiblePasswordInputType(int inputType) {
+ final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS
+ | EditorInfo.TYPE_MASK_VARIATION);
+ return variation
+ == (EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+ }
+
/**
* Directly change the content type integer of the text view, without
* modifying any other state.
diff --git a/core/java/com/android/internal/backup/BackupConstants.java b/core/java/com/android/internal/backup/BackupConstants.java
new file mode 100644
index 0000000..3ee11bd
--- /dev/null
+++ b/core/java/com/android/internal/backup/BackupConstants.java
@@ -0,0 +1,26 @@
+/*
+ * 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.backup;
+
+/**
+ * Constants used internally between the backup manager and its transports
+ */
+public class BackupConstants {
+ public static final int TRANSPORT_OK = 0;
+ public static final int TRANSPORT_ERROR = 1;
+ public static final int TRANSPORT_NOT_INITIALIZED = 2;
+}
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index af06965..a830ebd 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -22,24 +22,6 @@ import android.os.ParcelFileDescriptor;
/** {@hide} */
interface IBackupTransport {
-/* STOPSHIP - don't ship with this comment in place
- Things the transport interface has to do:
- 1. set up the connection to the destination
- - set up encryption
- - for Google cloud, log in using the user's gaia credential or whatever
- - for adb, just set up the all-in-one destination file
- 2. send each app's backup transaction
- - parse the data file for key/value pointers etc
- - send key/blobsize set to the Google cloud, get back quota ok/rejected response
- - sd/adb doesn't preflight; no per-app quota
- - app's entire change is essentially atomic
- - cloud transaction encrypts then sends each key/value pair separately; we already
- parsed the data when preflighting so we don't have to again here
- - sd target streams raw data into encryption envelope then to sd?
- 3. shut down connection to destination
- - cloud: tear down connection etc
- - adb: close the file
-*/
/**
* Ask the transport where, on local device storage, to keep backup state blobs.
* This is per-transport so that mock transports used for testing can coexist with
@@ -68,6 +50,17 @@ interface IBackupTransport {
long requestBackupTime();
/**
+ * Initialize the server side storage for this device, erasing all stored data.
+ * The transport may send the request immediately, or may buffer it. After
+ * this is called, {@link #finishBackup} must be called to ensure the request
+ * is sent and received successfully.
+ *
+ * @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far) or
+ * {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure).
+ */
+ int initializeDevice();
+
+ /**
* Send one application's data to the backup destination. The transport may send
* the data immediately, or may buffer it. After this is called, {@link #finishBackup}
* must be called to ensure the data is sent and recorded successfully.
@@ -77,10 +70,16 @@ interface IBackupTransport {
* @param data The data stream that resulted from invoking the application's
* BackupService.doBackup() method. This may be a pipe rather than a file on
* persistent media, so it may not be seekable.
- * @return false if errors occurred (the backup should be aborted and rescheduled),
- * true if everything is OK so far (but {@link #finishBackup} must be called).
+ * @param wipeAllFirst When true, <i>all</i> backed-up data for the current device/account
+ * will be erased prior to the storage of the data provided here. The purpose of this
+ * is to provide a guarantee that no stale data exists in the restore set when the
+ * device begins providing backups.
+ * @return one of {@link BackupConstants#TRANSPORT_OK} (OK so far),
+ * {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure), or
+ * {@link BackupConstants#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
+ * become lost due to inactive expiry or some other reason and needs re-initializing)
*/
- boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
+ int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
/**
* Erase the give application's data from the backup destination. This clears
@@ -88,10 +87,9 @@ interface IBackupTransport {
* the app had never yet been backed up. After this is called, {@link finishBackup}
* must be called to ensure that the operation is recorded successfully.
*
- * @return false if errors occurred (the backup should be aborted and rescheduled),
- * true if everything is OK so far (but {@link #finishBackup} must be called).
+ * @return the same error codes as {@link #performBackup}.
*/
- boolean clearBackupData(in PackageInfo packageInfo);
+ int clearBackupData(in PackageInfo packageInfo);
/**
* Finish sending application data to the backup destination. This must be
@@ -99,10 +97,9 @@ interface IBackupTransport {
* all data is sent. Only when this method returns true can a backup be assumed
* to have succeeded.
*
- * @return false if errors occurred (the backup should be aborted and rescheduled),
- * true if everything is OK.
+ * @return the same error codes as {@link #performBackup}.
*/
- boolean finishBackup();
+ int finishBackup();
/**
* Get the set of backups currently available over this transport.
@@ -120,10 +117,11 @@ interface IBackupTransport {
* @param token A backup token as returned by {@link #getAvailableRestoreSets}.
* @param packages List of applications to restore (if data is available).
* Application data will be restored in the order given.
- * @return false if errors occurred (the restore should be aborted and rescheduled),
- * true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
+ * @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far, call
+ * {@link #nextRestorePackage}) or {@link BackupConstants#TRANSPORT_ERROR}
+ * (an error occurred, the restore should be aborted and rescheduled).
*/
- boolean startRestore(long token, in PackageInfo[] packages);
+ int startRestore(long token, in PackageInfo[] packages);
/**
* Get the package name of the next application with data in the backup store.
@@ -136,10 +134,9 @@ interface IBackupTransport {
/**
* Get the data for the application returned by {@link #nextRestorePackage}.
* @param data An open, writable file into which the backup data should be stored.
- * @return false if errors occurred (the restore should be aborted and rescheduled),
- * true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
+ * @return the same error codes as {@link #nextRestorePackage}.
*/
- boolean getRestoreData(in ParcelFileDescriptor outFd);
+ int getRestoreData(in ParcelFileDescriptor outFd);
/**
* End a restore session (aborting any in-process data transfer as necessary),
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 2facce2..4fc3edc 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -47,17 +47,22 @@ public class LocalTransport extends IBackupTransport.Stub {
}
- public String transportDirName() throws RemoteException {
+ public String transportDirName() {
return TRANSPORT_DIR_NAME;
}
- public long requestBackupTime() throws RemoteException {
+ public long requestBackupTime() {
// any time is a good time for local backup
return 0;
}
- public boolean performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
- throws RemoteException {
+ public int initializeDevice() {
+ if (DEBUG) Log.v(TAG, "wiping all data");
+ deleteContents(mDataDir);
+ return BackupConstants.TRANSPORT_OK;
+ }
+
+ public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
File packageDir = new File(mDataDir, packageInfo.packageName);
@@ -95,7 +100,7 @@ public class LocalTransport extends IBackupTransport.Stub {
entity.write(buf, 0, dataSize);
} catch (IOException e) {
Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath());
- return false;
+ return BackupConstants.TRANSPORT_ERROR;
} finally {
entity.close();
}
@@ -103,15 +108,30 @@ public class LocalTransport extends IBackupTransport.Stub {
entityFile.delete();
}
}
- return true;
+ return BackupConstants.TRANSPORT_OK;
} catch (IOException e) {
// oops, something went wrong. abort the operation and return error.
Log.v(TAG, "Exception reading backup input:", e);
- return false;
+ return BackupConstants.TRANSPORT_ERROR;
+ }
+ }
+
+ // Deletes the contents but not the given directory
+ private void deleteContents(File dirname) {
+ File[] contents = dirname.listFiles();
+ if (contents != null) {
+ for (File f : contents) {
+ if (f.isDirectory()) {
+ // delete the directory's contents then fall through
+ // and delete the directory itself.
+ deleteContents(f);
+ }
+ f.delete();
+ }
}
}
- public boolean clearBackupData(PackageInfo packageInfo) {
+ public int clearBackupData(PackageInfo packageInfo) {
if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
File packageDir = new File(mDataDir, packageInfo.packageName);
@@ -119,12 +139,12 @@ public class LocalTransport extends IBackupTransport.Stub {
f.delete();
}
packageDir.delete();
- return true;
+ return BackupConstants.TRANSPORT_OK;
}
- public boolean finishBackup() throws RemoteException {
+ public int finishBackup() {
if (DEBUG) Log.v(TAG, "finishBackup()");
- return true;
+ return BackupConstants.TRANSPORT_OK;
}
// Restore handling
@@ -135,11 +155,11 @@ public class LocalTransport extends IBackupTransport.Stub {
return array;
}
- public boolean startRestore(long token, PackageInfo[] packages) {
+ public int startRestore(long token, PackageInfo[] packages) {
if (DEBUG) Log.v(TAG, "start restore " + token);
mRestorePackages = packages;
mRestorePackage = -1;
- return true;
+ return BackupConstants.TRANSPORT_OK;
}
public String nextRestorePackage() {
@@ -156,7 +176,7 @@ public class LocalTransport extends IBackupTransport.Stub {
return "";
}
- public boolean getRestoreData(ParcelFileDescriptor outFd) {
+ public int getRestoreData(ParcelFileDescriptor outFd) {
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName);
@@ -164,9 +184,9 @@ public class LocalTransport extends IBackupTransport.Stub {
// The restore set is the concatenation of the individual record blobs,
// each of which is a file in the package's directory
File[] blobs = packageDir.listFiles();
- if (blobs == null) {
+ if (blobs == null) { // nextRestorePackage() ensures the dir exists, so this is an error
Log.e(TAG, "Error listing directory: " + packageDir);
- return false; // nextRestorePackage() ensures the dir exists, so this is an error
+ return BackupConstants.TRANSPORT_ERROR;
}
// We expect at least some data if the directory exists in the first place
@@ -187,10 +207,10 @@ public class LocalTransport extends IBackupTransport.Stub {
in.close();
}
}
- return true;
+ return BackupConstants.TRANSPORT_OK;
} catch (IOException e) {
Log.e(TAG, "Unable to read backup records", e);
- return false;
+ return BackupConstants.TRANSPORT_ERROR;
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 2da72df..35c66ba 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -56,7 +56,9 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 39;
+ private static final int VERSION = 40;
+
+ private static int sNumSpeedSteps;
private final File mFile;
private final File mBackupFile;
@@ -213,7 +215,7 @@ public final class BatteryStatsImpl extends BatteryStats {
/**
* State for keeping track of counting information.
*/
- public static final class Counter extends BatteryStats.Counter implements Unpluggable {
+ public static class Counter extends BatteryStats.Counter implements Unpluggable {
int mCount;
int mLoadedCount;
int mLastCount;
@@ -302,7 +304,22 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedCount = mPluggedCount = mCount;
}
}
-
+
+ public static class SamplingCounter extends Counter {
+
+ SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
+ super(unpluggables, in);
+ }
+
+ SamplingCounter(ArrayList<Unpluggable> unpluggables) {
+ super(unpluggables);
+ }
+
+ public void addCountLocked(long count) {
+ mCount += count;
+ }
+ }
+
/**
* State for keeping track of timing information.
*/
@@ -1940,10 +1957,16 @@ public final class BatteryStatsImpl extends BatteryStats {
*/
long mUnpluggedForegroundTime;
+ SamplingCounter[] mSpeedBins;
+
Proc() {
mUnpluggables.add(this);
+ mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
+ for (int i = 0; i < mSpeedBins.length; i++) {
+ mSpeedBins[i] = new SamplingCounter(mUnpluggables);
+ }
}
-
+
public void unplug(long batteryUptime, long batteryRealtime) {
mUnpluggedUserTime = mUserTime;
mUnpluggedSystemTime = mSystemTime;
@@ -1974,6 +1997,11 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeLong(mUnpluggedSystemTime);
out.writeLong(mUnpluggedForegroundTime);
out.writeInt(mUnpluggedStarts);
+
+ out.writeInt(mSpeedBins.length);
+ for (int i = 0; i < mSpeedBins.length; i++) {
+ mSpeedBins[i].writeToParcel(out);
+ }
}
void readFromParcelLocked(Parcel in) {
@@ -1993,6 +2021,12 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedSystemTime = in.readLong();
mUnpluggedForegroundTime = in.readLong();
mUnpluggedStarts = in.readInt();
+
+ int bins = in.readInt();
+ mSpeedBins = new SamplingCounter[bins];
+ for (int i = 0; i < bins; i++) {
+ mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
+ }
}
public BatteryStatsImpl getBatteryStats() {
@@ -2075,6 +2109,22 @@ public final class BatteryStatsImpl extends BatteryStats {
}
return val;
}
+
+ /* Called by ActivityManagerService when CPU times are updated. */
+ public void addSpeedStepTimes(long[] values) {
+ for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
+ mSpeedBins[i].addCountLocked(values[i]);
+ }
+ }
+
+ @Override
+ public long getTimeAtCpuSpeedStep(int speedStep, int which) {
+ if (speedStep < mSpeedBins.length) {
+ return mSpeedBins[speedStep].getCountLocked(which);
+ } else {
+ return 0;
+ }
+ }
}
/**
@@ -2625,6 +2675,10 @@ public final class BatteryStatsImpl extends BatteryStats {
readFromParcel(p);
}
+ public void setNumSpeedSteps(int steps) {
+ if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
+ }
+
@Override
public int getStartCount() {
return mStartCount;
@@ -2853,6 +2907,11 @@ public final class BatteryStatsImpl extends BatteryStats {
return mDischargeCurrentLevel;
}
+ @Override
+ public int getCpuSpeedSteps() {
+ return sNumSpeedSteps;
+ }
+
/**
* Retrieve the statistics object for a particular uid, creating if needed.
*/
@@ -3063,7 +3122,9 @@ public final class BatteryStatsImpl extends BatteryStats {
getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
}
}
-
+
+ sNumSpeedSteps = in.readInt();
+
final int NU = in.readInt();
for (int iu = 0; iu < NU; iu++) {
int uid = in.readInt();
@@ -3206,6 +3267,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ out.writeInt(sNumSpeedSteps);
final int NU = mUidStats.size();
out.writeInt(NU);
for (int iu = 0; iu < NU; iu++) {
@@ -3404,6 +3466,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mFullTimers.clear();
mWindowTimers.clear();
+ sNumSpeedSteps = in.readInt();
+
int numUids = in.readInt();
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
@@ -3484,7 +3548,9 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(0);
}
}
-
+
+ out.writeInt(sNumSpeedSteps);
+
int size = mUidStats.size();
out.writeInt(size);
for (int i = 0; i < size; i++) {
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 94f703a..4b4b717 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -47,14 +47,9 @@ public class PowerProfile {
public static final String POWER_CPU_IDLE = "cpu.idle";
/**
- * Power consumption when CPU is running at normal speed.
- */
- public static final String POWER_CPU_NORMAL = "cpu.normal";
-
- /**
- * Power consumption when CPU is running at full speed.
+ * Power consumption when CPU is in power collapse mode.
*/
- public static final String POWER_CPU_FULL = "cpu.full";
+ public static final String POWER_CPU_ACTIVE = "cpu.active";
/**
* Power consumption when WiFi driver is scanning for networks.
@@ -124,6 +119,8 @@ public class PowerProfile {
*/
public static final String POWER_VIDEO = "dsp.video";
+ public static final String POWER_CPU_SPEEDS = "cpu.speeds";
+
static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>();
private static final String TAG_DEVICE = "device";
@@ -214,10 +211,10 @@ public class PowerProfile {
}
/**
- * Returns the average current in mA consumed by the subsystem for the given level.
+ * Returns the average current in mA consumed by the subsystem for the given level.
* @param type the subsystem type
* @param level the level of power at which the subsystem is running. For instance, the
- * signal strength of the cell network between 0 and 4 (if there are 4 bars max.).
+ * signal strength of the cell network between 0 and 4 (if there are 4 bars max.)
* If there is no data for multiple levels, the level is ignored.
* @return the average current in milliAmps.
*/
@@ -240,4 +237,12 @@ public class PowerProfile {
return 0;
}
}
+
+ public int getNumSpeedSteps() {
+ Object value = sPowerMap.get(POWER_CPU_SPEEDS);
+ if (value != null && value instanceof Double[]) {
+ return ((Double[])value).length;
+ }
+ return 1; // Only one speed
+ }
}
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index 4ec597c..35d637d 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -63,6 +63,7 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList
private static final String TAG = "ContactHeaderWidget";
private TextView mDisplayNameView;
+ private View mAggregateBadge;
private TextView mPhoneticNameView;
private CheckBox mStarredView;
private FasttrackBadgeWidget mPhotoView;
@@ -159,6 +160,8 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList
mDisplayNameView = (TextView) findViewById(R.id.name);
mDisplayNameView.setOnLongClickListener(this);
+ mAggregateBadge = findViewById(R.id.aggregate_badge);
+ mAggregateBadge.setVisibility(View.GONE);
mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
@@ -248,7 +251,9 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList
PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
} else {
- setDisplayName((String) cookie, null);
+ String phoneNumber = (String) cookie;
+ setDisplayName(phoneNumber, null);
+ mPhotoView.assignContactFromPhone(phoneNumber, true);
}
break;
}
@@ -259,7 +264,9 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList
EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
} else {
- setDisplayName((String) cookie, null);
+ String emailAddress = (String) cookie;
+ setDisplayName(emailAddress, null);
+ mPhotoView.assignContactFromEmail(emailAddress, true);
}
break;
}
@@ -280,6 +287,13 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList
}
/**
+ * Turn on/off showing of the aggregate bage element.
+ */
+ public void showAggregateBadge(boolean showBagde) {
+ mAggregateBadge.setVisibility(showBagde ? View.VISIBLE : View.GONE);
+ }
+
+ /**
* Turn on/off showing of the star element.
*/
public void showStar(boolean showStar) {
@@ -306,6 +320,7 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList
*/
public void setContactUri(Uri uri) {
mContactUri = uri;
+ mPhotoView.assignContactUri(uri);
}
/**
@@ -398,7 +413,7 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList
*/
public void bindFromPhoneNumber(String number) {
mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number,
- Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
PHONE_LOOKUP_PROJECTION, null, null, null);
}
diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java
index 712f1bf..426cef5 100644
--- a/core/java/com/android/internal/widget/RotarySelector.java
+++ b/core/java/com/android/internal/widget/RotarySelector.java
@@ -25,7 +25,9 @@ import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
-import android.view.animation.AccelerateInterpolator;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.animation.DecelerateInterpolator;
import static android.view.animation.AnimationUtils.currentAnimationTimeMillis;
import com.android.internal.R;
@@ -59,21 +61,18 @@ public class RotarySelector extends View {
private int mLeftHandleX;
private int mRightHandleX;
- // current offset of user's dragging
- private int mTouchDragOffset = 0;
+ // current offset of rotary widget along the x axis
+ private int mRotaryOffsetX = 0;
// state of the animation used to bring the handle back to its start position when
// the user lets go before triggering an action
private boolean mAnimating = false;
- private long mAnimationEndTime;
- private int mAnimatingDelta;
- private AccelerateInterpolator mInterpolator;
+ private long mAnimationStartTime;
+ private long mAnimationDuration;
+ private int mAnimatingDeltaXStart; // the animation will interpolate from this delta to zero
+ private int mAnimatingDeltaXEnd;
- /**
- * 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;
+ private DecelerateInterpolator mInterpolator;
/**
* If the user is currently dragging something.
@@ -91,8 +90,8 @@ public class RotarySelector extends View {
// Vibration (haptic feedback)
private Vibrator mVibrator;
- private static final long VIBRATE_SHORT = 60; // msec
- private static final long VIBRATE_LONG = 100; // msec
+ private static final long VIBRATE_SHORT = 30; // msec
+ private static final long VIBRATE_LONG = 60; // msec
/**
* The drawable for the arrows need to be scrunched this many dips towards the rotary bg below
@@ -108,17 +107,37 @@ public class RotarySelector extends View {
/**
* How far from the edge of the screen the user must drag to trigger the event.
*/
- private static final int EDGE_TRIGGER_DIP = 65;
+ private static final int EDGE_TRIGGER_DIP = 100;
/**
* 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;
+ static final int SNAP_BACK_ANIMATION_DURATION_MILLIS = 300;
+ static final int SPIN_ANIMATION_DURATION_MILLIS = 800;
- private static final boolean DRAW_CENTER_DIMPLE = false;
+ private static final boolean DRAW_CENTER_DIMPLE = true;
private int mEdgeTriggerThresh;
+ private int mDimpleWidth;
+ private int mBackgroundWidth;
+ private int mBackgroundHeight;
+ private final int mOuterRadius;
+ private final int mInnerRadius;
+ private int mDimpleSpacing;
+
+ private VelocityTracker mVelocityTracker;
+ private int mMinimumVelocity;
+ private int mMaximumVelocity;
+
+ /**
+ * The number of dimples we are flinging when we do the "spin" animation. Used to know when to
+ * wrap the icons back around so they "rotate back" onto the screen.
+ * @see #updateAnimation()
+ */
+ private int mDimplesOfFling = 0;
+
+
public RotarySelector(Context context) {
this(context, null);
@@ -152,9 +171,31 @@ public class RotarySelector extends View {
mArrowLongLeft.setBounds(0, 0, arrowW, arrowH);
mArrowLongRight.setBounds(0, 0, arrowW, arrowH);
- mInterpolator = new AccelerateInterpolator();
+ mInterpolator = new DecelerateInterpolator(1f);
mEdgeTriggerThresh = (int) (mDensity * EDGE_TRIGGER_DIP);
+
+ mDimpleWidth = mDimple.getIntrinsicWidth();
+
+ mBackgroundWidth = mBackground.getIntrinsicWidth();
+ mBackgroundHeight = mBackground.getIntrinsicHeight();
+ mOuterRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP);
+ mInnerRadius = (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity);
+
+ final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+ mMinimumVelocity = configuration.getScaledMinimumFlingVelocity() * 2;
+ mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ mLeftHandleX = (int) (EDGE_PADDING_DIP * mDensity) + mDimpleWidth / 2;
+ mRightHandleX =
+ getWidth() - (int) (EDGE_PADDING_DIP * mDensity) - mDimpleWidth / 2;
+
+ mDimpleSpacing = (getWidth() / 2) - mLeftHandleX;
}
/**
@@ -214,7 +255,7 @@ public class RotarySelector extends View {
final int width = MeasureSpec.getSize(widthMeasureSpec); // screen width
final int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
- final int backgroundH = mBackground.getIntrinsicHeight();
+ final int backgroundH = mBackgroundHeight;
// by making the height less than arrow + bg, arrow and bg will be scrunched together,
// overlaying somewhat (though on transparent portions of the drawable).
@@ -224,44 +265,26 @@ public class RotarySelector extends View {
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));
+ log(String.format("onDraw: mAnimating=%s, mRotaryOffsetX=%d, mGrabbedState=%d",
+ mAnimating, mRotaryOffsetX, mGrabbedState));
}
final int height = getHeight();
// update animating state before we draw anything
- if (mAnimating && !mFrozen) {
- long millisLeft = mAnimationEndTime - currentAnimationTimeMillis();
- if (DBG) log("millisleft for animating: " + millisLeft);
- if (millisLeft <= 0) {
- reset();
- } else {
- float interpolation = mInterpolator.getInterpolation(
- (float) millisLeft / ANIMATION_DURATION_MILLIS);
- mTouchDragOffset = (int) (mAnimatingDelta * interpolation);
- }
+ if (mAnimating) {
+ updateAnimation();
}
// Background:
- final int backgroundW = mBackground.getIntrinsicWidth();
- final int backgroundH = mBackground.getIntrinsicHeight();
+ final int backgroundW = mBackgroundWidth;
+ final int backgroundH = mBackgroundHeight;
final int backgroundY = height - backgroundH;
if (DBG) log("- Background INTRINSIC: " + backgroundW + " x " + backgroundH);
mBackground.setBounds(0, backgroundY,
@@ -293,16 +316,13 @@ public class RotarySelector extends View {
// 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 xOffset = mLeftHandleX + mRotaryOffsetX;
final int drawableY = getYOnArc(
mBackground,
- innerRadius,
- outerRadius,
+ mInnerRadius,
+ mOuterRadius,
xOffset);
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
@@ -312,22 +332,22 @@ public class RotarySelector extends View {
}
if (DRAW_CENTER_DIMPLE) {
- final int xOffset = getWidth() / 2 + mTouchDragOffset;
+ final int xOffset = getWidth() / 2 + mRotaryOffsetX;
final int drawableY = getYOnArc(
mBackground,
- innerRadius,
- outerRadius,
+ mInnerRadius,
+ mOuterRadius,
xOffset);
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
}
{
- final int xOffset = mRightHandleX + mTouchDragOffset;
+ final int xOffset = mRightHandleX + mRotaryOffsetX;
final int drawableY = getYOnArc(
mBackground,
- innerRadius,
- outerRadius,
+ mInnerRadius,
+ mOuterRadius,
xOffset);
drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
@@ -336,7 +356,33 @@ public class RotarySelector extends View {
}
}
- if (mAnimating) invalidate();
+ // draw extra left hand dimples
+ int dimpleLeft = mRotaryOffsetX + mLeftHandleX - mDimpleSpacing;
+ final int halfdimple = mDimpleWidth / 2;
+ while (dimpleLeft > -halfdimple) {
+ final int drawableY = getYOnArc(
+ mBackground,
+ mInnerRadius,
+ mOuterRadius,
+ dimpleLeft);
+
+ drawCentered(mDimple, canvas, dimpleLeft, drawableY + bgTop);
+ dimpleLeft -= mDimpleSpacing;
+ }
+
+ // draw extra right hand dimples
+ int dimpleRight = mRotaryOffsetX + mRightHandleX + mDimpleSpacing;
+ final int rightThresh = mRight + halfdimple;
+ while (dimpleRight < rightThresh) {
+ final int drawableY = getYOnArc(
+ mBackground,
+ mInnerRadius,
+ mOuterRadius,
+ dimpleRight);
+
+ drawCentered(mDimple, canvas, dimpleRight, drawableY + bgTop);
+ dimpleRight += mDimpleSpacing;
+ }
}
/**
@@ -383,12 +429,17 @@ public class RotarySelector extends View {
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
- if (mAnimating || mFrozen) {
+ if (mAnimating) {
return true;
}
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(event);
+
final int eventX = (int) event.getX();
- final int hitWindow = mDimple.getIntrinsicWidth();
+ final int hitWindow = mDimpleWidth;
final int action = event.getAction();
switch (action) {
@@ -400,12 +451,12 @@ public class RotarySelector extends View {
invalidate();
}
if (eventX < mLeftHandleX + hitWindow) {
- mTouchDragOffset = eventX - mLeftHandleX;
+ mRotaryOffsetX = eventX - mLeftHandleX;
mGrabbedState = LEFT_HANDLE_GRABBED;
invalidate();
vibrate(VIBRATE_SHORT);
} else if (eventX > mRightHandleX - hitWindow) {
- mTouchDragOffset = eventX - mRightHandleX;
+ mRotaryOffsetX = eventX - mRightHandleX;
mGrabbedState = RIGHT_HANDLE_GRABBED;
invalidate();
vibrate(VIBRATE_SHORT);
@@ -415,18 +466,38 @@ public class RotarySelector extends View {
case MotionEvent.ACTION_MOVE:
if (DBG) log("touch-move");
if (mGrabbedState == LEFT_HANDLE_GRABBED) {
- mTouchDragOffset = eventX - mLeftHandleX;
+ mRotaryOffsetX = eventX - mLeftHandleX;
invalidate();
if (eventX >= getRight() - mEdgeTriggerThresh && !mTriggered) {
mTriggered = true;
- mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
+ dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ final int velocity = Math.max(mMinimumVelocity, (int) velocityTracker.getXVelocity());
+ mDimplesOfFling = Math.max(
+ 8,
+ Math.abs(velocity / mDimpleSpacing));
+ startAnimationWithVelocity(
+ eventX - mLeftHandleX,
+ mDimplesOfFling * mDimpleSpacing,
+ velocity);
}
} else if (mGrabbedState == RIGHT_HANDLE_GRABBED) {
- mTouchDragOffset = eventX - mRightHandleX;
+ mRotaryOffsetX = eventX - mRightHandleX;
invalidate();
if (eventX <= mEdgeTriggerThresh && !mTriggered) {
mTriggered = true;
- mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
+ dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ final int velocity = Math.min(-mMinimumVelocity, (int) velocityTracker.getXVelocity());
+ mDimplesOfFling = Math.max(
+ 8,
+ Math.abs(velocity / mDimpleSpacing));
+ startAnimationWithVelocity(
+ eventX - mRightHandleX,
+ -(mDimplesOfFling * mDimpleSpacing),
+ velocity);
}
}
break;
@@ -435,32 +506,85 @@ public class RotarySelector extends View {
// handle animating back to start if they didn't trigger
if (mGrabbedState == LEFT_HANDLE_GRABBED
&& Math.abs(eventX - mLeftHandleX) > 5) {
- mAnimating = true;
- mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
- mAnimatingDelta = eventX - mLeftHandleX;
+ // set up "snap back" animation
+ startAnimation(eventX - mLeftHandleX, 0, SNAP_BACK_ANIMATION_DURATION_MILLIS);
} else if (mGrabbedState == RIGHT_HANDLE_GRABBED
&& Math.abs(eventX - mRightHandleX) > 5) {
- mAnimating = true;
- mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
- mAnimatingDelta = eventX - mRightHandleX;
+ // set up "snap back" animation
+ startAnimation(eventX - mRightHandleX, 0, SNAP_BACK_ANIMATION_DURATION_MILLIS);
}
-
- mTouchDragOffset = 0;
+ mRotaryOffsetX = 0;
mGrabbedState = NOTHING_GRABBED;
invalidate();
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle(); // wishin' we had generational GC
+ mVelocityTracker = null;
+ }
break;
case MotionEvent.ACTION_CANCEL:
if (DBG) log("touch-cancel");
reset();
invalidate();
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
break;
}
return true;
}
+ private void startAnimation(int startX, int endX, int duration) {
+ mAnimating = true;
+ mAnimationStartTime = currentAnimationTimeMillis();
+ mAnimationDuration = duration;
+ mAnimatingDeltaXStart = startX;
+ mAnimatingDeltaXEnd = endX;
+ mGrabbedState = NOTHING_GRABBED;
+ mDimplesOfFling = 0;
+ invalidate();
+ }
+
+ private void startAnimationWithVelocity(int startX, int endX, int pixelsPerSecond) {
+ mAnimating = true;
+ mAnimationStartTime = currentAnimationTimeMillis();
+ mAnimationDuration = 1000 * (endX - startX) / pixelsPerSecond;
+ mAnimatingDeltaXStart = startX;
+ mAnimatingDeltaXEnd = endX;
+ mGrabbedState = NOTHING_GRABBED;
+ invalidate();
+ }
+
+ private void updateAnimation() {
+ final long millisSoFar = currentAnimationTimeMillis() - mAnimationStartTime;
+ final long millisLeft = mAnimationDuration - millisSoFar;
+ final int totalDeltaX = mAnimatingDeltaXStart - mAnimatingDeltaXEnd;
+ if (DBG) log("millisleft for animating: " + millisLeft);
+ if (millisLeft <= 0) {
+ reset();
+ return;
+ }
+ // from 0 to 1 as animation progresses
+ float interpolation =
+ mInterpolator.getInterpolation((float) millisSoFar / mAnimationDuration);
+ final int dx = (int) (totalDeltaX * (1 - interpolation));
+ mRotaryOffsetX = mAnimatingDeltaXEnd + dx;
+ if (mDimplesOfFling > 0) {
+ if (mRotaryOffsetX < 4 * mDimpleSpacing) {
+ // wrap around on fling left
+ mRotaryOffsetX += (4 + mDimplesOfFling - 4) * mDimpleSpacing;
+ } else if (mRotaryOffsetX > 4 * mDimpleSpacing) {
+ // wrap around on fling right
+ mRotaryOffsetX -= (4 + mDimplesOfFling - 4) * mDimpleSpacing;
+ }
+ }
+ invalidate();
+ }
+
private void reset() {
mAnimating = false;
- mTouchDragOffset = 0;
+ mRotaryOffsetX = 0;
+ mDimplesOfFling = 0;
mGrabbedState = NOTHING_GRABBED;
mTriggered = false;
}
@@ -470,7 +594,8 @@ public class RotarySelector extends View {
*/
private synchronized void vibrate(long duration) {
if (mVibrator == null) {
- mVibrator = (android.os.Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+ mVibrator = (android.os.Vibrator)
+ getContext().getSystemService(Context.VIBRATOR_SERVICE);
}
mVibrator.vibrate(duration);
}
@@ -504,12 +629,11 @@ public class RotarySelector extends View {
/**
* Dispatches a trigger event to our listener.
*/
- private boolean dispatchTriggerEvent(int whichHandle) {
+ private void dispatchTriggerEvent(int whichHandle) {
vibrate(VIBRATE_LONG);
if (mOnDialTriggerListener != null) {
- return mOnDialTriggerListener.onDialTrigger(this, whichHandle);
+ mOnDialTriggerListener.onDialTrigger(this, whichHandle);
}
- return false;
}
/**
@@ -530,22 +654,13 @@ public class RotarySelector extends View {
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).
+ * either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}.
*/
- boolean onDialTrigger(View v, int whichHandle);
+ void onDialTrigger(View v, int whichHandle);
}
diff --git a/core/java/com/google/android/mms/pdu/GenericPdu.java b/core/java/com/google/android/mms/pdu/GenericPdu.java
index 46c6e00..705de6a 100644
--- a/core/java/com/google/android/mms/pdu/GenericPdu.java
+++ b/core/java/com/google/android/mms/pdu/GenericPdu.java
@@ -89,4 +89,25 @@ public class GenericPdu {
public void setMmsVersion(int value) throws InvalidHeaderValueException {
mPduHeaders.setOctet(value, PduHeaders.MMS_VERSION);
}
+
+ /**
+ * Get From value.
+ * From-value = Value-length
+ * (Address-present-token Encoded-string-value | Insert-address-token)
+ *
+ * @return the value
+ */
+ public EncodedStringValue getFrom() {
+ return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
+ }
+
+ /**
+ * Set From value.
+ *
+ * @param value the value
+ * @throws NullPointerException if the value is null.
+ */
+ public void setFrom(EncodedStringValue value) {
+ mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
+ }
}
diff --git a/core/java/com/google/android/mms/pdu/PduComposer.java b/core/java/com/google/android/mms/pdu/PduComposer.java
index 094e992..8b31936 100644
--- a/core/java/com/google/android/mms/pdu/PduComposer.java
+++ b/core/java/com/google/android/mms/pdu/PduComposer.java
@@ -450,6 +450,29 @@ public class PduComposer {
appendQuotedString(str.getBytes());
}
+ private EncodedStringValue appendAddressType(EncodedStringValue address) {
+ EncodedStringValue temp = null;
+
+ try {
+ int addressType = checkAddressType(address.getString());
+ temp = EncodedStringValue.copy(address);
+ if (PDU_PHONE_NUMBER_ADDRESS_TYPE == addressType) {
+ // Phone number.
+ temp.appendTextString(STRING_PHONE_NUMBER_ADDRESS_TYPE.getBytes());
+ } else if (PDU_IPV4_ADDRESS_TYPE == addressType) {
+ // Ipv4 address.
+ temp.appendTextString(STRING_IPV4_ADDRESS_TYPE.getBytes());
+ } else if (PDU_IPV6_ADDRESS_TYPE == addressType) {
+ // Ipv6 address.
+ temp.appendTextString(STRING_IPV6_ADDRESS_TYPE.getBytes());
+ }
+ } catch (NullPointerException e) {
+ return null;
+ }
+
+ return temp;
+ }
+
/**
* Append header to mMessage.
*/
@@ -489,21 +512,8 @@ public class PduComposer {
EncodedStringValue temp;
for (int i = 0; i < addr.length; i++) {
- try {
- int addressType = checkAddressType(addr[i].getString());
- temp = EncodedStringValue.copy(addr[i]);
- if (PDU_PHONE_NUMBER_ADDRESS_TYPE == addressType) {
- // Phone number.
- temp.appendTextString(
- STRING_PHONE_NUMBER_ADDRESS_TYPE.getBytes());
- } else if (PDU_IPV4_ADDRESS_TYPE == addressType) {
- // Ipv4 address.
- temp.appendTextString(STRING_IPV4_ADDRESS_TYPE.getBytes());
- } else if (PDU_IPV6_ADDRESS_TYPE == addressType) {
- // Ipv6 address.
- temp.appendTextString(STRING_IPV6_ADDRESS_TYPE.getBytes());
- }
- } catch (NullPointerException e) {
+ temp = appendAddressType(addr[i]);
+ if (temp == null) {
return PDU_COMPOSE_CONTENT_ERROR;
}
@@ -530,7 +540,13 @@ public class PduComposer {
// Address-present-token = <Octet 128>
append(PduHeaders.FROM_ADDRESS_PRESENT_TOKEN);
- appendEncodedString(from);
+
+ temp = appendAddressType(from);
+ if (temp == null) {
+ return PDU_COMPOSE_CONTENT_ERROR;
+ }
+
+ appendEncodedString(temp);
int flen = fstart.getLength();
mStack.pop();
diff --git a/core/java/com/google/android/mms/pdu/ReadRecInd.java b/core/java/com/google/android/mms/pdu/ReadRecInd.java
index 0a4dbf0..880e3ac 100644
--- a/core/java/com/google/android/mms/pdu/ReadRecInd.java
+++ b/core/java/com/google/android/mms/pdu/ReadRecInd.java
@@ -73,27 +73,6 @@ public class ReadRecInd extends GenericPdu {
}
/**
- * Get From value.
- * From-value = Value-length
- * (Address-present-token Encoded-string-value | Insert-address-token)
- *
- * @return the value
- */
- public EncodedStringValue getFrom() {
- return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
- }
-
- /**
- * Set From value.
- *
- * @param value the value
- * @throws NullPointerException if the value is null.
- */
- public void setFrom(EncodedStringValue value) {
- mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
- }
-
- /**
* Get Message-ID value.
*
* @return the value
diff --git a/core/java/com/google/android/mms/pdu/SendReq.java b/core/java/com/google/android/mms/pdu/SendReq.java
index 9ea6e47..597cd00 100644
--- a/core/java/com/google/android/mms/pdu/SendReq.java
+++ b/core/java/com/google/android/mms/pdu/SendReq.java
@@ -226,27 +226,6 @@ public class SendReq extends MultimediaMessagePdu {
}
/**
- * Get From value.
- * From-value = Value-length
- * (Address-present-token Encoded-string-value | Insert-address-token)
- *
- * @return the value
- */
- public EncodedStringValue getFrom() {
- return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
- }
-
- /**
- * Set From value.
- *
- * @param value the value
- * @throws NullPointerException if the value is null.
- */
- public void setFrom(EncodedStringValue value) {
- mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
- }
-
- /**
* Get X-Mms-Message-Class value.
* Message-class-value = Class-identifier | Token-text
* Class-identifier = Personal | Advertisement | Informational | Auto
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index ce2b10c..6b92994 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -55,7 +55,7 @@ private:
jobject mCameraJObjectWeak; // weak reference to java object
jclass mCameraJClass; // strong reference to java class
- sp<Camera> mCamera; // strong reference to native object
+ sp<Camera> mCamera; // strong reference to native object
Mutex mLock;
};
@@ -391,20 +391,26 @@ static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz)
}
}
-static jint android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
{
LOGV("lock");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
- if (camera == 0) return INVALID_OPERATION;
- return (jint) camera->lock();
+ if (camera == 0) return;
+
+ if (camera->lock() != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "lock failed");
+ }
}
-static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
{
LOGV("unlock");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
- if (camera == 0) return INVALID_OPERATION;
- return (jint) camera->unlock();
+ if (camera == 0) return;
+
+ if (camera->unlock() != NO_ERROR) {
+ jniThrowException(env, "java/lang/RuntimeException", "unlock failed");
+ }
}
//-------------------------------------------------
@@ -450,10 +456,10 @@ static JNINativeMethod camMethods[] = {
"()V",
(void*)android_hardware_Camera_reconnect },
{ "lock",
- "()I",
+ "()V",
(void*)android_hardware_Camera_lock },
{ "unlock",
- "()I",
+ "()V",
(void*)android_hardware_Camera_unlock },
};
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index e703ed8..e37e832 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -48,6 +48,8 @@ static jmethodID method_onDeviceRemoved;
static jmethodID method_onDeviceDisconnectRequested;
static jmethodID method_onCreatePairedDeviceResult;
+static jmethodID method_onCreateDeviceResult;
+static jmethodID method_onDiscoverServicesResult;
static jmethodID method_onGetDeviceServiceChannelResult;
static jmethodID method_onRequestPinCode;
@@ -92,6 +94,10 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
"(Ljava/lang/String;I)V");
+ method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
+ "(Ljava/lang/String;Z)V");
+ method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
+ "(Ljava/lang/String;Z)V");
method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
"(Ljava/lang/String;Ljava/lang/String;)Z");
@@ -1097,6 +1103,54 @@ done:
free(user);
}
+void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
+ LOGV(__FUNCTION__);
+
+ native_data_t *nat = (native_data_t *)n;
+ const char *address= (const char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env;
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+
+ LOGV("... Address = %s", address);
+
+ bool result = JNI_TRUE;
+ if (dbus_set_error_from_message(&err, msg)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ result = JNI_FALSE;
+ }
+ env->CallVoidMethod(nat->me,
+ method_onCreateDeviceResult,
+ env->NewStringUTF(address),
+ result);
+ free(user);
+}
+
+void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
+ LOGV(__FUNCTION__);
+
+ native_data_t *nat = (native_data_t *)n;
+ const char *path = (const char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env;
+ nat->vm->GetEnv((void**)&env, nat->envVer);
+
+ LOGV("... Device Path = %s", path);
+
+ bool result = JNI_TRUE;
+ if (dbus_set_error_from_message(&err, msg)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ result = JNI_FALSE;
+ }
+ env->CallVoidMethod(nat->me,
+ method_onDiscoverServicesResult,
+ env->NewStringUTF(path),
+ result);
+ free(user);
+}
+
void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
LOGV(__FUNCTION__);
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 0b71acb..c2f93eea 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -66,6 +66,8 @@ extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
DBusMessage *msg,
void *data);
void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
+void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
+void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
@@ -385,33 +387,24 @@ static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
LOGV(__FUNCTION__);
- jboolean result = JNI_FALSE;
#ifdef HAVE_BLUETOOTH
native_data_t *nat = get_native_data(env, object);
if (nat) {
const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
- DBusError err;
- dbus_error_init(&err);
- DBusMessage *reply =
- dbus_func_args_error(env, nat->conn, &err,
- get_adapter_path(env, object),
- DBUS_ADAPTER_IFACE, "RemoveDevice",
- DBUS_TYPE_OBJECT_PATH, &c_object_path,
- DBUS_TYPE_INVALID);
- if (!reply) {
- if (dbus_error_is_set(&err)) {
- LOG_AND_FREE_DBUS_ERROR(&err);
- } else
- LOGE("DBus reply is NULL in function %s", __FUNCTION__);
- result = JNI_FALSE;
- } else {
- result = JNI_TRUE;
- }
+ bool ret = dbus_func_args_async(env, nat->conn, -1,
+ NULL,
+ NULL,
+ NULL,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE,
+ "RemoveDevice",
+ DBUS_TYPE_OBJECT_PATH, &c_object_path,
+ DBUS_TYPE_INVALID);
env->ReleaseStringUTFChars(object_path, c_object_path);
- if (reply) dbus_message_unref(reply);
+ return ret ? JNI_TRUE : JNI_FALSE;
}
#endif
- return result;
+ return JNI_FALSE;
}
static jint enableNative(JNIEnv *env, jobject object) {
@@ -757,6 +750,75 @@ static jboolean setDevicePropertyBooleanNative(JNIEnv *env, jobject object,
#endif
}
+
+static jboolean createDeviceNative(JNIEnv *env, jobject object,
+ jstring address) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
+
+ if (nat && eventLoopNat) {
+ const char *c_address = env->GetStringUTFChars(address, NULL);
+ LOGV("... address = %s", c_address);
+ char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+ strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
+
+ bool ret = dbus_func_args_async(env, nat->conn, -1,
+ onCreateDeviceResult,
+ context_address,
+ eventLoopNat,
+ get_adapter_path(env, object),
+ DBUS_ADAPTER_IFACE,
+ "CreateDevice",
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(address, c_address);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+static jboolean discoverServicesNative(JNIEnv *env, jobject object,
+ jstring path, jstring pattern) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+ struct event_loop_native_data_t *eventLoopNat =
+ get_EventLoop_native_data(env, eventLoop);
+
+ if (nat && eventLoopNat) {
+ const char *c_path = env->GetStringUTFChars(path, NULL);
+ const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
+ int len = env->GetStringLength(path) + 1;
+ char *context_path = (char *)calloc(len, sizeof(char));
+ strlcpy(context_path, c_path, len); // for callback
+
+ LOGV("... Object Path = %s", c_path);
+ LOGV("... Pattern = %s, strlen = %d", c_pattern, strlen(c_pattern));
+
+ bool ret = dbus_func_args_async(env, nat->conn, -1,
+ onDiscoverServicesResult,
+ context_path,
+ eventLoopNat,
+ c_path,
+ DBUS_DEVICE_IFACE,
+ "DiscoverServices",
+ DBUS_TYPE_STRING, &c_pattern,
+ DBUS_TYPE_INVALID);
+ env->ReleaseStringUTFChars(path, c_path);
+ env->ReleaseStringUTFChars(pattern, c_pattern);
+ return ret ? JNI_TRUE : JNI_FALSE;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+
static JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"classInitNative", "()V", (void*)classInitNative},
@@ -797,6 +859,8 @@ static JNINativeMethod sMethods[] = {
(void *)cancelPairingUserInputNative},
{"setDevicePropertyBooleanNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
(void *)setDevicePropertyBooleanNative},
+ {"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative},
+ {"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative},
};
int register_android_server_BluetoothService(JNIEnv *env) {
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
index 9d1ef53..f1258e8 100644
--- a/core/res/res/anim/activity_close_enter.xml
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -21,5 +21,5 @@
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
<translate android:fromXDelta="-100%" android:toXDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
index 47cb6d6..bf3d8cd3 100644
--- a/core/res/res/anim/activity_close_exit.xml
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -20,5 +20,5 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
<translate android:fromXDelta="0%" android:toXDelta="33%"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
index e4c7e9b..a9ea381 100644
--- a/core/res/res/anim/activity_open_enter.xml
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -20,5 +20,5 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
<translate android:fromXDelta="33%" android:toXDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
index 9d47b7f..b04b79e 100644
--- a/core/res/res/anim/activity_open_exit.xml
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -21,5 +21,5 @@
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
<translate android:fromXDelta="0%" android:toXDelta="-100%"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/dialog_enter.xml b/core/res/res/anim/dialog_enter.xml
index 167f4bc..d4983c6 100644
--- a/core/res/res/anim/dialog_enter.xml
+++ b/core/res/res/anim/dialog_enter.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* //device/apps/common/res/anim/fade_in.xml
-**
+/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +21,7 @@
android:interpolator="@anim/decelerate_interpolator">
<scale android:fromXScale="0.9" android:toXScale="1.0"
android:fromYScale="0.9" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
+ android:pivotX="50%" android:pivotY="50%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="@android:integer/config_shortAnimTime" />
diff --git a/core/res/res/anim/dialog_exit.xml b/core/res/res/anim/dialog_exit.xml
index d412cfb..2aa629a 100644
--- a/core/res/res/anim/dialog_exit.xml
+++ b/core/res/res/anim/dialog_exit.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* //device/apps/common/res/anim/fade_out.xml
-**
+/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,11 +16,12 @@
** limitations under the License.
*/
-->
+
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/accelerate_interpolator">
<scale android:fromXScale="1.0" android:toXScale="0.9"
android:fromYScale="1.0" android:toYScale="0.9"
- android:pivotX="50%p" android:pivotY="50%p"
+ android:pivotX="50%" android:pivotY="50%"
android:duration="@android:integer/config_shortAnimTime" />
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="@android:integer/config_shortAnimTime"/>
diff --git a/core/res/res/anim/recent_enter.xml b/core/res/res/anim/recent_enter.xml
index deeb96b..8faa2c1 100644
--- a/core/res/res/anim/recent_enter.xml
+++ b/core/res/res/anim/recent_enter.xml
@@ -19,10 +19,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
- <scale android:fromXScale="2.0" android:toXScale="1.0"
- android:fromYScale="2.0" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
- android:duration="@android:integer/config_mediumAnimTime" />
+ <scale android:fromXScale="0.9" android:toXScale="1.0"
+ android:fromYScale="0.9" android:toYScale="1.0"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime" />
</set>
diff --git a/core/res/res/anim/recent_exit.xml b/core/res/res/anim/recent_exit.xml
index fed7014..9399329 100644
--- a/core/res/res/anim/recent_exit.xml
+++ b/core/res/res/anim/recent_exit.xml
@@ -18,12 +18,11 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@anim/decelerate_interpolator"
- android:zAdjustment="top">
- <scale android:fromXScale="1.0" android:toXScale="2.0"
- android:fromYScale="1.0" android:toYScale="2.0"
- android:pivotX="50%p" android:pivotY="50%p"
- android:duration="@android:integer/config_mediumAnimTime" />
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:interpolator="@anim/accelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale="0.9"
+ android:fromYScale="1.0" android:toYScale="0.9"
+ android:pivotX="50%" android:pivotY="50%"
+ android:duration="@android:integer/config_shortAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 98975fb..db331b1 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -18,8 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@anim/decelerate_interpolator"
- android:zAdjustment="top">
+ android:interpolator="@anim/decelerate_interpolator">
<scale android:fromXScale="1.0" android:toXScale="2.0"
android:fromYScale="1.0" android:toYScale="2.0"
android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/anim/translucent_enter.xml b/core/res/res/anim/translucent_enter.xml
index fb4c1c3..04852a8 100644
--- a/core/res/res/anim/translucent_enter.xml
+++ b/core/res/res/anim/translucent_enter.xml
@@ -20,7 +20,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
<translate android:fromXDelta="75%" android:toXDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/translucent_exit.xml b/core/res/res/anim/translucent_exit.xml
index 1d424e1..adaf3d1 100644
--- a/core/res/res/anim/translucent_exit.xml
+++ b/core/res/res/anim/translucent_exit.xml
@@ -20,7 +20,7 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/accelerate_interpolator">
<translate android:fromXDelta="0%" android:toXDelta="75%"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:duration="@android:integer/config_mediumAnimTime"/>
+ android:duration="@android:integer/config_shortAnimTime"/>
</set>
diff --git a/core/res/res/anim/wallpaper_close_enter.xml b/core/res/res/anim/wallpaper_close_enter.xml
index e4c7e9b..0d13009 100644
--- a/core/res/res/anim/wallpaper_close_enter.xml
+++ b/core/res/res/anim/wallpaper_close_enter.xml
@@ -17,8 +17,22 @@
*/
-->
+<!-- This version zooms the new non-wallpaper down on top of the
+ wallpaper. -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <scale android:fromXScale="2.0" android:toXScale="1.0"
+ android:fromYScale="2.0" android:toYScale="1.0"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
+
+<!-- This version is a variation on the inter-activity slide that
+ also scales the wallpaper. -->
+<!--
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
<translate android:fromXDelta="33%" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
+-->
diff --git a/core/res/res/anim/wallpaper_close_exit.xml b/core/res/res/anim/wallpaper_close_exit.xml
index 16edec1..5d91e30 100644
--- a/core/res/res/anim/wallpaper_close_exit.xml
+++ b/core/res/res/anim/wallpaper_close_exit.xml
@@ -17,6 +17,22 @@
*/
-->
+<!-- This version zooms the new non-wallpaper down on top of the
+ wallpaper. The wallpaper here just stays fixed behind. -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator"
+ android:zAdjustment="top">
+ <scale android:fromXScale="1.0" android:toXScale=".5"
+ android:fromYScale="1.0" android:toYScale=".5"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
+
+<!-- This version is a variation on the inter-activity slide that
+ also scales the wallpaper. -->
+<!--
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
@@ -27,3 +43,4 @@
<translate android:fromXDelta="0%" android:toXDelta="-100%"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
+-->
diff --git a/core/res/res/anim/wallpaper_open_enter.xml b/core/res/res/anim/wallpaper_open_enter.xml
index af22b47..cf27cf0 100644
--- a/core/res/res/anim/wallpaper_open_enter.xml
+++ b/core/res/res/anim/wallpaper_open_enter.xml
@@ -17,6 +17,22 @@
*/
-->
+<!-- This version zooms the new non-wallpaper up off the wallpaper the
+ wallpaper. The wallpaper here just stays fixed behind. -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator"
+ android:zAdjustment="top">
+ <scale android:fromXScale=".5" android:toXScale="1.0"
+ android:fromYScale=".5" android:toYScale="1.0"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
+
+<!-- This version is a variation on the inter-activity slide that
+ also scales the wallpaper. -->
+<!--
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator"
android:zAdjustment="top">
@@ -27,3 +43,4 @@
<translate android:fromXDelta="-100%" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
+-->
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 47cb6d6..b7a539c 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -17,8 +17,22 @@
*/
-->
+<!-- This version zooms the new non-wallpaper down on top of the
+ wallpaper. -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/decelerate_interpolator">
+ <scale android:fromXScale="1.0" android:toXScale="2.0"
+ android:fromYScale="1.0" android:toYScale="2.0"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
+
+<!-- This version is a variation on the inter-activity slide that
+ also scales the wallpaper. -->
+<!--
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/decelerate_interpolator">
<translate android:fromXDelta="0%" android:toXDelta="33%"
android:duration="@android:integer/config_mediumAnimTime"/>
</set>
+-->
diff --git a/core/res/res/drawable-hdpi/dark_header.9.png b/core/res/res/drawable-hdpi/dark_header.9.png
index a2fa569..3e63fa6 100644
--- a/core/res/res/drawable-hdpi/dark_header.9.png
+++ b/core/res/res/drawable-hdpi/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
index c7803a2..99a67b9 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
index d8d8aa9..cfe258b 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
index 63859f7..30a68d0 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
index ced2832..8f35315 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_vertical_bright.9.png b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
index 1035656..99a67b9 100644
--- a/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
+++ b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_bright_opaque.9.png b/core/res/res/drawable-hdpi/divider_vertical_bright_opaque.9.png
index 5c537ee..5c537ee 100644
--- a/core/res/res/drawable/divider_vertical_bright_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_vertical_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_vertical_dark.9.png b/core/res/res/drawable-hdpi/divider_vertical_dark.9.png
new file mode 100644
index 0000000..30a68d0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_vertical_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark_opaque.9.png b/core/res/res/drawable-hdpi/divider_vertical_dark_opaque.9.png
index 8f35315..8f35315 100644
--- a/core/res/res/drawable/divider_vertical_dark_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_vertical_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge.9.png b/core/res/res/drawable-hdpi/fasttrack_badge.9.png
new file mode 100644
index 0000000..1eeabf4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge_pressed.9.png b/core/res/res/drawable-hdpi/fasttrack_badge_pressed.9.png
new file mode 100644
index 0000000..0cfd09d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge_small.9.png b/core/res/res/drawable-hdpi/fasttrack_badge_small.9.png
new file mode 100644
index 0000000..7140957
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge_small.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge_small_pressed.9.png b/core/res/res/drawable-hdpi/fasttrack_badge_small_pressed.9.png
new file mode 100644
index 0000000..ee030fb
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_aggregated.png b/core/res/res/drawable-hdpi/ic_aggregated.png
new file mode 100644
index 0000000..7ca15b1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_aggregated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_ringer_off.png b/core/res/res/drawable-hdpi/ic_lock_ringer_off.png
new file mode 100644
index 0000000..e7cb234
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_ringer_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_ringer_on.png b/core/res/res/drawable-hdpi/ic_lock_ringer_on.png
new file mode 100644
index 0000000..ce0cfab
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_ringer_on.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/light_header.9.png b/core/res/res/drawable-hdpi/light_header.9.png
index 27db59d..6fc53ca 100644
--- a/core/res/res/drawable-hdpi/light_header.9.png
+++ b/core/res/res/drawable-hdpi/light_header.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dark_header.9.png b/core/res/res/drawable-mdpi/dark_header.9.png
index 7242b61..f4a14f1 100644
--- a/core/res/res/drawable-mdpi/dark_header.9.png
+++ b/core/res/res/drawable-mdpi/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/divider_vertical_bright_opaque.9.png b/core/res/res/drawable-mdpi/divider_vertical_bright_opaque.9.png
new file mode 100644
index 0000000..5c537ee
--- /dev/null
+++ b/core/res/res/drawable-mdpi/divider_vertical_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark.9.png b/core/res/res/drawable-mdpi/divider_vertical_dark.9.png
index 548d0bd..548d0bd 100644
--- a/core/res/res/drawable/divider_vertical_dark.9.png
+++ b/core/res/res/drawable-mdpi/divider_vertical_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/divider_vertical_dark_opaque.9.png b/core/res/res/drawable-mdpi/divider_vertical_dark_opaque.9.png
new file mode 100644
index 0000000..8f35315
--- /dev/null
+++ b/core/res/res/drawable-mdpi/divider_vertical_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fasttrack_badge.9.png b/core/res/res/drawable-mdpi/fasttrack_badge.9.png
new file mode 100644
index 0000000..d8dff34
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fasttrack_badge_pressed.9.png b/core/res/res/drawable-mdpi/fasttrack_badge_pressed.9.png
new file mode 100644
index 0000000..c8ca33a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fasttrack_badge_small.9.png b/core/res/res/drawable-mdpi/fasttrack_badge_small.9.png
new file mode 100644
index 0000000..38f14f7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge_small.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fasttrack_badge_small_pressed.9.png b/core/res/res/drawable-mdpi/fasttrack_badge_small_pressed.9.png
new file mode 100644
index 0000000..b23e921
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_aggregated.png b/core/res/res/drawable-mdpi/ic_aggregated.png
new file mode 100644
index 0000000..7c2e2b0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_aggregated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_ringer_off.png b/core/res/res/drawable-mdpi/ic_lock_ringer_off.png
new file mode 100644
index 0000000..98cfb11
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_ringer_off.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_ringer_on.png b/core/res/res/drawable-mdpi/ic_lock_ringer_on.png
new file mode 100644
index 0000000..691b99e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_ringer_on.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark.xml b/core/res/res/drawable/fasttrack_badge.xml
index c60d403..89c63a1 100644
--- a/core/res/res/drawable/fasttrack_badge_dark.xml
+++ b/core/res/res/drawable/fasttrack_badge.xml
@@ -19,10 +19,10 @@
android:state_focused="false"
android:state_selected="false"
android:state_pressed="false"
- android:drawable="@drawable/fasttrack_badge_dark_normal" />
+ android:drawable="@drawable/fasttrack_badge" />
<item
android:state_pressed="true"
- android:drawable="@drawable/fasttrack_badge_dark_pressed" />
+ android:drawable="@drawable/fasttrack_badge_pressed" />
</selector>
diff --git a/core/res/res/drawable/fasttrack_badge_dark_normal.9.png b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
deleted file mode 100644
index 52bb08c..0000000
--- a/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
deleted file mode 100644
index 84a6783..0000000
--- a/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light_normal.9.png b/core/res/res/drawable/fasttrack_badge_light_normal.9.png
deleted file mode 100644
index 595b179..0000000
--- a/core/res/res/drawable/fasttrack_badge_light_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light_pressed.9.png b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
deleted file mode 100644
index 8e3f557..0000000
--- a/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle_large.xml b/core/res/res/drawable/fasttrack_badge_middle_large.xml
deleted file mode 100644
index dd591bd..0000000
--- a/core/res/res/drawable/fasttrack_badge_middle_large.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_focused="false"
- android:state_selected="false"
- android:state_pressed="false"
- android:drawable="@drawable/fasttrack_badge_middle_large_normal" />
-
- <item
- android:state_pressed="true"
- android:drawable="@drawable/fasttrack_badge_middle_large_pressed" />
-
-</selector> \ No newline at end of file
diff --git a/core/res/res/drawable/fasttrack_badge_middle_large_normal.9.png b/core/res/res/drawable/fasttrack_badge_middle_large_normal.9.png
deleted file mode 100644
index ca275cd..0000000
--- a/core/res/res/drawable/fasttrack_badge_middle_large_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle_large_pressed.9.png b/core/res/res/drawable/fasttrack_badge_middle_large_pressed.9.png
deleted file mode 100644
index b69ccbd..0000000
--- a/core/res/res/drawable/fasttrack_badge_middle_large_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light.xml b/core/res/res/drawable/fasttrack_badge_small.xml
index fd81258..269e936 100644
--- a/core/res/res/drawable/fasttrack_badge_light.xml
+++ b/core/res/res/drawable/fasttrack_badge_small.xml
@@ -19,10 +19,10 @@
android:state_focused="false"
android:state_selected="false"
android:state_pressed="false"
- android:drawable="@drawable/fasttrack_badge_light_normal" />
+ android:drawable="@drawable/fasttrack_badge_small" />
<item
android:state_pressed="true"
- android:drawable="@drawable/fasttrack_badge_light_pressed" />
+ android:drawable="@drawable/fasttrack_badge_small_pressed" />
</selector>
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index e800dfa..d19bb04 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -38,8 +38,24 @@
android:layout_marginTop="5dip"
android:orientation="vertical">
- <!-- "Name" field is locale-specific. -->
- <include layout="@layout/contact_header_name"/>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/aggregate_badge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="3dip"
+ android:paddingTop="3dip"
+ android:src="@drawable/ic_aggregated"
+ />
+
+ <!-- "Name" field is locale-specific. -->
+ <include layout="@layout/contact_header_name"/>
+
+ </LinearLayout>
<TextView android:id="@+id/status"
android:layout_width="fill_parent"
diff --git a/core/res/res/layout/keyguard_screen_rotary_unlock.xml b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
index cf97d04..9f18124 100644
--- a/core/res/res/layout/keyguard_screen_rotary_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
@@ -83,6 +83,7 @@
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
+ android:drawablePadding="4dip"
/>
<TextView
@@ -94,6 +95,7 @@
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
+ android:drawablePadding="4dip"
/>
<TextView
@@ -108,15 +110,15 @@
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.-->
+ <!-- By having the rotary selector hang from the top, we get a layout more
+ robust for different screen sizes. On hvga, 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"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="286dip"
/>
<!-- emergency call button shown when sim is missing or PUKd -->
diff --git a/core/res/res/layout/tab_indicator.xml b/core/res/res/layout/tab_indicator.xml
index e3ea555..71e4001 100644
--- a/core/res/res/layout/tab_indicator.xml
+++ b/core/res/res/layout/tab_indicator.xml
@@ -18,8 +18,8 @@
android:layout_width="0dip"
android:layout_height="64dip"
android:layout_weight="1"
- android:layout_marginLeft="-4px"
- android:layout_marginRight="-4px"
+ android:layout_marginLeft="-3dip"
+ android:layout_marginRight="-3dip"
android:orientation="vertical"
android:background="@android:drawable/tab_indicator">
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index eae838a..a0d046f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -102,9 +102,9 @@
<!-- Text color, typeface, size, and style for "small" inverse text. Defaults to secondary inverse text color. -->
<attr name="textAppearanceSmallInverse" format="reference" />
- <!-- Text color, typeface, size, and style for system search result title. Defaults to primary inverse text color. @hide -->
+ <!-- Text color, typeface, size, and style for system search result title. Defaults to primary inverse text color. -->
<attr name="textAppearanceSearchResultTitle" format="reference" />
- <!-- Text color, typeface, size, and style for system search result subtitle. Defaults to primary inverse text color. @hide -->
+ <!-- Text color, typeface, size, and style for system search result subtitle. Defaults to primary inverse text color. -->
<attr name="textAppearanceSearchResultSubtitle" format="reference" />
@@ -396,14 +396,20 @@
<attr name="spinnerItemStyle" format="reference" />
<!-- Default MapView style. -->
<attr name="mapViewStyle" format="reference" />
- <!-- Dark Fasttrack badge style. -->
+ <!-- Default Fasttrack badge style. -->
<attr name="fasttrackBadgeWidgetStyle" format="reference" />
- <!-- Dark Fasttrack badge style with small fasttrack window. -->
+ <!-- Default Fasttrack badge style with small fasttrack window. -->
<attr name="fasttrackBadgeWidgetStyleWindowSmall" format="reference" />
- <!-- Dark Fasttrack badge style with medium fasttrack window. -->
+ <!-- Default Fasttrack badge style with medium fasttrack window. -->
<attr name="fasttrackBadgeWidgetStyleWindowMedium" format="reference" />
- <!-- Dark Fasttrack badge style with large fasttrack window. -->
+ <!-- Default Fasttrack badge style with large fasttrack window. -->
<attr name="fasttrackBadgeWidgetStyleWindowLarge" format="reference" />
+ <!-- Default Fasttrack badge style with small fasttrack window. -->
+ <attr name="fasttrackBadgeWidgetStyleSmallWindowSmall" format="reference" />
+ <!-- Default Fasttrack badge style with medium fasttrack window. -->
+ <attr name="fasttrackBadgeWidgetStyleSmallWindowMedium" format="reference" />
+ <!-- Default Fasttrack badge style with large fasttrack window. -->
+ <attr name="fasttrackBadgeWidgetStyleSmallWindowLarge" format="reference" />
<!-- =================== -->
<!-- Preference styles -->
@@ -3486,13 +3492,29 @@
<!-- Contacts meta-data attributes -->
<!-- =============================== -->
+ <!-- TODO: remove this deprecated styleable -->
<declare-styleable name="Icon">
<attr name="icon" />
<attr name="mimeType" />
</declare-styleable>
+ <!-- TODO: remove this deprecated styleable -->
<declare-styleable name="IconDefault">
<attr name="icon" />
</declare-styleable>
+ <!-- Maps a specific contact data MIME-type to styling information -->
+ <declare-styleable name="ContactsDataKind">
+ <!-- Mime-type handled by this mapping -->
+ <attr name="mimeType" />
+ <!-- Icon used to represent data of this kind -->
+ <attr name="icon" />
+ <!-- Column in data table that summarizes this data -->
+ <attr name="summaryColumn" format="string" />
+ <!-- Column in data table that contains details for this data -->
+ <attr name="detailColumn" format="string" />
+ <!-- Flag indicating that detail should be built from SocialProvider -->
+ <attr name="detailSocialSummary" format="boolean" />
+ </declare-styleable>
+
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index c967c4c..15841a8 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -19,7 +19,7 @@
-->
<resources>
<drawable name="screen_background_light">#ffffffff</drawable>
- <drawable name="screen_background_dark">#ff202020</drawable>
+ <drawable name="screen_background_dark">#ff000000</drawable>
<drawable name="status_bar_closed_default_background">#ff000000</drawable>
<drawable name="status_bar_opened_default_background">#ff000000</drawable>
<drawable name="search_bar_default_color">#ff000000</drawable>
@@ -36,7 +36,7 @@
<color name="white">#ffffffff</color>
<color name="black">#ff000000</color>
<color name="transparent">#00000000</color>
- <color name="background_dark">#ff202020</color>
+ <color name="background_dark">#ff000000</color>
<color name="bright_foreground_dark">#ffffffff</color>
<color name="bright_foreground_dark_disabled">#80ffffff</color>
<color name="bright_foreground_dark_inverse">#ff000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b710acb..7aeaec4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -27,13 +27,13 @@
<bool name="config_sf_limitedAlpha">false</bool>
<!-- The duration (in milliseconds) of a short animation. -->
- <integer name="config_shortAnimTime">100</integer>
+ <integer name="config_shortAnimTime">150</integer>
<!-- The duration (in milliseconds) of a medium-length animation. -->
- <integer name="config_mediumAnimTime">150</integer>
+ <integer name="config_mediumAnimTime">250</integer>
<!-- The duration (in milliseconds) of a long animation. -->
- <integer name="config_longAnimTime">300</integer>
+ <integer name="config_longAnimTime">400</integer>
<!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION.
Please don't copy them, copy anything else. -->
@@ -78,6 +78,20 @@
A value of -1 means no change in orientation by default. -->
<integer name="config_carDockRotation">-1</integer>
+ <!-- Control whether being in the desk dock (and powered) always
+ keeps the screen on. By default it doesn't. Set to true to make it. -->
+ <bool name="config_deskDockKeepsScreenOn">false</bool>
+
+ <!-- Control whether being in the car dock (and powered) always
+ keeps the screen on. By default it does. Set to false to not keep on. -->
+ <bool name="config_carDockKeepsScreenOn">true</bool>
+
+ <!-- Control whether being in the desk dock should enable accelerometer based screen orientation -->
+ <bool name="config_deskDockEnablesAccelerometer">false</bool>
+
+ <!-- Control whether being in the car dock should enable accelerometer based screen orientation -->
+ <bool name="config_carDockEnablesAccelerometer">false</bool>
+
<!-- Indicate whether the lid state impacts the accessibility of
the physical keyboard. 0 means it doesn't, 1 means it is accessible
when the lid is open, 2 means it is accessible when the lid is
@@ -105,5 +119,7 @@
<item>20</item>
<item>30</item>
</integer-array>
-
+
+ <bool name="config_use_strict_phone_number_comparation">false</bool>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2bc2a0f..b08a58a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1164,12 +1164,19 @@
<public type="attr" name="restoreNeedsApplication" />
<public type="attr" name="smallIcon" />
<public type="attr" name="accountPreferences" />
+ <public type="attr" name="textAppearanceSearchResultSubtitle" />
+ <public type="attr" name="textAppearanceSearchResultTitle" />
+ <public type="attr" name="summaryColumn" />
+ <public type="attr" name="detailColumn" />
+ <public type="attr" name="detailSocialSummary" />
<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" />
+ <public type="style" name="TextAppearance.SearchResult.Title" />
+ <public type="style" name="TextAppearance.SearchResult.Subtitle" />
<!-- Semi-transparent background that can be used when placing a dark
themed UI on top of some arbitrary background (such as the
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bd79c75..e2f6981 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1200,6 +1200,106 @@
<item>Jabber</item>
</string-array>
+ <!-- Custom phone number type -->
+ <string name="phoneTypeCustom">Custom</string>
+ <!-- Home phone number type -->
+ <string name="phoneTypeHome">Home</string>
+ <!-- Mobile phone number type -->
+ <string name="phoneTypeMobile">Mobile</string>
+ <!-- Work phone number type -->
+ <string name="phoneTypeWork">Work</string>
+ <!-- Work fax phone number type -->
+ <string name="phoneTypeFaxWork">Work Fax</string>
+ <!-- Home fax phone number type -->
+ <string name="phoneTypeFaxHome">Home Fax</string>
+ <!-- Pager phone number type -->
+ <string name="phoneTypePager">Pager</string>
+ <!-- Other phone number type -->
+ <string name="phoneTypeOther">Other</string>
+ <!-- Callback phone number type -->
+ <string name="phoneTypeCallback">Callback</string>
+ <!-- Car phone number type -->
+ <string name="phoneTypeCar">Car</string>
+ <!-- Company main phone number type -->
+ <string name="phoneTypeCompanyMain">Company Main</string>
+ <!-- ISDN phone number type -->
+ <string name="phoneTypeIsdn">ISDN</string>
+ <!-- Main phone number type -->
+ <string name="phoneTypeMain">Main</string>
+ <!-- Other fax phone number type -->
+ <string name="phoneTypeOtherFax">Other Fax</string>
+ <!-- Radio phone number type -->
+ <string name="phoneTypeRadio">Radio</string>
+ <!-- Telex phone number type -->
+ <string name="phoneTypeTelex">Telex</string>
+ <!-- TTY TDD phone number type -->
+ <string name="phoneTypeTtyTdd">TTY TDD</string>
+ <!-- Work mobile phone number type -->
+ <string name="phoneTypeWorkMobile">Work Mobile</string>
+ <!-- Work pager phone number type -->
+ <string name="phoneTypeWorkPager">Work Pager</string>
+ <!-- Assistant phone number type -->
+ <string name="phoneTypeAssistant">Assistant</string>
+ <!-- MMS phone number type -->
+ <string name="phoneTypeMms">MMS</string>
+
+ <!-- Custom email type -->
+ <string name="emailTypeCustom">Custom</string>
+ <!-- Home email type -->
+ <string name="emailTypeHome">Home</string>
+ <!-- Work email type -->
+ <string name="emailTypeWork">Work</string>
+ <!-- Other email type -->
+ <string name="emailTypeOther">Other</string>
+ <!-- Mobile email type -->
+ <string name="emailTypeMobile">Mobile</string>
+
+ <!-- Custom postal address type -->
+ <string name="postalTypeCustom">Custom</string>
+ <!-- Home postal address type -->
+ <string name="postalTypeHome">Home</string>
+ <!-- Work postal address type -->
+ <string name="postalTypeWork">Work</string>
+ <!-- Other postal address type -->
+ <string name="postalTypeOther">Other</string>
+
+ <!-- Custom IM address type -->
+ <string name="imTypeCustom">Custom</string>
+ <!-- Home IM address type -->
+ <string name="imTypeHome">Home</string>
+ <!-- Work IM address type -->
+ <string name="imTypeWork">Work</string>
+ <!-- Other IM address type -->
+ <string name="imTypeOther">Other</string>
+
+ <!-- Custom IM address type -->
+ <string name="imProtocolCustom">Custom</string>
+ <!-- AIM IM protocol type -->
+ <string name="imProtocolAim">AIM</string>
+ <!-- MSN IM protocol type -->
+ <string name="imProtocolMsn">Windows Live</string>
+ <!-- Yahoo IM protocol type -->
+ <string name="imProtocolYahoo">Yahoo</string>
+ <!-- Skype IM protocol type -->
+ <string name="imProtocolSkype">Skype</string>
+ <!-- QQ IM protocol type -->
+ <string name="imProtocolQq">QQ</string>
+ <!-- Google Talk IM protocol type -->
+ <string name="imProtocolGoogleTalk">Google Talk</string>
+ <!-- ICQ IM protocol type -->
+ <string name="imProtocolIcq">ICQ</string>
+ <!-- Jabber IM protocol type -->
+ <string name="imProtocolJabber">Jabber</string>
+ <!-- NetMeeting IM protocol type -->
+ <string name="imProtocolNetMeeting">NetMeeting</string>
+
+ <!-- Work organization type -->
+ <string name="orgTypeWork">Work</string>
+ <!-- Other organization type -->
+ <string name="orgTypeOther">Other</string>
+ <!-- Custom organization type -->
+ <string name="orgTypeCustom">Custom</string>
+
<!-- Instructions telling the user to enter their pin to unlock the keyguard.
Displayed in one line in a large font. -->
<string name="keyguard_password_enter_pin_code">Enter PIN code</string>
@@ -1391,6 +1491,9 @@
<!-- Title of the WebView save password dialog. If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
<string name="save_password_label">Confirm</string>
+ <!-- Toast for double-tap -->
+ <string name="double_tap_toast">Tip: double-tap to zoom in and out.</string>
+
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 35db8ee..e78c213 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -58,6 +58,19 @@
<item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
<item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
<item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
+ <item name="taskOpenEnterAnimation">@anim/activity_open_enter</item>
+ <item name="taskOpenExitAnimation">@anim/activity_open_exit</item>
+ <item name="taskCloseEnterAnimation">@anim/activity_close_enter</item>
+ <item name="taskCloseExitAnimation">@anim/activity_close_exit</item>
+ <item name="taskToFrontEnterAnimation">@anim/activity_open_enter</item>
+ <item name="taskToFrontExitAnimation">@anim/activity_open_exit</item>
+ <item name="taskToBackEnterAnimation">@anim/activity_close_enter</item>
+ <item name="taskToBackExitAnimation">@anim/activity_close_exit</item>
+ <!-- There is a good argument to be made that the user shouldn't
+ be aware of task transitions, so we are going to use the same
+ animation for them as we do for regular activity transitions. -->
+ <!-- These provide an alternative animation for task transitions. -->
+ <!--
<item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
<item name="taskOpenExitAnimation">@anim/task_open_exit</item>
<item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
@@ -66,6 +79,7 @@
<item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
<item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
<item name="taskToBackExitAnimation">@anim/task_close_exit</item>
+ -->
<item name="wallpaperOpenEnterAnimation">@anim/wallpaper_open_enter</item>
<item name="wallpaperOpenExitAnimation">@anim/wallpaper_open_exit</item>
<item name="wallpaperCloseEnterAnimation">@anim/wallpaper_close_enter</item>
@@ -524,9 +538,17 @@
</style>
<style name="Widget.FasttrackBadgeWidget">
- <item name="android:layout_width">48dip</item>
- <item name="android:layout_height">52dip</item>
- <item name="android:background">@android:drawable/fasttrack_badge_dark</item>
+ <item name="android:layout_width">50dip</item>
+ <item name="android:layout_height">56dip</item>
+ <item name="android:background">@android:drawable/fasttrack_badge</item>
+ <item name="android:clickable">true</item>
+ <item name="android:scaleType">fitCenter</item>
+ </style>
+
+ <style name="Widget.FasttrackBadgeWidgetSmall">
+ <item name="android:layout_width">39dip</item>
+ <item name="android:layout_height">42dip</item>
+ <item name="android:background">@android:drawable/fasttrack_badge_small</item>
<item name="android:clickable">true</item>
<item name="android:scaleType">fitCenter</item>
</style>
@@ -542,6 +564,18 @@
<style name="Widget.FasttrackBadgeWidget.WindowLarge">
<item name="android:fasttrackWindowSize">modeLarge</item>
</style>
+
+ <style name="Widget.FasttrackBadgeWidgetSmall.WindowSmall">
+ <item name="android:fasttrackWindowSize">modeSmall</item>
+ </style>
+
+ <style name="Widget.FasttrackBadgeWidgetSmall.WindowMedium">
+ <item name="android:fasttrackWindowSize">modeMedium</item>
+ </style>
+
+ <style name="Widget.FasttrackBadgeWidgetSmall.WindowLarge">
+ <item name="android:fasttrackWindowSize">modeLarge</item>
+ </style>
<!-- Text Appearances -->
<eat-comment />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 04402fd..c0ca21b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -59,11 +59,7 @@
<item name="textAppearanceLargeInverse">@android:style/TextAppearance.Large.Inverse</item>
<item name="textAppearanceMediumInverse">@android:style/TextAppearance.Medium.Inverse</item>
<item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
-
- <!-- @hide -->
<item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.SearchResult.Title</item>
-
- <!-- @hide -->
<item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.SearchResult.Subtitle</item>
<item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
@@ -179,6 +175,9 @@
<item name="fasttrackBadgeWidgetStyleWindowSmall">@android:style/Widget.FasttrackBadgeWidget.WindowSmall</item>
<item name="fasttrackBadgeWidgetStyleWindowMedium">@android:style/Widget.FasttrackBadgeWidget.WindowMedium</item>
<item name="fasttrackBadgeWidgetStyleWindowLarge">@android:style/Widget.FasttrackBadgeWidget.WindowLarge</item>
+ <item name="fasttrackBadgeWidgetStyleSmallWindowSmall">@android:style/Widget.FasttrackBadgeWidgetSmall.WindowSmall</item>
+ <item name="fasttrackBadgeWidgetStyleSmallWindowMedium">@android:style/Widget.FasttrackBadgeWidgetSmall.WindowMedium</item>
+ <item name="fasttrackBadgeWidgetStyleSmallWindowLarge">@android:style/Widget.FasttrackBadgeWidgetSmall.WindowLarge</item>
<!-- Preference styles -->
<item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
@@ -358,7 +357,7 @@
<style name="Theme.NoDisplay">
<item name="android:windowBackground">@null</item>
<item name="android:windowContentOverlay">@null</item>
- <item name="android:windowIsTranslucent">false</item>
+ <item name="android:windowIsTranslucent">true</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:windowDisablePreview">true</item>
<item name="android:windowNoDisplay">true</item>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 859902e..710b71e 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -26,15 +26,24 @@
<item name="wifi.on">0.1</item>
<item name="wifi.active">0.1</item>
<item name="wifi.scan">0.1</item>
- <item name="cpu.idle">0.1</item>
- <item name="cpu.normal">0.2</item>
- <item name="cpu.full">1</item>
<item name="dsp.audio">0.1</item>
<item name="dsp.video">0.1</item>
<item name="radio.active">1</item>
<item name="gps.on">1</item>
+ <!-- Current consumed by the radio at different signal strengths, when paging -->
<array name="radio.on"> <!-- Strength 0 to BINS-1 -->
<value>1</value>
<value>0.1</value>
</array>
+ <!-- Different CPU speeds as reported in
+ /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state -->
+ <array name="cpu.speeds">
+ <value>400000</value> <!-- 400 MHz CPU speed -->
+ </array>
+ <!-- Power consumption when CPU is idle -->
+ <item name="cpu.idle">0.1</item>
+ <!-- Power consumption at different speeds -->
+ <array name="cpu.active">
+ <value>0.2</value>
+ </array>
</device>