Merge change 23870 into eclair
* changes:
Allow hasIccCard to be useable by any processes.
diff --git a/api/current.xml b/api/current.xml
index b052a61..7bb99e4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -17373,6 +17373,21 @@
visibility="public"
>
</method>
+<method name="getRunningServiceControlPanel"
+ return="android.app.PendingIntent"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="service" type="android.content.ComponentName">
+</parameter>
+<exception name="SecurityException" type="java.lang.SecurityException">
+</exception>
+</method>
<method name="getRunningServices"
return="java.util.List<android.app.ActivityManager.RunningServiceInfo>"
abstract="false"
@@ -17942,6 +17957,39 @@
visibility="public"
>
</field>
+<field name="REASON_PROVIDER_IN_USE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="REASON_SERVICE_IN_USE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="REASON_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="importance"
type="int"
transient="false"
@@ -17952,6 +18000,36 @@
visibility="public"
>
</field>
+<field name="importanceReasonCode"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="importanceReasonComponent"
+ type="android.content.ComponentName"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="importanceReasonPid"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="lru"
type="int"
transient="false"
@@ -18125,6 +18203,26 @@
visibility="public"
>
</field>
+<field name="clientLabel"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="clientPackage"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="crashCount"
type="int"
transient="false"
@@ -112103,6 +112201,17 @@
visibility="public"
>
</constructor>
+<field name="ACTION_ACCESSIBILITY_SETTINGS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.settings.ACCESSIBILITY_SETTINGS""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_AIRPLANE_MODE_SETTINGS"
type="java.lang.String"
transient="false"
diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk
new file mode 100644
index 0000000..631c219
--- /dev/null
+++ b/cmds/bugreport/Android.mk
@@ -0,0 +1,14 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= bugreport.c
+
+LOCAL_MODULE:= bugreport
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/cmds/bugreport/bugreport.c b/cmds/bugreport/bugreport.c
new file mode 100644
index 0000000..4a0b511
--- /dev/null
+++ b/cmds/bugreport/bugreport.c
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+
+int main(int argc, char *argv[]) {
+ char buffer[65536];
+ int i, s;
+
+ /* start the dumpstate service */
+ property_set("ctl.start", "dumpstate");
+
+ /* socket will not be available until service starts */
+ for (i = 0; i < 10; i++) {
+ s = socket_local_client("dumpstate",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (s >= 0)
+ break;
+ /* try again in 1 second */
+ sleep(1);
+ }
+
+ if (s < 0) {
+ fprintf(stderr, "Failed to connect to dumpstate service\n");
+ exit(1);
+ }
+
+ while (1) {
+ int length = read(s, buffer, sizeof(buffer));
+ if (length <= 0)
+ break;
+ fwrite(buffer, 1, length, stdout);
+ }
+
+ close(s);
+ return 0;
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index f61d7ec..f8b37a8 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -11,7 +11,7 @@
include $(BUILD_EXECUTABLE)
-COMMANDS = dumpcrash bugreport
+COMMANDS = dumpcrash
SYMLINKS := $(addprefix $(TARGET_OUT_EXECUTABLES)/,$(COMMANDS))
$(SYMLINKS): DUMPSTATE_BINARY := dumpstate
$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ad06fa9..af73112 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -366,6 +366,19 @@
*/
public int flags;
+ /**
+ * For special services that are bound to by system code, this is
+ * the package that holds the binding.
+ */
+ public String clientPackage;
+
+ /**
+ * For special services that are bound to by system code, this is
+ * a string resource providing a user-visible label for who the
+ * client is.
+ */
+ public int clientLabel;
+
public RunningServiceInfo() {
}
@@ -386,6 +399,8 @@
dest.writeLong(lastActivityTime);
dest.writeLong(restarting);
dest.writeInt(this.flags);
+ dest.writeString(clientPackage);
+ dest.writeInt(clientLabel);
}
public void readFromParcel(Parcel source) {
@@ -401,6 +416,8 @@
lastActivityTime = source.readLong();
restarting = source.readLong();
flags = source.readInt();
+ clientPackage = source.readString();
+ clientLabel = source.readInt();
}
public static final Creator<RunningServiceInfo> CREATOR = new Creator<RunningServiceInfo>() {
@@ -439,6 +456,22 @@
}
/**
+ * Returns a PendingIntent you can start to show a control panel for the
+ * given running service. If the service does not have a control panel,
+ * null is returned.
+ */
+ public PendingIntent getRunningServiceControlPanel(ComponentName service)
+ throws SecurityException {
+ try {
+ return ActivityManagerNative.getDefault()
+ .getRunningServiceControlPanel(service);
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return null;
+ }
+ }
+
+ /**
* Information you can retrieve about the available memory through
* {@link ActivityManager#getMemoryInfo}.
*/
@@ -704,8 +737,51 @@
*/
public int lru;
+ /**
+ * Constant for {@link #importanceReasonCode}: nothing special has
+ * been specified for the reason for this level.
+ */
+ public static final int REASON_UNKNOWN = 0;
+
+ /**
+ * Constant for {@link #importanceReasonCode}: one of the application's
+ * content providers is being used by another process. The pid of
+ * the client process is in {@link #importanceReasonPid} and the
+ * target provider in this process is in
+ * {@link #importanceReasonComponent}.
+ */
+ public static final int REASON_PROVIDER_IN_USE = 1;
+
+ /**
+ * Constant for {@link #importanceReasonCode}: one of the application's
+ * content providers is being used by another process. The pid of
+ * the client process is in {@link #importanceReasonPid} and the
+ * target provider in this process is in
+ * {@link #importanceReasonComponent}.
+ */
+ public static final int REASON_SERVICE_IN_USE = 2;
+
+ /**
+ * The reason for {@link #importance}, if any.
+ */
+ public int importanceReasonCode;
+
+ /**
+ * For the specified values of {@link #importanceReasonCode}, this
+ * is the process ID of the other process that is a client of this
+ * process. This will be 0 if no other process is using this one.
+ */
+ public int importanceReasonPid;
+
+ /**
+ * For the specified values of {@link #importanceReasonCode}, this
+ * is the name of the component that is being used in this process.
+ */
+ public ComponentName importanceReasonComponent;
+
public RunningAppProcessInfo() {
importance = IMPORTANCE_FOREGROUND;
+ importanceReasonCode = REASON_UNKNOWN;
}
public RunningAppProcessInfo(String pProcessName, int pPid, String pArr[]) {
@@ -724,6 +800,9 @@
dest.writeStringArray(pkgList);
dest.writeInt(importance);
dest.writeInt(lru);
+ dest.writeInt(importanceReasonCode);
+ dest.writeInt(importanceReasonPid);
+ ComponentName.writeToParcel(importanceReasonComponent, dest);
}
public void readFromParcel(Parcel source) {
@@ -732,6 +811,9 @@
pkgList = source.readStringArray();
importance = source.readInt();
lru = source.readInt();
+ importanceReasonCode = source.readInt();
+ importanceReasonPid = source.readInt();
+ importanceReasonComponent = ComponentName.readFromParcel(source);
}
public static final Creator<RunningAppProcessInfo> CREATOR =
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 213f26e..4ed152e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -510,6 +510,15 @@
return true;
}
+ case GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ ComponentName comp = ComponentName.CREATOR.createFromParcel(data);
+ PendingIntent pi = getRunningServiceControlPanel(comp);
+ reply.writeNoException();
+ PendingIntent.writePendingIntentOrNullToParcel(pi, reply);
+ return true;
+ }
+
case START_SERVICE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
@@ -1634,6 +1643,21 @@
reply.recycle();
}
+ public PendingIntent getRunningServiceControlPanel(ComponentName service)
+ throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ service.writeToParcel(data, 0);
+ mRemote.transact(GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION, data, reply, 0);
+ reply.readException();
+ PendingIntent res = PendingIntent.readPendingIntentOrNullFromParcel(reply);
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType) throws RemoteException
{
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a7bef54..a937c11 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -126,13 +126,15 @@
public void finishOtherInstances(IBinder token, ComponentName className) throws RemoteException;
/* oneway */
public void reportThumbnail(IBinder token,
- Bitmap thumbnail, CharSequence description) throws RemoteException;
+ Bitmap thumbnail, CharSequence description) throws RemoteException;
public ContentProviderHolder getContentProvider(IApplicationThread caller,
- String name) throws RemoteException;
+ String name) throws RemoteException;
public void removeContentProvider(IApplicationThread caller,
- String name) throws RemoteException;
+ String name) throws RemoteException;
public void publishContentProviders(IApplicationThread caller,
- List<ContentProviderHolder> providers) throws RemoteException;
+ List<ContentProviderHolder> providers) throws RemoteException;
+ public PendingIntent getRunningServiceControlPanel(ComponentName service)
+ throws RemoteException;
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType) throws RemoteException;
public int stopService(IApplicationThread caller, Intent service,
@@ -367,7 +369,7 @@
int PUBLISH_CONTENT_PROVIDERS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+29;
int SET_PERSISTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+30;
int FINISH_SUB_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+31;
-
+ int GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+32;
int START_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+33;
int STOP_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+34;
int BIND_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+35;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 87a8f39..1d1161e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2044,6 +2044,24 @@
public static final String EXTRA_CHANGED_COMPONENT_NAME =
"android.intent.extra.changed_component_name";
+ /**
+ * @hide
+ * Magic extra system code can use when binding, to give a label for
+ * who it is that has bound to a service. This is an integer giving
+ * a framework string resource that can be displayed to the user.
+ */
+ public static final String EXTRA_CLIENT_LABEL =
+ "android.intent.extra.client_label";
+
+ /**
+ * @hide
+ * Magic extra system code can use when binding, to give a PendingIntent object
+ * that can be launched for the user to disable the system's use of this
+ * service.
+ */
+ public static final String EXTRA_CLIENT_INTENT =
+ "android.intent.extra.client_intent";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 5ffe962..6d27bc7 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -1064,6 +1064,10 @@
Intent intent = new Intent();
intent.setAction("android.content.SyncAdapter");
intent.setComponent(info.componentName);
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+ com.android.internal.R.string.sync_binding_label);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0));
return mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 980cff3..699ddb2 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -74,6 +74,12 @@
public static final int SHELL_UID = 2000;
/**
+ * Defines the UID/GID for the log group.
+ * @hide
+ */
+ public static final int LOG_UID = 1007;
+
+ /**
* Defines the UID/GID for the WIFI supplicant process.
* @hide
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 125ed0b..64e47eb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -119,6 +119,20 @@
"android.settings.AIRPLANE_MODE_SETTINGS";
/**
+ * Activity Action: Show settings for accessibility modules.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_ACCESSIBILITY_SETTINGS =
+ "android.settings.ACCESSIBILITY_SETTINGS";
+
+ /**
* Activity Action: Show settings to allow configuration of security and
* location privacy.
* <p>
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d569220..82bff4a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5410,6 +5410,18 @@
}
/**
+ * @hide
+ */
+ protected void onDrawVScrollBar(Canvas canvas, ScrollBarDrawable scrollBar,
+ int l, int t, int r, int b) {
+ scrollBar.setBounds(l, t, r, b);
+ scrollBar.setParameters(computeVerticalScrollRange(),
+ computeVerticalScrollOffset(),
+ computeVerticalScrollExtent(), true);
+ scrollBar.draw(canvas);
+ }
+
+ /**
* <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()}
* returns true.</p>
*
@@ -5441,13 +5453,11 @@
// TODO: Deal with RTL languages to position scrollbar on left
final int left = scrollX + width - size - (mUserPaddingRight & inside);
- scrollBar.setBounds(left, scrollY + (mPaddingTop & inside),
- left + size, scrollY + height - (mUserPaddingBottom & inside));
- scrollBar.setParameters(
- computeVerticalScrollRange(),
- computeVerticalScrollOffset(),
- computeVerticalScrollExtent(), true);
- scrollBar.draw(canvas);
+ onDrawVScrollBar(canvas, scrollBar,
+ left,
+ scrollY + (mPaddingTop & inside),
+ left + size,
+ scrollY + height - (mUserPaddingBottom & inside));
}
/**
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 41e604d..e504591 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -177,17 +177,6 @@
}
/**
- * Tell the host application that the WebView has changed viewing modes.
- * @param newViewingMode One of the values described in WebView as possible
- * values for the viewing mode
- */
- /* package */ void uiOnChangeViewingMode(int newViewingMode) {
- if (mWebChromeClient != null) {
- mWebChromeClient.onChangeViewingMode(mWebView, newViewingMode);
- }
- }
-
- /**
* Called by the UI side. Calling overrideUrlLoading from the WebCore
* side will post a message to call this method.
*/
diff --git a/core/java/android/webkit/ViewManager.java b/core/java/android/webkit/ViewManager.java
index af33b4f..63f4033 100644
--- a/core/java/android/webkit/ViewManager.java
+++ b/core/java/android/webkit/ViewManager.java
@@ -50,8 +50,8 @@
}
setBounds(x, y, width, height);
final AbsoluteLayout.LayoutParams lp =
- new AbsoluteLayout.LayoutParams(ctv(width), ctv(height),
- ctv(x), ctv(y));
+ new AbsoluteLayout.LayoutParams(ctvX(width), ctvX(height),
+ ctvX(x), ctvY(y));
mWebView.mPrivateHandler.post(new Runnable() {
public void run() {
// This method may be called multiple times. If the view is
@@ -97,9 +97,21 @@
return new ChildView();
}
- // contentToView shorthand.
- private int ctv(int val) {
- return mWebView.contentToView(val);
+ /**
+ * Shorthand for calling mWebView.contentToViewX. Used when obtaining a
+ * view x coordinate from a content x coordinate, or when getting a
+ * view dimension from a content dimension, whether it be in x or y.
+ */
+ private int ctvX(int val) {
+ return mWebView.contentToViewX(val);
+ }
+
+ /**
+ * Shorthand for calling mWebView.contentToViewY. Used when obtaining a
+ * view y coordinate from a content y coordinate.
+ */
+ private int ctvY(int val) {
+ return mWebView.contentToViewY(val);
}
void scaleAll() {
@@ -107,10 +119,10 @@
View view = v.mView;
AbsoluteLayout.LayoutParams lp =
(AbsoluteLayout.LayoutParams) view.getLayoutParams();
- lp.width = ctv(v.width);
- lp.height = ctv(v.height);
- lp.x = ctv(v.x);
- lp.y = ctv(v.y);
+ lp.width = ctvX(v.width);
+ lp.height = ctvX(v.height);
+ lp.x = ctvX(v.x);
+ lp.y = ctvY(v.y);
view.setLayoutParams(lp);
}
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index ad4ba05..6421fe7 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -23,15 +23,6 @@
public class WebChromeClient {
/**
- * Tell the host application that the WebView has changed viewing modes.
- * @param view The WebView that initiated the callback.
- * @param newViewingMode One of the values described in WebView as possible
- * values for the viewing mode
- * @hide
- */
- public void onChangeViewingMode(WebView view, int newViewingMode) {}
-
- /**
* Tell the host application the current progress of loading a page.
* @param view The WebView that initiated the callback.
* @param newProgress Current page loading progress, represented by
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 792fdf2..611681f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -525,48 +525,6 @@
// the last zoom scale.
boolean mInZoomOverview = false;
- // The viewing mode of this webview. Reported back to the WebChromeClient
- // so we can hide and display the title bar as appropriate.
- private int mViewingMode;
- /**
- * Not supporting overview vs reading mode
- * @hide
- */
- public final static int NO_VIEWING_MODE = 0;
- /**
- * Zoom overview mode. The page is zoomed all the way out, mInZoomOverview
- * is true, and the title bar is showing. Double tapping will change to
- * reading mode.
- * @hide
- */
- public final static int OVERVIEW_MODE = 1;
- /**
- * Reading mode. The page is at the level specified by the user,
- * mInZoomOverview is false, and the title bar is not showing. Double
- * tapping will change to zoom overview mode.
- * @hide
- */
- public final static int READING_MODE = 2;
- /**
- * Modified reading mode, which shows the title bar. mInZoomOverview is
- * false, and double tapping will change to zoom overview mode. However,
- * if the scrolling will change to reading mode. Used when swiping a
- * tab into view which was in reading mode, unless it was a mobile site
- * with zero scroll.
- * @hide
- */
- public final static int READING_MODE_WITH_TITLE_BAR = 3;
- /**
- * Another modified reading mode. For loading a mobile site, or swiping a
- * tab into view which was displaying a mobile site in reading mode
- * with zero scroll
- * @hide
- */
- public final static int TITLE_BAR_DISMISS_MODE = 4;
- // Whether the current site is a mobile site. Determined when we receive
- // NEW_PICTURE_MSG_ID to help determine how to handle double taps
- private boolean mMobileSite;
-
// ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
// engadget always have wider mContentWidth no matter what viewport size is.
int mZoomOverviewWidth = WebViewCore.DEFAULT_VIEWPORT_WIDTH;
@@ -962,14 +920,20 @@
/*
* Return the height of the view where the content of WebView should render
- * to.
+ * to. Note that this excludes mTitleBar, if there is one.
*/
private int getViewHeight() {
- if (!isHorizontalScrollBarEnabled() || mOverlayHorizontalScrollbar) {
- return getHeight();
- } else {
- return getHeight() - getHorizontalScrollbarHeight();
+ int height = getHeight();
+ if (isHorizontalScrollBarEnabled() && mOverlayHorizontalScrollbar) {
+ height -= getHorizontalScrollbarHeight();
}
+ if (mTitleBar != null) {
+ int titleBarVisibleHeight = mTitleBar.getHeight() - mScrollY;
+ if (titleBarVisibleHeight > 0) {
+ height -= titleBarVisibleHeight;
+ }
+ }
+ return height;
}
/**
@@ -1180,7 +1144,6 @@
if (mInZoomOverview) {
b.putFloat("lastScale", mLastScale);
}
- b.putBoolean("mobile", mMobileSite);
return true;
}
return false;
@@ -1226,20 +1189,12 @@
// correctly
mActualScale = scale;
float lastScale = b.getFloat("lastScale", -1.0f);
- mMobileSite = b.getBoolean("mobile", false);
if (lastScale > 0) {
mInZoomOverview = true;
- mViewingMode = OVERVIEW_MODE;
mLastScale = lastScale;
} else {
mInZoomOverview = false;
- if (mMobileSite && (mScrollX | mScrollY) == 0) {
- mViewingMode = TITLE_BAR_DISMISS_MODE;
- } else {
- mViewingMode = READING_MODE_WITH_TITLE_BAR;
- }
}
- mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
invalidate();
return true;
}
@@ -1692,8 +1647,8 @@
if (type == HitTestResult.UNKNOWN_TYPE
|| type == HitTestResult.SRC_ANCHOR_TYPE) {
// Now check to see if it is an image.
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+ int contentY = viewToContentY((int) mLastTouchY + mScrollY);
String text = nativeImageURI(contentX, contentY);
if (text != null) {
result.setType(type == HitTestResult.UNKNOWN_TYPE ?
@@ -1736,8 +1691,8 @@
* as the data member with "url" as key. The result can be null.
*/
public void requestImageRef(Message msg) {
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+ int contentY = viewToContentY((int) mLastTouchY + mScrollY);
String ref = nativeImageURI(contentX, contentY);
Bundle data = msg.getData();
data.putString("url", ref);
@@ -1771,31 +1726,88 @@
return pinLoc(y, getViewHeight(), computeVerticalScrollRange());
}
- /*package*/ int viewToContent(int x) {
+ /**
+ * A title bar which is embedded in this WebView, and scrolls along with it
+ * vertically, but not horizontally.
+ */
+ private View mTitleBar;
+
+ /**
+ * Add or remove a title bar to be embedded into the WebView, and scroll
+ * along with it vertically, while remaining in view horizontally. Pass
+ * null to remove the title bar from the WebView, and return to drawing
+ * the WebView normally without translating to account for the title bar.
+ * @hide
+ */
+ public void addTitleBar(View v) {
+ if (null == v) {
+ removeView(mTitleBar);
+ } else {
+ addView(v, new AbsoluteLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT, mScrollX, 0));
+ }
+ mTitleBar = v;
+ }
+
+ /**
+ * 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);
}
- /*package*/ int contentToView(int x) {
+ /**
+ * Given a y coordinate in view space, convert it to content space.
+ * Takes into account the height of the title bar if there is one
+ * embedded into the WebView.
+ */
+ /*package*/ int viewToContentY(int y) {
+ if (mTitleBar != null) {
+ y -= mTitleBar.getHeight();
+ }
+ return viewToContentX(y);
+ }
+
+ /**
+ * Given an x coordinate in content space, convert it to view
+ * space. Also used for absolute heights.
+ */
+ /*package*/ int contentToViewX(int x) {
return Math.round(x * mActualScale);
}
+ /**
+ * Given a y coordinate in content space, convert it to view
+ * space. Takes into account the height of the title bar.
+ */
+ /*package*/ int contentToViewY(int y) {
+ int val = Math.round(y * mActualScale);
+ if (mTitleBar != null) {
+ val += mTitleBar.getHeight();
+ }
+ return val;
+ }
+
// Called by JNI to invalidate the View, given rectangle coordinates in
// content space
private void viewInvalidate(int l, int t, int r, int b) {
- invalidate(contentToView(l), contentToView(t), contentToView(r),
- contentToView(b));
+ invalidate(contentToViewX(l), contentToViewY(t), contentToViewX(r),
+ contentToViewY(b));
}
// Called by JNI to invalidate the View after a delay, given rectangle
// coordinates in content space
private void viewInvalidateDelayed(long delay, int l, int t, int r, int b) {
- postInvalidateDelayed(delay, contentToView(l), contentToView(t),
- contentToView(r), contentToView(b));
+ postInvalidateDelayed(delay, contentToViewX(l), contentToViewY(t),
+ contentToViewX(r), contentToViewY(b));
}
private Rect contentToView(Rect x) {
- return new Rect(contentToView(x.left), contentToView(x.top)
- , contentToView(x.right), contentToView(x.bottom));
+ return new Rect(contentToViewX(x.left), contentToViewY(x.top)
+ , contentToViewX(x.right), contentToViewY(x.bottom));
}
// stop the scroll animation, and don't let a subsequent fling add
@@ -1934,10 +1946,10 @@
// Sets r to be our visible rectangle in content coordinates
private void calcOurContentVisibleRect(Rect r) {
calcOurVisibleRect(r);
- r.left = viewToContent(r.left);
- r.top = viewToContent(r.top);
- r.right = viewToContent(r.right);
- r.bottom = viewToContent(r.bottom);
+ r.left = viewToContentX(r.left);
+ r.top = viewToContentY(r.top);
+ r.right = viewToContentX(r.right);
+ r.bottom = viewToContentY(r.bottom);
}
static class ViewSizeData {
@@ -1994,7 +2006,7 @@
if (mDrawHistory) {
return mHistoryWidth;
} else {
- return contentToView(mContentWidth);
+ return contentToViewX(mContentWidth);
}
}
@@ -2006,7 +2018,7 @@
if (mDrawHistory) {
return mHistoryHeight;
} else {
- int height = contentToView(mContentHeight);
+ int height = contentToViewX(mContentHeight);
if (mFindIsUp) {
height += FIND_HEIGHT;
}
@@ -2014,6 +2026,23 @@
}
}
+ @Override
+ protected int computeVerticalScrollOffset() {
+ int offset = super.computeVerticalScrollOffset();
+ if (mTitleBar != null) {
+ // Need to adjust so that the resulting offset is at minimum
+ // the height of the title bar, if it is visible.
+ offset += mTitleBar.getHeight()*computeVerticalScrollRange()
+ /getViewHeight();
+ }
+ return offset;
+ }
+
+ @Override
+ protected int computeVerticalScrollExtent() {
+ return getViewHeight();
+ }
+
/**
* Get the url for the current page. This is not always the same as the url
* passed to WebViewClient.onPageStarted because although the load for
@@ -2365,8 +2394,8 @@
// keys are hit, this should be safe. Right?
return false;
}
- cx = contentToView(cx);
- cy = contentToView(cy);
+ cx = contentToViewX(cx);
+ cy = contentToViewY(cy);
if (mHeightCanMeasure) {
// move our visible rect according to scroll request
if (cy != 0) {
@@ -2398,8 +2427,8 @@
// saved scroll position, it is ok to skip this.
return false;
}
- int vx = contentToView(cx);
- int vy = contentToView(cy);
+ int vx = contentToViewX(cx);
+ int vy = contentToViewY(cy);
// Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
// vx + " " + vy + "]");
pinScrollTo(vx, vy, false, 0);
@@ -2417,8 +2446,8 @@
// is used in the view system.
return;
}
- int vx = contentToView(cx);
- int vy = contentToView(cy);
+ int vx = contentToViewX(cx);
+ int vy = contentToViewY(cy);
pinScrollTo(vx, vy, true, 0);
}
@@ -2435,12 +2464,12 @@
}
if (mHeightCanMeasure) {
- if (getMeasuredHeight() != contentToView(mContentHeight)
+ if (getMeasuredHeight() != contentToViewX(mContentHeight)
&& updateLayout) {
requestLayout();
}
} else if (mWidthCanMeasure) {
- if (getMeasuredWidth() != contentToView(mContentWidth)
+ if (getMeasuredWidth() != contentToViewX(mContentWidth)
&& updateLayout) {
requestLayout();
}
@@ -2582,7 +2611,22 @@
}
@Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ if (child == mTitleBar) {
+ // When drawing the title bar, move it horizontally to always show
+ // at the top of the WebView.
+ mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft());
+ }
+ return super.drawChild(canvas, child, drawingTime);
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
+ int saveCount = canvas.getSaveCount();
+ if (mTitleBar != null) {
+ canvas.save();
+ canvas.translate(0, (int) mTitleBar.getHeight());
+ }
// if mNativeClass is 0, the WebView has been destroyed. Do nothing.
if (mNativeClass == 0) {
return;
@@ -2596,7 +2640,7 @@
mTouchMode = TOUCH_DONE_MODE;
}
}
- int sc = canvas.save();
+ canvas.save();
if (mTouchMode >= FIRST_SCROLL_ZOOM && mTouchMode <= LAST_SCROLL_ZOOM) {
scrollZoomDraw(canvas);
} else {
@@ -2613,7 +2657,7 @@
|| mTrackballDown || mGotCenterDown, false);
drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
}
- canvas.restoreToCount(sc);
+ canvas.restoreToCount(saveCount);
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
@@ -3210,7 +3254,7 @@
// Initialize our generation number.
mTextGeneration = 0;
}
- mWebTextView.setTextSize(contentToView(nativeFocusCandidateTextSize()));
+ mWebTextView.setTextSize(contentToViewX(nativeFocusCandidateTextSize()));
Rect visibleRect = new Rect();
calcOurContentVisibleRect(visibleRect);
// Note that sendOurVisibleRect calls viewToContent, so the coordinates
@@ -3370,8 +3414,8 @@
mShiftIsPressed = true;
if (nativeHasCursorNode()) {
Rect rect = nativeCursorNodeBounds();
- mSelectX = contentToView(rect.left);
- mSelectY = contentToView(rect.top);
+ mSelectX = contentToViewX(rect.left);
+ mSelectY = contentToViewY(rect.top);
} else {
mSelectX = mScrollX + (int) mLastTouchX;
mSelectY = mScrollY + (int) mLastTouchY;
@@ -3758,12 +3802,6 @@
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
- if (mViewingMode == READING_MODE_WITH_TITLE_BAR
- || mViewingMode == TITLE_BAR_DISMISS_MODE) {
- mViewingMode = READING_MODE;
- mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
- }
-
sendOurVisibleRect();
}
@@ -3840,8 +3878,8 @@
eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) {
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
- ted.mX = viewToContent((int) x + mScrollX);
- ted.mY = viewToContent((int) y + mScrollY);
+ ted.mX = viewToContentX((int) x + mScrollX);
+ ted.mY = viewToContentY((int) y + mScrollY);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
}
@@ -3873,8 +3911,8 @@
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "select=" + mSelectX + "," + mSelectY);
}
- nativeMoveSelection(viewToContent(mSelectX)
- , viewToContent(mSelectY), false);
+ nativeMoveSelection(viewToContentX(mSelectX),
+ viewToContentY(mSelectY), false);
mTouchSelection = mExtendSelection = true;
} else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
@@ -3930,8 +3968,8 @@
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "xtend=" + mSelectX + "," + mSelectY);
}
- nativeMoveSelection(viewToContent(mSelectX)
- , viewToContent(mSelectY), true);
+ nativeMoveSelection(viewToContentX(mSelectX),
+ viewToContentY(mSelectY), true);
invalidate();
break;
}
@@ -3981,13 +4019,6 @@
deltaY = newScrollY - mScrollY;
boolean done = false;
if (deltaX == 0 && deltaY == 0) {
- // The user attempted to pan the page, so dismiss the title
- // bar
- if (mViewingMode == READING_MODE_WITH_TITLE_BAR
- || mViewingMode == TITLE_BAR_DISMISS_MODE) {
- mViewingMode = READING_MODE;
- mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
- }
done = true;
} else {
if (mSnapScrollMode == SNAP_X || mSnapScrollMode == SNAP_Y) {
@@ -4307,8 +4338,8 @@
+ " yRate=" + yRate
);
}
- nativeMoveSelection(viewToContent(mSelectX)
- , viewToContent(mSelectY), mExtendSelection);
+ nativeMoveSelection(viewToContentX(mSelectX),
+ viewToContentY(mSelectY), mExtendSelection);
int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
: mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
: 0;
@@ -4687,8 +4718,8 @@
return;
}
// mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+ int contentY = viewToContentY((int) mLastTouchY + mScrollY);
Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
contentX + mNavSlop, contentY + mNavSlop);
nativeSelectBestAt(rect);
@@ -4703,8 +4734,8 @@
if (!inEditingMode() || mWebViewCore == null) {
return;
}
- mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContent(x),
- viewToContent(y));
+ mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContentX(x),
+ viewToContentY(y));
}
/**
@@ -4751,16 +4782,16 @@
if (!inEditingMode()) {
return;
}
- int x = viewToContent((int) event.getX() + mWebTextView.getLeft());
- int y = viewToContent((int) event.getY() + mWebTextView.getTop());
+ int x = viewToContentX((int) event.getX() + mWebTextView.getLeft());
+ int y = viewToContentY((int) event.getY() + mWebTextView.getTop());
nativeTextInputMotionUp(x, y);
}
/*package*/ void shortPressOnTextField() {
if (inEditingMode()) {
View v = mWebTextView;
- int x = viewToContent((v.getLeft() + v.getRight()) >> 1);
- int y = viewToContent((v.getTop() + v.getBottom()) >> 1);
+ int x = viewToContentX((v.getLeft() + v.getRight()) >> 1);
+ int y = viewToContentY((v.getTop() + v.getBottom()) >> 1);
nativeTextInputMotionUp(x, y);
}
}
@@ -4771,8 +4802,8 @@
}
switchOutDrawHistory();
// mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+ int contentY = viewToContentY((int) mLastTouchY + mScrollY);
if (nativeMotionUp(contentX, contentY, mNavSlop)) {
if (mLogEvent) {
Checkin.updateStats(mContext.getContentResolver(),
@@ -4784,42 +4815,13 @@
}
}
- /**
- * Called when the Tabs are used to slide this WebView's tab into view.
- * @hide
- */
- public void slideIntoFocus() {
- if (mViewingMode == READING_MODE) {
- if (!mMobileSite || (mScrollX | mScrollY) != 0) {
- mViewingMode = READING_MODE_WITH_TITLE_BAR;
- } else {
- mViewingMode = TITLE_BAR_DISMISS_MODE;
- }
- mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
- }
- }
-
private void doDoubleTap() {
- if (mWebViewCore.getSettings().getUseWideViewPort() == false ||
- mViewingMode == NO_VIEWING_MODE) {
+ if (mWebViewCore.getSettings().getUseWideViewPort() == false) {
return;
}
- if (mViewingMode == TITLE_BAR_DISMISS_MODE) {
- mViewingMode = READING_MODE;
- // mInZoomOverview will not change, so change the viewing mode
- // and return
- mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
- return;
- }
- if (mViewingMode == READING_MODE_WITH_TITLE_BAR && mMobileSite) {
- scrollTo(0,0);
- }
- // READING_MODE_WITH_TITLE_BAR will go to OVERVIEW_MODE here.
mZoomCenterX = mLastTouchX;
mZoomCenterY = mLastTouchY;
mInZoomOverview = !mInZoomOverview;
- mViewingMode = mInZoomOverview ? OVERVIEW_MODE : READING_MODE;
- mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
// remove the zoom control after double tap
if (getSettings().getBuiltInZoomControls()) {
if (mZoomButtonsController.isVisible()) {
@@ -4837,8 +4839,8 @@
zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth);
} else {
// mLastTouchX and mLastTouchY are the point in the current viewport
- int contentX = viewToContent((int) mLastTouchX + mScrollX);
- int contentY = viewToContent((int) mLastTouchY + mScrollY);
+ int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+ int contentY = viewToContentY((int) mLastTouchY + mScrollY);
int left = nativeGetBlockLeftEdge(contentX, contentY, mActualScale);
if (left != NO_LEFTEDGE) {
// add a 5pt padding to the left edge. Re-calculate the zoom
@@ -5169,22 +5171,12 @@
restoreState.mScrollY);
if (!ENABLE_DOUBLETAP_ZOOM
|| !settings.getLoadWithOverviewMode()) {
- mMobileSite = false;
- mViewingMode = NO_VIEWING_MODE;
} else {
- mMobileSite = restoreState.mMobileSite;
if (useWideViewport
&& restoreState.mViewScale == 0) {
- mViewingMode = OVERVIEW_MODE;
mInZoomOverview = true;
- } else if (mMobileSite
- && (mScrollX | mScrollY) == 0) {
- mViewingMode = TITLE_BAR_DISMISS_MODE;
- } else {
- mViewingMode = READING_MODE_WITH_TITLE_BAR;
}
}
- mCallbackProxy.uiOnChangeViewingMode(mViewingMode);
// As we are on a new page, remove the WebTextView. This
// is necessary for page loads driven by webkit, and in
// particular when the user was on a password field, so
@@ -5648,7 +5640,7 @@
width = visRect.width() / 2;
}
// FIXME the divisor should be retrieved from somewhere
- return viewToContent(width);
+ return viewToContentX(width);
}
private int getScaledMaxYScroll() {
@@ -5663,7 +5655,7 @@
// FIXME the divisor should be retrieved from somewhere
// the closest thing today is hard-coded into ScrollView.java
// (from ScrollView.java, line 363) int maxJump = height/2;
- return viewToContent(height);
+ return viewToContentY(height);
}
/**
diff --git a/core/res/res/drawable-hdpi/tab_focus.9.png b/core/res/res/drawable-hdpi/tab_focus.9.png
index 0c3a9ee..6e8a71f 100644
--- a/core/res/res/drawable-hdpi/tab_focus.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
index 54e3022..51194a4 100644
--- a/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
index 34a85f0..51194a4 100644
--- a/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_focus_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press.9.png b/core/res/res/drawable-hdpi/tab_press.9.png
index 6b3c1c7..119b2c6 100644
--- a/core/res/res/drawable-hdpi/tab_press.9.png
+++ b/core/res/res/drawable-hdpi/tab_press.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_left.9.png b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
index f998532..dc2fbce 100644
--- a/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_press_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_press_bar_right.9.png b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
index 43515bd..dc2fbce 100644
--- a/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_press_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected.9.png b/core/res/res/drawable-hdpi/tab_selected.9.png
index b128b48..29d45a17 100644
--- a/core/res/res/drawable-hdpi/tab_selected.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
index a49ef68..aa935fe 100644
--- a/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_left.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
index 472f839..aa935fe 100644
--- a/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
+++ b/core/res/res/drawable-hdpi/tab_selected_bar_right.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/tab_unselected.9.png b/core/res/res/drawable-hdpi/tab_unselected.9.png
index ed9e311..f5781ab 100644
--- a/core/res/res/drawable-hdpi/tab_unselected.9.png
+++ b/core/res/res/drawable-hdpi/tab_unselected.9.png
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 70c9385..3333915 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1943,25 +1943,34 @@
<string-array translatable="false" name="carrier_properties">
</string-array>
- <!-- Title for the selected state of a CompoundButton. -->
- <string name="accessibility_compound_button_selected">checked</string>
+ <!-- Title for the selected state of a CompoundButton. -->
+ <string name="accessibility_compound_button_selected">checked</string>
- <!-- Title for the unselected state of a CompoundButton. -->
- <string name="accessibility_compound_button_unselected">not checked</string>
+ <!-- Title for the unselected state of a CompoundButton. -->
+ <string name="accessibility_compound_button_unselected">not checked</string>
- <string name="grant_credentials_permission_message_desc">The
- listed applications are requesting permission to access the login credentials for account <xliff:g id="account" example="foo@gmail.com">%1$s</xliff:g> from
- <xliff:g id="application" example="Google Apps">%2$s</xliff:g>. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted
- again.</string>
+ <string name="grant_credentials_permission_message_desc">The
+ listed applications are requesting permission to access the login credentials for account <xliff:g id="account" example="foo@gmail.com">%1$s</xliff:g> from
+ <xliff:g id="application" example="Google Apps">%2$s</xliff:g>. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted
+ again.</string>
- <string name="grant_credentials_permission_message_with_authtokenlabel_desc">The
- listed applications are requesting permission to access the <xliff:g id="type" example="Contacts">%1$s</xliff:g> login credentials for account <xliff:g id="account" example="foo@gmail.com">%2$s</xliff:g> from
- <xliff:g id="application" example="Google Apps">%3$s</xliff:g>. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted
- again.</string>
+ <string name="grant_credentials_permission_message_with_authtokenlabel_desc">The
+ listed applications are requesting permission to access the <xliff:g id="type" example="Contacts">%1$s</xliff:g> login credentials for account <xliff:g id="account" example="foo@gmail.com">%2$s</xliff:g> from
+ <xliff:g id="application" example="Google Apps">%3$s</xliff:g>. Do you wish to grant this permission? If so, your answer will be remembered and you will not be prompted
+ again.</string>
- <string name="allow">Allow</string>
- <string name="deny">Deny</string>
- <string name="permission_request_notification_title">Permission Requested</string>
- <string name="permission_request_notification_subtitle">for account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
+ <string name="allow">Allow</string>
+ <string name="deny">Deny</string>
+ <string name="permission_request_notification_title">Permission Requested</string>
+ <string name="permission_request_notification_subtitle">for account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
+ <!-- Label to show for a service that is running because it is an input method. -->
+ <string name="input_method_binding_label">Input method</string>
+ <!-- Label to show for a service that is running because it is a sync adapter. -->
+ <string name="sync_binding_label">Sync</string>
+ <!-- Label to show for a service that is running because it is an accessibility module. -->
+ <string name="accessibility_binding_label">Accessibility</string>
+ <!-- Label to show for a service that is running because it is a wallpaper. -->
+ <string name="wallpaper_binding_label">Wallpaper</string>
+
</resources>
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 536f71c..e6cb395 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -110,9 +110,12 @@
}
public void data(Object o) {
- mRS.nAllocationDataFromObject(mID, mType, o);
+ mRS.nAllocationSubDataFromObject(mID, mType, 0, o);
}
+ public void subData(int offset, Object o) {
+ mRS.nAllocationSubDataFromObject(mID, mType, offset, o);
+ }
public class Adapter1D extends BaseObj {
Adapter1D(int id, RenderScript rs) {
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 0ca112c..0b7e667 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -244,8 +244,8 @@
}
public Builder addFloatXY(String prefix) {
- add(DataType.FLOAT, DataKind.X, false, 32, prefix + "X");
- add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "Y");
+ add(DataType.FLOAT, DataKind.X, false, 32, prefix + "x");
+ add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "y");
return this;
}
@@ -257,9 +257,9 @@
}
public Builder addFloatXYZ(String prefix) {
- add(DataType.FLOAT, DataKind.X, false, 32, prefix + "X");
- add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "Y");
- add(DataType.FLOAT, DataKind.Z, false, 32, prefix + "Z");
+ add(DataType.FLOAT, DataKind.X, false, 32, prefix + "x");
+ add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "y");
+ add(DataType.FLOAT, DataKind.Z, false, 32, prefix + "z");
return this;
}
@@ -270,8 +270,8 @@
}
public Builder addFloatST(String prefix) {
- add(DataType.FLOAT, DataKind.S, false, 32, prefix + "S");
- add(DataType.FLOAT, DataKind.T, false, 32, prefix + "T");
+ add(DataType.FLOAT, DataKind.S, false, 32, prefix + "s");
+ add(DataType.FLOAT, DataKind.T, false, 32, prefix + "t");
return this;
}
@@ -283,9 +283,9 @@
}
public Builder addFloatNorm(String prefix) {
- add(DataType.FLOAT, DataKind.NX, false, 32, prefix + "NX");
- add(DataType.FLOAT, DataKind.NY, false, 32, prefix + "NY");
- add(DataType.FLOAT, DataKind.NZ, false, 32, prefix + "NZ");
+ add(DataType.FLOAT, DataKind.NX, false, 32, prefix + "nx");
+ add(DataType.FLOAT, DataKind.NY, false, 32, prefix + "ny");
+ add(DataType.FLOAT, DataKind.NZ, false, 32, prefix + "nz");
return this;
}
@@ -294,8 +294,8 @@
return this;
}
- public Builder addFloatPointSize(String name) {
- add(DataType.FLOAT, DataKind.POINT_SIZE, false, 32, name);
+ public Builder addFloatPointSize(String prefix) {
+ add(DataType.FLOAT, DataKind.POINT_SIZE, false, 32, prefix + "pointSize");
return this;
}
@@ -307,9 +307,9 @@
}
public Builder addFloatRGB(String prefix) {
- add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "R");
- add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "G");
- add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "B");
+ add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "r");
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "g");
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "b");
return this;
}
@@ -322,10 +322,10 @@
}
public Builder addFloatRGBA(String prefix) {
- add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "R");
- add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "G");
- add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "B");
- add(DataType.FLOAT, DataKind.ALPHA, false, 32, prefix + "A");
+ add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "r");
+ add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "g");
+ add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "b");
+ add(DataType.FLOAT, DataKind.ALPHA, false, 32, prefix + "a");
return this;
}
@@ -338,10 +338,10 @@
}
public Builder addUNorm8RGBA(String prefix) {
- add(DataType.UNSIGNED, DataKind.RED, true, 8, prefix + "R");
- add(DataType.UNSIGNED, DataKind.GREEN, true, 8, prefix + "G");
- add(DataType.UNSIGNED, DataKind.BLUE, true, 8, prefix + "B");
- add(DataType.UNSIGNED, DataKind.ALPHA, true, 8, prefix + "A");
+ add(DataType.UNSIGNED, DataKind.RED, true, 8, prefix + "r");
+ add(DataType.UNSIGNED, DataKind.GREEN, true, 8, prefix + "g");
+ add(DataType.UNSIGNED, DataKind.BLUE, true, 8, prefix + "b");
+ add(DataType.UNSIGNED, DataKind.ALPHA, true, 8, prefix + "a");
return this;
}
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 0f188f6..bd345e5 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -106,7 +106,7 @@
native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d, int sizeBytes);
native void nAllocationRead(int id, int[] d);
native void nAllocationRead(int id, float[] d);
- native void nAllocationDataFromObject(int id, Type t, Object o);
+ native void nAllocationSubDataFromObject(int id, Type t, int offset, Object o);
native void nTriangleMeshBegin(int vertex, int index);
native void nTriangleMeshAddVertex_XY (float x, float y);
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
index e66fb8a..5d87654 100644
--- a/graphics/java/android/renderscript/SimpleMesh.java
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -50,6 +50,13 @@
return Allocation.createTyped(mRS, mIndexType);
}
+ public Type getVertexType(int slot) {
+ return mVertexTypes[slot];
+ }
+
+ public Type getIndexType() {
+ return mIndexType;
+ }
public static class Builder {
RenderScript mRS;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 558146d..62c3914 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -543,7 +543,7 @@
//{"nAllocationDataFromObject", "(ILandroid/renderscript/Type;Ljava/lang/Object;)V", (void*)nAllocationDataFromObject },
static void
-nAllocationDataFromObject(JNIEnv *_env, jobject _this, jint alloc, jobject _type, jobject _o)
+nAllocationSubDataFromObject(JNIEnv *_env, jobject _this, jint alloc, jobject _type, jint offset, jobject _o)
{
RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
LOG_API("nAllocationDataFromObject con(%p), alloc(%p)", con, (RsAllocation)alloc);
@@ -556,7 +556,7 @@
const TypeFieldCache *tfc = &tc->fields[ct];
buf = tfc->ptr(_env, _o, tfc->field, buf);
}
- rsAllocationData(con, (RsAllocation)alloc, bufAlloc, tc->size);
+ rsAllocation1DSubData(con, (RsAllocation)alloc, offset, 1, bufAlloc, tc->size);
const uint32_t * tmp = (const uint32_t *)bufAlloc;
free(bufAlloc);
}
@@ -1282,7 +1282,7 @@
{"nAllocationSubData2D", "(IIIII[FI)V", (void*)nAllocationSubData2D_f },
{"nAllocationRead", "(I[I)V", (void*)nAllocationRead_i },
{"nAllocationRead", "(I[F)V", (void*)nAllocationRead_f },
-{"nAllocationDataFromObject", "(ILandroid/renderscript/Type;Ljava/lang/Object;)V", (void*)nAllocationDataFromObject },
+{"nAllocationSubDataFromObject", "(ILandroid/renderscript/Type;ILjava/lang/Object;)V", (void*)nAllocationSubDataFromObject },
{"nTriangleMeshBegin", "(II)V", (void*)nTriangleMeshBegin },
{"nTriangleMeshAddVertex_XY", "(FF)V", (void*)nTriangleMeshAddVertex_XY },
diff --git a/include/media/mediascanner.h b/include/media/mediascanner.h
index 7749566..cd0b86e 100644
--- a/include/media/mediascanner.h
+++ b/include/media/mediascanner.h
@@ -59,16 +59,17 @@
class MediaScannerClient
{
public:
- MediaScannerClient();
- virtual ~MediaScannerClient();
- void setLocale(const char* locale);
- void beginFile();
- bool addStringTag(const char* name, const char* value);
- void endFile();
-
- virtual bool scanFile(const char* path, long long lastModified, long long fileSize) = 0;
- virtual bool handleStringTag(const char* name, const char* value) = 0;
- virtual bool setMimeType(const char* mimeType) = 0;
+ MediaScannerClient();
+ virtual ~MediaScannerClient();
+ void setLocale(const char* locale);
+ void beginFile();
+ bool addStringTag(const char* name, const char* value);
+ void endFile();
+
+ virtual bool scanFile(const char* path, long long lastModified, long long fileSize) = 0;
+ virtual bool handleStringTag(const char* name, const char* value) = 0;
+ virtual bool setMimeType(const char* mimeType) = 0;
+ virtual bool addNoMediaFolder(const char* path) = 0;
protected:
void convertValues(uint32_t encoding);
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
index f348a62..c09f43c 100644
--- a/libs/rs/java/Fall/res/raw/fall.c
+++ b/libs/rs/java/Fall/res/raw/fall.c
@@ -52,8 +52,8 @@
}
void dropWithStrength(int x, int y, int r, int s) {
- int width = State_meshWidth;
- int height = State_meshHeight;
+ int width = State->meshWidth;
+ int height = State->meshHeight;
if (x < r) x = r;
if (y < r) y = r;
@@ -62,8 +62,8 @@
x = width - x;
- int rippleMapSize = State_rippleMapSize;
- int index = State_rippleIndex;
+ int rippleMapSize = State->rippleMapSize;
+ int index = State->rippleIndex;
int origin = offset(0, 0, width);
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
@@ -94,10 +94,10 @@
}
void updateRipples() {
- int rippleMapSize = State_rippleMapSize;
- int width = State_meshWidth;
- int height = State_meshHeight;
- int index = State_rippleIndex;
+ int rippleMapSize = State->rippleMapSize;
+ int width = State->meshWidth;
+ int height = State->meshHeight;
+ int index = State->rippleIndex;
int origin = offset(0, 0, width);
int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
@@ -139,9 +139,9 @@
void generateRipples() {
int rippleMapSize = loadI32(RSID_STATE, OFFSETOF_WorldState_rippleMapSize);
- int width = State_meshWidth;
- int height = State_meshHeight;
- int index = State_rippleIndex;
+ int width = State->meshWidth;
+ int height = State->meshHeight;
+ int index = State->rippleIndex;
int origin = offset(0, 0, width);
int b = width + 2;
@@ -180,7 +180,7 @@
// Update Z coordinate of the vertex
vertices[index + 7] = dy * fy;
-
+
w -= 1;
current += 1;
wave = nextWave;
@@ -210,7 +210,7 @@
float v2x = vertices[o1 + 5];
float v2y = vertices[o1 + 6];
float v2z = vertices[o1 + 7];
-
+
// V3
float v3x = vertices[ow + 5];
float v3y = vertices[ow + 6];
@@ -236,7 +236,7 @@
n3x *= len;
n3y *= len;
n3z *= len;
-
+
// V2
v2x = vertices[ow1 + 5];
v2y = vertices[ow1 + 6];
@@ -266,7 +266,7 @@
vertices[o + 0] = n3x;
vertices[o + 1] = n3y;
vertices[o + 2] = -n3z;
-
+
// reset Z
//vertices[(yOffset + x) << 3 + 7] = 0.0f;
}
@@ -322,7 +322,7 @@
float z2 = 0.0f;
float z3 = 0.0f;
float z4 = 0.0f;
-
+
float a = leafStruct[LEAF_STRUCT_ALTITUDE];
float s = leafStruct[LEAF_STRUCT_SCALE];
float r = leafStruct[LEAF_STRUCT_ANGLE];
@@ -384,7 +384,7 @@
LEAF_SIZE * s + y < -glHeight / 2.0f) {
int sprite = randf(LEAVES_TEXTURES_COUNT);
- leafStruct[LEAF_STRUCT_X] = randf2(-1.0f, 1.0f);
+ leafStruct[LEAF_STRUCT_X] = randf2(-1.0f, 1.0f);
leafStruct[LEAF_STRUCT_Y] = glHeight / 2.0f + LEAF_SIZE * 2 * randf(1.0f);
leafStruct[LEAF_STRUCT_SCALE] = randf2(0.4f, 0.5f);
leafStruct[LEAF_STRUCT_SPIN] = degf(randf2(-0.02f, 0.02f)) / 4.0f;
@@ -401,20 +401,20 @@
bindProgramVertex(NAMED_PVSky);
bindTexture(NAMED_PFBackground, 0, NAMED_TLeaves);
- int leavesCount = State_leavesCount;
+ int leavesCount = State->leavesCount;
int count = leavesCount * LEAF_STRUCT_FIELDS_COUNT;
- int width = State_meshWidth;
- int height = State_meshHeight;
- float glWidth = State_glWidth;
- float glHeight = State_glHeight;
+ int width = State->meshWidth;
+ int height = State->meshHeight;
+ float glWidth = State->glWidth;
+ float glHeight = State->glHeight;
- float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
+ float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
int i = 0;
for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
drawLeaf(i, vertices, width, height, glWidth, glHeight);
}
-
+
float matrix[16];
matrixLoadIdentity(matrix);
vpLoadModelMatrix(matrix);
@@ -433,8 +433,8 @@
bindProgramFragmentStore(NAMED_PFSLeaf);
bindTexture(NAMED_PFSky, 0, NAMED_TSky);
- float x = State_skyOffsetX + State_skySpeedX;
- float y = State_skyOffsetY + State_skySpeedY;
+ float x = State->skyOffsetX + State->skySpeedX;
+ float y = State->skyOffsetY + State->skySpeedY;
if (x > 1.0f) x = 0.0f;
if (x < -1.0f) x = 0.0f;
@@ -467,8 +467,8 @@
}
void drawNormals() {
- int width = State_meshWidth;
- int height = State_meshHeight;
+ int width = State->meshWidth;
+ int height = State->meshHeight;
float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
@@ -496,12 +496,10 @@
}
int main(int index) {
- int dropX = Drop_dropX;
- if (dropX != -1) {
- int dropY = Drop_dropY;
- drop(dropX, dropY, DROP_RADIUS);
- storeI32(RSID_DROP, OFFSETOF_DropState_dropX, -1);
- storeI32(RSID_DROP, OFFSETOF_DropState_dropY, -1);
+ if (Drop->dropX != -1) {
+ drop(Drop->dropX, Drop->dropY, DROP_RADIUS);
+ Drop->dropX = -1;
+ Drop->dropY = -1;
}
updateRipples();
diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c
index 8f3d930..8fbfee1 100644
--- a/libs/rs/java/Film/res/raw/filmstrip.c
+++ b/libs/rs/java/Film/res/raw/filmstrip.c
@@ -5,10 +5,6 @@
#pragma stateFragment(PFBackground)
#pragma stateFragmentStore(PSBackground)
-#define POS_TRANSLATE 0
-#define POS_ROTATE 1
-#define POS_FOCUS 2
-
#define STATE_TRIANGLE_OFFSET_COUNT 0
#define STATE_LAST_FOCUS 1
@@ -18,12 +14,14 @@
// bank1: (r) The position information
// bank2: (rw) The temporary texture state
+int lastFocus;
+
int main(int index)
{
float mat1[16];
- float trans = Pos_translate;
- float rot = Pos_rotate;
+ float trans = Pos->translate;
+ float rot = Pos->rotate;
matrixLoadScale(mat1, 2.f, 2.f, 2.f);
matrixTranslate(mat1, 0.f, 0.f, trans);
@@ -39,7 +37,7 @@
bindProgramFragment(NAMED_PFImages);
bindProgramVertex(NAMED_PVImages);
- float focusPos = Pos_focus;
+ float focusPos = Pos->focus;
int focusID = 0;
int lastFocusID = loadI32(2, STATE_LAST_FOCUS);
int imgCount = 13;
@@ -63,9 +61,9 @@
}
}
*/
- storeI32(2, STATE_LAST_FOCUS, focusID);
+ lastFocus = focusID;
- int triangleOffsetsCount = Pos_triangleOffsetCount;
+ int triangleOffsetsCount = Pos->triangleOffsetCount;
int imgId = 0;
for (imgId=1; imgId <= imgCount; imgId++) {
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
index 99f4048..36516c2 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.c
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -4,27 +4,32 @@
#pragma stateFragment(default)
#pragma stateFragmentStore(default)
-struct PartStruct {float dx; float dy; float x; float y; int c;};
int newPart = 0;
int main(int launchID) {
int ct;
- int count = Control_count - 1;
- int rate = Control_rate;
+ int count = Control->count;
+ int rate = Control->rate;
float height = getHeight();
- struct PartStruct * p = (struct PartStruct *)loadArrayF(1, 0);
+ struct point_s * p = (struct point_s *)point;
if (rate) {
float rMax = ((float)rate) * 0.005f;
- int x = Control_x;
- int y = Control_y;
- int c = colorFloatRGBAtoUNorm8(Control_r, Control_g, Control_b, 0.99f);
+ int x = Control->x;
+ int y = Control->y;
+ char r = Control->r * 255.f;
+ char g = Control->g * 255.f;
+ char b = Control->b * 255.f;
+ char a = 0xf0;
while (rate--) {
vec2Rand((float *)(p + newPart), rMax);
p[newPart].x = x;
p[newPart].y = y;
- p[newPart].c = c;
+ p[newPart].r = r;
+ p[newPart].g = g;
+ p[newPart].b = b;
+ p[newPart].a = a;
newPart++;
if (newPart >= count) {
newPart = 0;
@@ -45,6 +50,6 @@
}
uploadToBufferObject(NAMED_PartBuffer);
- drawSimpleMeshRange(NAMED_PartMesh, 0, count);
+ drawSimpleMesh(NAMED_PartMesh);
return 1;
}
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index 6d400c5..f4f9b0c 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -79,10 +79,10 @@
mIntAlloc.data(mSD);
Element.Builder eb = new Element.Builder(mRS);
- eb.addFloat(Element.DataKind.USER); //dx
- eb.addFloat(Element.DataKind.USER); //dy
- eb.addFloatXY();
- eb.addUNorm8RGBA();
+ eb.addFloat(Element.DataKind.USER, "dx");
+ eb.addFloat(Element.DataKind.USER, "dy");
+ eb.addFloatXY("");
+ eb.addUNorm8RGBA("");
Element primElement = eb.create();
@@ -102,6 +102,7 @@
sb.setScript(mRes, R.raw.fountain);
sb.setRoot(true);
sb.setType(mSDType, "Control", 0);
+ sb.setType(mSM.getVertexType(0), "point", 1);
Script script = sb.create();
script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index c28bd02..c132915 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -116,6 +116,7 @@
//glEnable(GL_LIGHT0);
glViewport(0, 0, mEGL.mWidth, mEGL.mHeight);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glEnable(GL_POINT_SMOOTH);
glClearColor(mRootScript->mEnviroment.mClearColor[0],
mRootScript->mEnviroment.mClearColor[1],
@@ -153,10 +154,18 @@
void Context::timerInit()
{
mTimeLast = getTime();
+ mTimeFrame = mTimeLast;
+ mTimeLastFrame = mTimeLast;
mTimerActive = RS_TIMER_INTERNAL;
timerReset();
}
+void Context::timerFrame()
+{
+ mTimeLastFrame = mTimeFrame;
+ mTimeFrame = getTime();
+}
+
void Context::timerSet(Timers tm)
{
uint64_t last = mTimeLast;
@@ -171,8 +180,10 @@
for (int ct = 0; ct < _RS_TIMER_TOTAL; ct++) {
total += mTimers[ct];
}
+ uint64_t frame = mTimeFrame - mTimeLastFrame;
- LOGV("RS Time Data: Idle %2.1f (%lli), Internal %2.1f (%lli), Script %2.1f (%lli), Clear & Swap %2.1f (%lli)",
+ LOGV("RS: Frame (%lli), Script %2.1f (%lli), Clear & Swap %2.1f (%lli), Idle %2.1f (%lli), Internal %2.1f (%lli)",
+ frame / 1000000,
100.0 * mTimers[RS_TIMER_IDLE] / total, mTimers[RS_TIMER_IDLE] / 1000000,
100.0 * mTimers[RS_TIMER_INTERNAL] / total, mTimers[RS_TIMER_INTERNAL] / 1000000,
100.0 * mTimers[RS_TIMER_SCRIPT] / total, mTimers[RS_TIMER_SCRIPT] / 1000000,
@@ -232,6 +243,7 @@
#endif
eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
#if RS_LOG_TIMES
+ rsc->timerFrame();
rsc->timerSet(RS_TIMER_INTERNAL);
rsc->timerPrint();
rsc->timerReset();
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index c58a88c..634416b 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -131,6 +131,7 @@
void timerReset();
void timerSet(Timers);
void timerPrint();
+ void timerFrame();
bool checkVersion1_1() const {return (mGL.mMajorVersion > 1) || (mGL.mMinorVersion >= 1); }
bool checkVersion2_0() const {return mGL.mMajorVersion >= 2; }
@@ -202,6 +203,8 @@
uint64_t mTimers[_RS_TIMER_TOTAL];
Timers mTimerActive;
uint64_t mTimeLast;
+ uint64_t mTimeFrame;
+ uint64_t mTimeLastFrame;
};
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 0c7ac18..9d9eb1b 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -67,6 +67,12 @@
= nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_MONOTONIC));
}
+ for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ if (mProgram.mSlotPointers[ct]) {
+ *mProgram.mSlotPointers[ct] = mSlots[ct]->getPtr();
+ }
+ }
+
bool ret = false;
tls->mScript = this;
ret = mProgram.mScript(launchIndex) != 0;
@@ -139,6 +145,7 @@
accRegisterSymbolCallback(mAccScript, symbolLookup, NULL);
accCompileScript(mAccScript);
accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
+ accGetScriptLabel(mAccScript, "init", (ACCvoid**) &mProgram.mInit);
rsAssert(mProgram.mScript);
if (!mProgram.mScript) {
@@ -148,6 +155,19 @@
LOGE(buf);
}
+ if (mProgram.mInit) {
+ mProgram.mInit();
+ }
+
+ for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+ if (mSlotNames[ct].length() > 0) {
+ accGetScriptLabel(mAccScript,
+ mSlotNames[ct].string(),
+ (ACCvoid**) &mProgram.mSlotPointers[ct]);
+ LOGE("var %s %p", mSlotNames[ct].string(), mProgram.mSlotPointers[ct]);
+ }
+ }
+
mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
@@ -224,6 +244,19 @@
}
}
+static void appendElementBody(String8 *s, const Element *e)
+{
+ s->append(" {\n");
+ for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
+ const Component *c = e->getComponent(ct2);
+ s->append(" ");
+ s->append(c->getCType());
+ s->append(" ");
+ s->append(c->getComponentName());
+ s->append(";\n");
+ }
+ s->append("}");
+}
void ScriptCState::appendVarDefines(String8 *str)
{
@@ -246,6 +279,8 @@
}
}
+
+
void ScriptCState::appendTypes(String8 *str)
{
char buf[256];
@@ -257,6 +292,19 @@
continue;
}
const Element *e = t->getElement();
+ if (e->getName() && (e->getComponentCount() > 1)) {
+ String8 s("struct struct_");
+ s.append(e->getName());
+ appendElementBody(&s, e);
+ s.append(";\n");
+ s.append("#define ");
+ s.append(e->getName());
+ s.append("_t struct struct_");
+ s.append(e->getName());
+ s.append("\n\n");
+ LOGD(s);
+ str->append(s);
+ }
if (t->getName()) {
for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
@@ -267,12 +315,39 @@
tmp.append(c->getComponentName());
sprintf(buf, " %i\n", ct2);
tmp.append(buf);
- //LOGD(tmp);
+ LOGD(tmp);
str->append(tmp);
}
}
if (mSlotNames[ct].length() > 0) {
+ String8 s;
+ if (e->getComponentCount() > 1) {
+ if (e->getName()) {
+ // Use the named struct
+ s.setTo(e->getName());
+ s.append("_t *");
+ } else {
+ // create an struct named from the slot.
+ s.setTo("struct ");
+ s.append(mSlotNames[ct]);
+ s.append("_s");
+ appendElementBody(&s, e);
+ s.append(";\n");
+ s.append("struct ");
+ s.append(mSlotNames[ct]);
+ s.append("_s * ");
+ }
+ } else {
+ // Just make an array
+ s.setTo(e->getComponent(0)->getCType());
+ s.append("_t *");
+ }
+ s.append(mSlotNames[ct]);
+ s.append(";\n");
+ LOGD(s);
+ str->append(s);
+#if 0
for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
const Component *c = e->getComponent(ct2);
tmp.setTo("#define ");
@@ -295,12 +370,12 @@
sprintf(buf, "%i, %i)\n", ct, ct2);
tmp.append(buf);
- //LOGD(tmp);
+ LOGD(tmp);
str->append(tmp);
}
+#endif
}
}
-
}
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 302515e..8aa99ef 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -35,6 +35,7 @@
{
public:
typedef int (*RunScript_t)(uint32_t launchIndex);
+ typedef void (*VoidFunc_t)();
ScriptC();
virtual ~ScriptC();
@@ -48,6 +49,9 @@
int mVersionMinor;
RunScript_t mScript;
+ VoidFunc_t mInit;
+
+ void ** mSlotPointers[MAX_SCRIPT_BANKS];
};
Program_t mProgram;
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 3d5aae3..fcc76ca5 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -825,6 +825,22 @@
}
}
+ public void addNoMediaFolder(String path) {
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Images.ImageColumns.DATA, "");
+ String [] pathSpec = new String[] {path + '%'};
+ try {
+ mMediaProvider.update(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values,
+ MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
+ mMediaProvider.update(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values,
+ MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
+ mMediaProvider.update(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values,
+ MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec);
+ } catch (RemoteException e) {
+ throw new RuntimeException();
+ }
+ }
+
}; // end of anonymous MediaScannerClient instance
private void prescan(String filePath) throws RemoteException {
diff --git a/media/java/android/media/MediaScannerClient.java b/media/java/android/media/MediaScannerClient.java
index cf1a8da..258c3b4 100644
--- a/media/java/android/media/MediaScannerClient.java
+++ b/media/java/android/media/MediaScannerClient.java
@@ -25,11 +25,13 @@
public void scanFile(String path, String mimeType, long lastModified, long fileSize);
+ public void addNoMediaFolder(String path);
+
/**
* Called by native code to return metadata extracted from media files.
*/
public void handleStringTag(String name, String value);
-
+
/**
* Called by native code to return mime type extracted from DRM content.
*/
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 97de486..6a5404e3 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -65,6 +65,8 @@
"(Ljava/lang/String;Ljava/lang/String;)V");
mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType",
"(Ljava/lang/String;)V");
+ mAddNoMediaFolderMethodID = env->GetMethodID(mediaScannerClientInterface, "addNoMediaFolder",
+ "(Ljava/lang/String;)V");
}
}
@@ -111,12 +113,26 @@
return (!mEnv->ExceptionCheck());
}
+ // returns true if it succeeded, false if an exception occured in the Java code
+ virtual bool addNoMediaFolder(const char* path)
+ {
+ jstring pathStr;
+ if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false;
+
+ mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
+
+ mEnv->DeleteLocalRef(pathStr);
+ return (!mEnv->ExceptionCheck());
+ }
+
+
private:
JNIEnv *mEnv;
jobject mClient;
jmethodID mScanFileMethodID;
jmethodID mHandleStringTagMethodID;
jmethodID mSetMimeTypeMethodID;
+ jmethodID mAddNoMediaFolderMethodID;
};
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index 55007ba..f67a7ae 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -25,6 +25,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.IEventListener;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -615,6 +616,10 @@
mId = sIdCounter++;
mComponentName = componentName;
mIntent = new Intent().setComponent(mComponentName);
+ mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+ com.android.internal.R.string.accessibility_binding_label);
+ mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0));
}
/**
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 558a024..1da2b47 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -32,6 +32,7 @@
import android.app.ActivityManagerNative;
import android.app.AlertDialog;
+import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -765,6 +766,10 @@
mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
mCurIntent.setComponent(info.getComponent());
+ mCurIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+ com.android.internal.R.string.input_method_binding_label);
+ mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) {
mLastBindTime = SystemClock.uptimeMillis();
mHaveConnection = true;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 14cd7a8..82cf1bc 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -112,6 +112,7 @@
private static final boolean MULTIPLE_APPLICATION_UIDS = true;
private static final int RADIO_UID = Process.PHONE_UID;
+ private static final int LOG_UID = Process.LOG_UID;
private static final int FIRST_APPLICATION_UID =
Process.FIRST_APPLICATION_UID;
private static final int MAX_APPLICATION_UIDS = 1000;
@@ -364,6 +365,10 @@
MULTIPLE_APPLICATION_UIDS
? RADIO_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLP("android.uid.log",
+ MULTIPLE_APPLICATION_UIDS
+ ? LOG_UID : FIRST_APPLICATION_UID,
+ ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index c101463..cc977b0 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -21,6 +21,7 @@
import android.app.IWallpaperManager;
import android.app.IWallpaperManagerCallback;
+import android.app.PendingIntent;
import android.backup.BackupManager;
import android.content.ComponentName;
import android.content.Context;
@@ -40,6 +41,7 @@
import android.os.RemoteCallbackList;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.provider.Settings;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
@@ -376,6 +378,10 @@
// Bind the service!
WallpaperConnection newConn = new WallpaperConnection();
intent.setComponent(realName);
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+ com.android.internal.R.string.wallpaper_binding_label);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
+ mContext, 0, new Intent(Intent.ACTION_SET_WALLPAPER), 0));
if (!mContext.bindService(intent, newConn,
Context.BIND_AUTO_CREATE)) {
throw new IllegalArgumentException("Unable to bind service: "
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 03ebf0c..9554a22 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8866,6 +8866,16 @@
} else {
currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
}
+ currApp.importanceReasonCode = app.adjTypeCode;
+ if (app.adjSource instanceof ProcessRecord) {
+ currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
+ } else if (app.adjSource instanceof HistoryRecord) {
+ HistoryRecord r = (HistoryRecord)app.adjSource;
+ if (r.app != null) currApp.importanceReasonPid = r.app.pid;
+ }
+ if (app.adjTarget instanceof ComponentName) {
+ currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
+ }
//Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
// + " lru=" + currApp.lru);
if (runList == null) {
@@ -9888,6 +9898,13 @@
if (r.app != null && r.app.persistent) {
info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
}
+ for (ConnectionRecord conn : r.connections.values()) {
+ if (conn.clientLabel != 0) {
+ info.clientPackage = conn.binding.client.info.packageName;
+ info.clientLabel = conn.clientLabel;
+ break;
+ }
+ }
return info;
}
@@ -9916,6 +9933,20 @@
}
}
+ public PendingIntent getRunningServiceControlPanel(ComponentName name) {
+ synchronized (this) {
+ ServiceRecord r = mServices.get(name);
+ if (r != null) {
+ for (ConnectionRecord conn : r.connections.values()) {
+ if (conn.clientIntent != null) {
+ return conn.clientIntent;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
private final ServiceRecord findServiceLocked(ComponentName name,
IBinder token) {
ServiceRecord r = mServices.get(name);
@@ -10783,6 +10814,29 @@
activity = (HistoryRecord)mHistory.get(aindex);
}
+ int clientLabel = 0;
+ PendingIntent clientIntent = null;
+
+ if (callerApp.info.uid == Process.SYSTEM_UID) {
+ // Hacky kind of thing -- allow system stuff to tell us
+ // what they are, so we can report this elsewhere for
+ // others to know why certain services are running.
+ try {
+ clientIntent = (PendingIntent)service.getParcelableExtra(
+ Intent.EXTRA_CLIENT_INTENT);
+ } catch (RuntimeException e) {
+ }
+ if (clientIntent != null) {
+ clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
+ if (clientLabel != 0) {
+ // There are no useful extras in the intent, trash them.
+ // System code calling with this stuff just needs to know
+ // this will happen.
+ service = service.cloneFilter();
+ }
+ }
+ }
+
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid());
@@ -10803,7 +10857,7 @@
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
- connection, flags);
+ connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
s.connections.put(binder, c);
@@ -12776,6 +12830,7 @@
return (app.curAdj=app.maxAdj);
}
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
app.adjSource = null;
app.adjTarget = null;
@@ -12909,6 +12964,8 @@
adj = clientAdj > VISIBLE_APP_ADJ
? clientAdj : VISIBLE_APP_ADJ;
app.adjType = "service";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
app.adjSource = cr.binding.client;
app.adjTarget = s.serviceInfo.name;
}
@@ -12922,6 +12979,8 @@
|| a.state == ActivityState.PAUSING)) {
adj = FOREGROUND_APP_ADJ;
app.adjType = "service";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE;
app.adjSource = a;
app.adjTarget = s.serviceInfo.name;
}
@@ -12964,6 +13023,8 @@
adj = clientAdj > FOREGROUND_APP_ADJ
? clientAdj : FOREGROUND_APP_ADJ;
app.adjType = "provider";
+ app.adjTypeCode = ActivityManager.RunningAppProcessInfo
+ .REASON_PROVIDER_IN_USE;
app.adjSource = client;
app.adjTarget = cpr.info.name;
}
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index b3343dd..f613b00 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import android.app.IServiceConnection;
+import android.app.PendingIntent;
import java.io.PrintWriter;
@@ -28,6 +29,8 @@
final HistoryRecord activity; // If non-null, the owning activity.
final IServiceConnection conn; // The client connection.
final int flags; // Binding options.
+ final int clientLabel; // String resource labeling this client.
+ final PendingIntent clientIntent; // How to launch the client.
String stringName; // Caching of toString.
void dump(PrintWriter pw, String prefix) {
@@ -40,11 +43,14 @@
}
ConnectionRecord(AppBindRecord _binding, HistoryRecord _activity,
- IServiceConnection _conn, int _flags) {
+ IServiceConnection _conn, int _flags,
+ int _clientLabel, PendingIntent _clientIntent) {
binding = _binding;
activity = _activity;
conn = _conn;
flags = _flags;
+ clientLabel = _clientLabel;
+ clientIntent = _clientIntent;
}
public String toString() {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 76fdf09..d05b44b 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -75,6 +75,7 @@
boolean reportLowMemory; // Set to true when waiting to report low mem
int lastPss; // Last pss size reported by app.
String adjType; // Debugging: primary thing impacting oom_adj.
+ int adjTypeCode; // Debugging: adj code to report to app.
Object adjSource; // Debugging: option dependent object.
Object adjTarget; // Debugging: target component impacting oom_adj.
diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.java b/telephony/java/com/android/internal/telephony/AdnRecord.java
index 5f40579..0896ba6 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecord.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecord.java
@@ -23,6 +23,8 @@
import com.android.internal.telephony.GsmAlphabet;
+import java.util.Arrays;
+
/**
*
@@ -38,6 +40,7 @@
String alphaTag = "";
String number = "";
+ String[] emails;
int extRecord = 0xff;
int efid; // or 0 if none
int recordNumber; // or 0 if none
@@ -74,13 +77,15 @@
int recordNumber;
String alphaTag;
String number;
+ String[] emails;
efid = source.readInt();
recordNumber = source.readInt();
alphaTag = source.readString();
number = source.readString();
+ emails = source.readStringArray();
- return new AdnRecord(efid, recordNumber, alphaTag, number);
+ return new AdnRecord(efid, recordNumber, alphaTag, number, emails);
}
public AdnRecord[] newArray(int size) {
@@ -90,29 +95,38 @@
//***** Constructor
- public
- AdnRecord (byte[] record) {
+ public AdnRecord (byte[] record) {
this(0, 0, record);
}
- public
- AdnRecord (int efid, int recordNumber, byte[] record) {
+ public AdnRecord (int efid, int recordNumber, byte[] record) {
this.efid = efid;
this.recordNumber = recordNumber;
parseRecord(record);
}
- public
- AdnRecord (String alphaTag, String number) {
+ public AdnRecord (String alphaTag, String number) {
this(0, 0, alphaTag, number);
}
- public
- AdnRecord (int efid, int recordNumber, String alphaTag, String number) {
+ public AdnRecord (String alphaTag, String number, String[] emails) {
+ this(0, 0, alphaTag, number, emails);
+ }
+
+ public AdnRecord (int efid, int recordNumber, String alphaTag, String number, String[] emails) {
this.efid = efid;
this.recordNumber = recordNumber;
this.alphaTag = alphaTag;
this.number = number;
+ this.emails = emails;
+ }
+
+ public AdnRecord(int efid, int recordNumber, String alphaTag, String number) {
+ this.efid = efid;
+ this.recordNumber = recordNumber;
+ this.alphaTag = alphaTag;
+ this.number = number;
+ this.emails = null;
}
//***** Instance Methods
@@ -125,12 +139,20 @@
return number;
}
+ public String[] getEmails() {
+ return emails;
+ }
+
+ public void setEmails(String[] emails) {
+ this.emails = emails;
+ }
+
public String toString() {
- return "ADN Record '" + alphaTag + "' '" + number + "'";
+ return "ADN Record '" + alphaTag + "' '" + number + " " + emails + "'";
}
public boolean isEmpty() {
- return alphaTag.equals("") && number.equals("");
+ return alphaTag.equals("") && number.equals("") && emails == null;
}
public boolean hasExtendedRecord() {
@@ -139,7 +161,8 @@
public boolean isEqual(AdnRecord adn) {
return ( alphaTag.equals(adn.getAlphaTag()) &&
- number.equals(adn.getNumber()) );
+ number.equals(adn.getNumber()) &&
+ Arrays.equals(emails, adn.getEmails()));
}
//***** Parcelable Implementation
@@ -152,6 +175,7 @@
dest.writeInt(recordNumber);
dest.writeString(alphaTag);
dest.writeString(number);
+ dest.writeStringArray(emails);
}
/**
@@ -274,10 +298,13 @@
extRecord = 0xff & record[record.length - 1];
+ emails = null;
+
} catch (RuntimeException ex) {
Log.w(LOG_TAG, "Error parsing AdnRecord", ex);
number = "";
alphaTag = "";
+ emails = null;
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
index c270ae5..c8c0658 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecordCache.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecordCache.java
@@ -16,14 +16,16 @@
package com.android.internal.telephony;
-import android.util.SparseArray;
-import android.util.Log;
-import android.os.Message;
-import android.os.Handler;
import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.telephony.gsm.UsimPhoneBookManager;
+
import java.util.ArrayList;
import java.util.Iterator;
-import com.android.internal.telephony.IccConstants;
/**
* {@hide}
@@ -32,6 +34,7 @@
//***** Instance Variables
PhoneBase phone;
+ private UsimPhoneBookManager mUsimPhoneBookManager;
// Indexed by EF ID
SparseArray<ArrayList<AdnRecord>> adnLikeFiles
@@ -55,6 +58,7 @@
public AdnRecordCache(PhoneBase phone) {
this.phone = phone;
+ mUsimPhoneBookManager = new UsimPhoneBookManager(phone, this);
}
//***** Called from SIMRecords
@@ -64,6 +68,7 @@
*/
public void reset() {
adnLikeFiles.clear();
+ mUsimPhoneBookManager.reset();
clearWaiters();
clearUserWriters();
@@ -103,14 +108,14 @@
*
* See 3GPP TS 51.011 for this mapping
*/
- private int
- extensionEfForEf(int efid) {
+ int extensionEfForEf(int efid) {
switch (efid) {
case EF_MBDN: return EF_EXT6;
case EF_ADN: return EF_EXT1;
case EF_SDN: return EF_EXT3;
case EF_FDN: return EF_EXT2;
case EF_MSISDN: return EF_EXT1;
+ case EF_PBR: return 0; // The EF PBR doesn't have an extension record
default: return -1;
}
}
@@ -223,11 +228,15 @@
* record
*/
public void
- requestLoadAllAdnLike (int efid, Message response) {
+ requestLoadAllAdnLike (int efid, int extensionEf, Message response) {
ArrayList<Message> waiters;
ArrayList<AdnRecord> result;
- result = getRecordsIfLoaded(efid);
+ if (efid == EF_PBR) {
+ result = mUsimPhoneBookManager.loadEfFilesFromUsim();
+ } else {
+ result = getRecordsIfLoaded(efid);
+ }
// Have we already loaded this efid?
if (result != null) {
@@ -258,9 +267,8 @@
adnLikeWaiters.put(efid, waiters);
- int extensionEF = extensionEfForEf(efid);
- if (extensionEF < 0) {
+ if (extensionEf < 0) {
// respond with error if not known ADN-like record
if (response != null) {
@@ -272,7 +280,7 @@
return;
}
- new AdnRecordLoader(phone).loadAllFromEF(efid, extensionEF,
+ new AdnRecordLoader(phone).loadAllFromEF(efid, extensionEf,
obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0));
}
@@ -311,7 +319,7 @@
adnLikeWaiters.delete(efid);
if (ar.exception == null) {
- adnLikeFiles.put(efid, (ArrayList<AdnRecord>) (ar.result));
+ adnLikeFiles.put(efid, (ArrayList<AdnRecord>) ar.result);
}
notifyWaiters(waiters, ar);
break;
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 200340e..0f76633 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -655,7 +655,7 @@
}
- public boolean hasApplicationType(IccCardApplication.AppType type) {
+ public boolean isApplicationOnIcc(IccCardApplication.AppType type) {
if (mIccCardStatus == null) return false;
for (int i = 0 ; i < mIccCardStatus.getNumApplications(); i++) {
diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java
index 7eafafd..acc9197 100644
--- a/telephony/java/com/android/internal/telephony/IccConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccConstants.java
@@ -42,6 +42,9 @@
static final int EF_CFIS = 0x6FCB;
static final int EF_IMG = 0x4f20;
+ // USIM SIM file ids from TS 31.102
+ public static final int EF_PBR = 0x4F30;
+
// GSM SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6
static final int EF_MAILBOX_CPHS = 0x6F17;
static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11;
@@ -59,6 +62,7 @@
static final String MF_SIM = "3F00";
static final String DF_TELECOM = "7F10";
+ static final String DF_PHONEBOOK = "5F3A";
static final String DF_GRAPHICS = "5F50";
static final String DF_GSM = "7F20";
static final String DF_CDMA = "7F25";
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 0bcaaa6..31cf6a7 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -115,7 +115,8 @@
* Replace oldAdn with newAdn in ADN-like record in EF
*
* getAdnRecordsInEf must be called at least once before this function,
- * otherwise an error will be returned
+ * otherwise an error will be returned. Currently the email field
+ * if set in the ADN record is ignored.
* throws SecurityException if no WRITE_CONTACTS permission
*
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
@@ -167,7 +168,8 @@
* Update an ADN-like EF record by record index
*
* This is useful for iteration the whole ADN file, such as write the whole
- * phone book or erase/format the whole phonebook
+ * phone book or erase/format the whole phonebook. Currently the email field
+ * if set in the ADN record is ignored.
* throws SecurityException if no WRITE_CONTACTS permission
*
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
@@ -237,12 +239,13 @@
"Requires android.permission.READ_CONTACTS permission");
}
+ efid = updateEfForIccType(efid);
if (DBG) logd("getAdnRecordsInEF: efid=" + efid);
synchronized(mLock) {
checkThread();
Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE);
- adnCache.requestLoadAllAdnLike(efid, response);
+ adnCache.requestLoadAllAdnLike(efid, adnCache.extensionEfForEf(efid), response);
try {
mLock.wait();
} catch (InterruptedException e) {
@@ -262,5 +265,15 @@
}
}
}
+
+ private int updateEfForIccType(int efid) {
+ // Check if we are trying to read ADN records
+ if (efid == IccConstants.EF_ADN) {
+ if (phone.getIccCard().isApplicationOnIcc(IccCardApplication.AppType.APPTYPE_USIM)) {
+ return IccConstants.EF_PBR;
+ }
+ }
+ return efid;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index 4cbd779..ffcfe6f 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -46,7 +46,8 @@
private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
"name",
- "number"
+ "number",
+ "emails"
};
private static final int ADN = 1;
@@ -55,6 +56,7 @@
private static final String STR_TAG = "tag";
private static final String STR_NUMBER = "number";
+ private static final String STR_EMAILS = "emails";
private static final String STR_PIN2 = "pin2";
private static final UriMatcher URL_MATCHER =
@@ -172,7 +174,8 @@
String tag = initialValues.getAsString("tag");
String number = initialValues.getAsString("number");
- boolean success = addIccRecordToEf(efType, tag, number, pin2);
+ // TODO(): Read email instead of sending null.
+ boolean success = addIccRecordToEf(efType, tag, number, null, pin2);
if (!success) {
return null;
@@ -238,6 +241,7 @@
// parse where clause
String tag = null;
String number = null;
+ String[] emails = null;
String pin2 = null;
String[] tokens = where.split("AND");
@@ -261,6 +265,9 @@
tag = normalizeValue(val);
} else if (STR_NUMBER.equals(key)) {
number = normalizeValue(val);
+ } else if (STR_EMAILS.equals(key)) {
+ //TODO(): Email is null.
+ emails = null;
} else if (STR_PIN2.equals(key)) {
pin2 = normalizeValue(val);
}
@@ -274,7 +281,7 @@
return 0;
}
- boolean success = deleteIccRecordFromEf(efType, tag, number, pin2);
+ boolean success = deleteIccRecordFromEf(efType, tag, number, emails, pin2);
if (!success) {
return 0;
}
@@ -307,9 +314,11 @@
String tag = values.getAsString("tag");
String number = values.getAsString("number");
+ String[] emails = null;
String newTag = values.getAsString("newTag");
String newNumber = values.getAsString("newNumber");
-
+ String[] newEmails = null;
+ // TODO(): Update for email.
boolean success = updateIccRecordInEf(efType, tag, number,
newTag, newNumber, pin2);
@@ -355,9 +364,9 @@
}
private boolean
- addIccRecordToEf(int efType, String name, String number, String pin2) {
+ addIccRecordToEf(int efType, String name, String number, String[] emails, String pin2) {
if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name +
- ", number=" + number);
+ ", number=" + number + ", emails=" + emails);
boolean success = false;
@@ -384,7 +393,7 @@
private boolean
updateIccRecordInEf(int efType, String oldName, String oldNumber,
- String newName, String newNumber,String pin2) {
+ String newName, String newNumber, String pin2) {
if (DBG) log("updateIccRecordInEf: efType=" + efType +
", oldname=" + oldName + ", oldnumber=" + oldNumber +
", newname=" + newName + ", newnumber=" + newNumber);
@@ -407,9 +416,10 @@
}
- private boolean deleteIccRecordFromEf(int efType, String name, String number, String pin2) {
+ private boolean deleteIccRecordFromEf(int efType, String name, String number, String[] emails,
+ String pin2) {
if (DBG) log("deleteIccRecordFromEf: efType=" + efType +
- ", name=" + name + ", number=" + number + ", pin2=" + pin2);
+ ", name=" + name + ", number=" + number + ", emails=" + emails + ", pin2=" + pin2);
boolean success = false;
@@ -438,13 +448,26 @@
private void loadRecord(AdnRecord record,
ArrayList<ArrayList> results) {
if (!record.isEmpty()) {
- ArrayList<String> contact = new ArrayList<String>(2);
+ ArrayList<String> contact = new ArrayList<String>();
String alphaTag = record.getAlphaTag();
String number = record.getNumber();
+ String[] emails = record.getEmails();
- if (DBG) log("loadRecord: " + alphaTag + ", " + number);
+ if (DBG) log("loadRecord: " + alphaTag + ", " + number + ",");
contact.add(alphaTag);
contact.add(number);
+ StringBuilder emailString = new StringBuilder();
+
+ if (emails != null) {
+ for (String email: emails) {
+ if (DBG) log("Adding email:" + email);
+ emailString.append(email);
+ emailString.append(",");
+ }
+ contact.add(emailString.toString());
+ } else {
+ contact.add(null);
+ }
results.add(contact);
}
}
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index ea24c25..b8d9e3c 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -31,7 +31,7 @@
public abstract class IccRecords extends Handler implements IccConstants {
protected static final boolean DBG = true;
- //***** Instance Variables
+ // ***** Instance Variables
protected PhoneBase phone;
protected RegistrantList recordsLoadedRegistrants = new RegistrantList();
@@ -40,7 +40,7 @@
protected AdnRecordCache adnCache;
- //***** Cached SIM State; cleared on channel close
+ // ***** Cached SIM State; cleared on channel close
protected boolean recordsRequested = false; // true if we've made requests for the sim records
@@ -54,23 +54,26 @@
protected boolean isVoiceMailFixed = false;
protected int countVoiceMessages = 0;
- protected int mncLength = 0; // 0 is used to indicate that the value
- // is not initialized
+ protected int mncLength = UNINITIALIZED;
protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated
protected String spn;
protected int spnDisplayCondition;
- //***** Constants
+ // ***** Constants
+
+ // Markers for mncLength
+ protected static final int UNINITIALIZED = -1;
+ protected static final int UNKNOWN = 0;
// Bitmasks for SPN display rules.
protected static final int SPN_RULE_SHOW_SPN = 0x01;
protected static final int SPN_RULE_SHOW_PLMN = 0x02;
- //***** Event Constants
+ // ***** Event Constants
protected static final int EVENT_SET_MSISDN_DONE = 30;
- //***** Constructor
+ // ***** Constructor
public IccRecords(PhoneBase p) {
this.phone = p;
@@ -234,4 +237,3 @@
protected abstract void log(String s);
}
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/MccTable.java
similarity index 84%
rename from telephony/java/com/android/internal/telephony/gsm/MccTable.java
rename to telephony/java/com/android/internal/telephony/MccTable.java
index 9343f44..0d11f8c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/MccTable.java
@@ -14,7 +14,17 @@
* limitations under the License.
*/
-package com.android.internal.telephony.gsm;
+package com.android.internal.telephony;
+
+import android.app.ActivityManagerNative;
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.net.wifi.WifiManager;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Log;
import java.util.Arrays;
@@ -475,8 +485,10 @@
0x65630400, 0x67660400, 0x70790400, 0x73720400, 0x75790400, 0x666b0400
};
+ static final String LOG_TAG = "MccTable";
+
/**
- * Given a GSM Mobile Country Code, returns a default time zone ID
+ * Given a Mobile Country Code, returns a default time zone ID
* if available. Returns null if unavailable.
*/
public static String defaultTimeZoneForMcc(int mcc) {
@@ -494,7 +506,7 @@
}
/**
- * Given a GSM Mobile Country Code, returns an ISO two-character
+ * Given a Mobile Country Code, returns an ISO two-character
* country code if available. Returns "" if unavailable.
*/
public static String countryCodeForMcc(int mcc) {
@@ -553,4 +565,95 @@
return wifi;
}
+ /**
+ * Updates MCC and MNC device configuration information for application retrieving
+ * correct version of resources. If either MCC or MNC is 0, they will be ignored (not set).
+ * @param phone PhoneBae to act on.
+ * @param mccmnc truncated imsi with just the MCC and MNC - MNC assumed to be from 4th to end
+ */
+ public static void updateMccMncConfiguration(PhoneBase phone, String mccmnc) {
+ Configuration config = new Configuration();
+ int mcc, mnc;
+
+ try {
+ mcc = Integer.parseInt(mccmnc.substring(0,3));
+ mnc = Integer.parseInt(mccmnc.substring(3));
+ } catch (NumberFormatException e) {
+ Log.e(LOG_TAG, "Error parsing IMSI");
+ return;
+ }
+
+ Log.d(LOG_TAG, "updateMccMncConfiguration: mcc=" + mcc + ", mnc=" + mnc);
+
+ if (mcc != 0) {
+ config.mcc = mcc;
+ setTimezoneFromMccIfNeeded(phone, mcc);
+ setLocaleFromMccIfNeeded(phone, mcc);
+ setWifiChannelsFromMccIfNeeded(phone, mcc);
+ }
+ if (mnc != 0) {
+ config.mnc = mnc;
+ }
+ try {
+ ActivityManagerNative.getDefault().updateConfiguration(config);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Can't update configuration", e);
+ }
+ }
+
+ /**
+ * If the timezone is not already set, set it based on the MCC of the SIM.
+ * @param phone PhoneBase to act on (get context from).
+ * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
+ */
+ private static void setTimezoneFromMccIfNeeded(PhoneBase phone, int mcc) {
+ String timezone = SystemProperties.get(ServiceStateTracker.TIMEZONE_PROPERTY);
+ if (timezone == null || timezone.length() == 0) {
+ String zoneId = defaultTimeZoneForMcc(mcc);
+ if (zoneId != null && zoneId.length() > 0) {
+ Context context = phone.getContext();
+ // Set time zone based on MCC
+ AlarmManager alarm =
+ (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ alarm.setTimeZone(zoneId);
+ Log.d(LOG_TAG, "timezone set to "+zoneId);
+ }
+ }
+ }
+
+ /**
+ * If the locale is not already set, set it based on the MCC of the SIM.
+ * @param phone PhoneBase to act on.
+ * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
+ */
+ private static void setLocaleFromMccIfNeeded(PhoneBase phone, int mcc) {
+ String language = MccTable.defaultLanguageForMcc(mcc);
+ String country = MccTable.countryCodeForMcc(mcc);
+
+ Log.d(LOG_TAG, "locale set to "+language+"_"+country);
+ phone.setSystemLocale(language, country);
+ }
+
+ /**
+ * If the number of allowed wifi channels has not been set, set it based on
+ * the MCC of the SIM.
+ * @param phone PhoneBase to act on (get context from).
+ * @param mcc Mobile Country Code of the SIM or SIM-like entity (build prop on CDMA)
+ */
+ private static void setWifiChannelsFromMccIfNeeded(PhoneBase phone, int mcc) {
+ int wifiChannels = MccTable.wifiChannelsForMcc(mcc);
+ if (wifiChannels != 0) {
+ Context context = phone.getContext();
+ // only set to this default if the user hasn't manually set it
+ try {
+ Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
+ } catch (Settings.SettingNotFoundException e) {
+ Log.d(LOG_TAG, "WIFI_NUM_ALLOWED_CHANNESL set to " + wifiChannels);
+ WifiManager wM = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ // don't persist
+ wM.setNumAllowedChannels(wifiChannels, false);
+ }
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 647b991..ff06bc0 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -48,10 +48,7 @@
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.DataConnection;
-// TODO(Moto): need to move MccTable from telephony.gsm to telephony
-// since there is no difference between CDMA and GSM for MccTable and
-// CDMA uses gsm's MccTable is not good.
-import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccException;
import com.android.internal.telephony.IccFileHandler;
@@ -203,7 +200,7 @@
updateCurrentCarrierInProvider(operatorNumeric);
// Updates MCC MNC device configuration information
- updateMccMncConfiguration(operatorNumeric);
+ MccTable.updateMccMncConfiguration(this, operatorNumeric);
// Notify voicemails.
@@ -1406,21 +1403,4 @@
return false;
}
- /**
- * Updates MCC and MNC device configuration information for application retrieving
- * correct version of resources
- *
- */
- private void updateMccMncConfiguration(String operatorNumeric) {
- if (operatorNumeric.length() >= 5) {
- Configuration config = new Configuration();
- config.mcc = Integer.parseInt(operatorNumeric.substring(0,3));
- config.mnc = Integer.parseInt(operatorNumeric.substring(3));
- try {
- ActivityManagerNative.getDefault().updateConfiguration(config);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Can't update configuration", e);
- }
- }
- }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index dab529e..46e360b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -45,9 +45,8 @@
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataConnectionTracker;
-import com.android.internal.telephony.gsm.MccTable;
import com.android.internal.telephony.IccCard;
-import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyEventLog;
import com.android.internal.telephony.TelephonyIntents;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 7c74314..b9ece8b 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -28,7 +28,7 @@
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.cdma.RuimCard;
-import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.MccTable;
// can't be used since VoiceMailConstants is not public
//import com.android.internal.telephony.gsm.VoiceMailConstants;
@@ -47,7 +47,7 @@
private static final boolean DBG = true;
private boolean m_ota_commited=false;
- //***** Instance Variables
+ // ***** Instance Variables
private String mImsi;
private String mMyMobileNumber;
@@ -55,7 +55,7 @@
private String mPrlVersion;
- //***** Event Constants
+ // ***** Event Constants
private static final int EVENT_RUIM_READY = 1;
private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
@@ -109,7 +109,7 @@
@Override
protected void onRadioOffOrNotAvailable() {
countVoiceMessages = 0;
- mncLength = 0;
+ mncLength = UNINITIALIZED;
iccid = null;
adnCache.reset();
@@ -167,7 +167,7 @@
}
// TODO(Moto): mncLength is not set anywhere.
- if (mncLength != 0) {
+ if (mncLength != UNINITIALIZED && mncLength != UNKNOWN) {
// Length = length of MCC + length of MNC
// TODO: change spec name
// length of mcc = 3 (3GPP2 C.S0005 - Section 2.3)
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index a9be068..65463e5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -49,6 +49,7 @@
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.TelephonyEventLog;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
index a08cdde..206e62f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
@@ -19,15 +19,18 @@
import android.os.Message;
import android.util.Log;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccCardApplication;
import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.Phone;
/**
* {@hide}
*/
public final class SIMFileHandler extends IccFileHandler implements IccConstants {
static final String LOG_TAG = "GSM";
-
+ private Phone mPhone;
//***** Instance Variables
@@ -35,6 +38,7 @@
SIMFileHandler(GSMPhone phone) {
super(phone);
+ mPhone = phone;
}
public void dispose() {
@@ -53,7 +57,6 @@
}
protected String getEFPath(int efid) {
- // TODO(): Make changes when USIM is supported
// TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility.
// Implement this after discussion with OEMs.
switch(efid) {
@@ -79,8 +82,23 @@
case EF_SPN_SHORT_CPHS:
case EF_INFO_CPHS:
return MF_SIM + DF_GSM;
+
+ case EF_PBR:
+ // we only support global phonebook.
+ return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
}
- return getCommonIccEFPath(efid);
+ String path = getCommonIccEFPath(efid);
+ if (path == null) {
+ // The EFids in USIM phone book entries are decided by the card manufacturer.
+ // So if we don't match any of the cases above and if its a USIM return
+ // the phone book path.
+ IccCard card = phone.getIccCard();
+ if (card != null && card.isApplicationOnIcc(IccCardApplication.AppType.APPTYPE_USIM)) {
+ return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
+ }
+ Log.e(LOG_TAG, "Error: EF Path being returned in null");
+ }
+ return path;
}
protected void logd(String msg) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 4272faa..7f7855a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -19,13 +19,10 @@
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
-import android.app.AlarmManager;
import android.content.Context;
-import android.net.wifi.WifiManager;
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemProperties;
-import android.provider.Settings;
import android.util.Log;
import com.android.internal.telephony.AdnRecord;
@@ -37,6 +34,7 @@
import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.IccVmFixedException;
import com.android.internal.telephony.IccVmNotSupportedException;
+import com.android.internal.telephony.MccTable;
import java.util.ArrayList;
@@ -51,14 +49,14 @@
private static final boolean DBG = true;
- //***** Instance Variables
+ // ***** Instance Variables
VoiceMailConstants mVmConfig;
SpnOverride mSpnOverride;
- //***** Cached SIM State; cleared on channel close
+ // ***** Cached SIM State; cleared on channel close
String imsi;
boolean callForwardingEnabled;
@@ -88,7 +86,7 @@
String pnnHomeName = null;
- //***** Constants
+ // ***** Constants
// Bitmasks for SPN display rules.
static final int SPN_RULE_SHOW_SPN = 0x01;
@@ -113,7 +111,7 @@
private static final int CPHS_SST_MBN_MASK = 0x30;
private static final int CPHS_SST_MBN_ENABLED = 0x30;
- //***** Event Constants
+ // ***** Event Constants
private static final int EVENT_SIM_READY = 1;
private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
@@ -143,9 +141,7 @@
private static final int EVENT_SIM_REFRESH = 31;
private static final int EVENT_GET_CFIS_DONE = 32;
- private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
-
- //***** Constructor
+ // ***** Constructor
SIMRecords(GSMPhone p) {
super(p);
@@ -188,7 +184,7 @@
msisdn = null;
voiceMailNum = null;
countVoiceMessages = 0;
- mncLength = 0;
+ mncLength = UNINITIALIZED;
iccid = null;
// -1 means no EF_SPN found; treat accordingly.
spnDisplayCondition = -1;
@@ -453,79 +449,16 @@
* provided the SIM card. Returns null of SIM is not yet ready
*/
String getSIMOperatorNumeric() {
- if (imsi == null) {
+ if (imsi == null || mncLength == UNINITIALIZED || mncLength == UNKNOWN) {
return null;
}
- if (mncLength != 0) {
- // Length = length of MCC + length of MNC
- // length of mcc = 3 (TS 23.003 Section 2.2)
- return imsi.substring(0, 3 + mncLength);
- }
-
- // Guess the MNC length based on the MCC if we don't
- // have a valid value in ef[ad]
-
- int mcc;
-
- mcc = Integer.parseInt(imsi.substring(0,3));
-
- return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
+ // Length = length of MCC + length of MNC
+ // length of mcc = 3 (TS 23.003 Section 2.2)
+ return imsi.substring(0, 3 + mncLength);
}
- /**
- * If the timezone is not already set, set it based on the MCC of the SIM.
- * @param mcc Mobile Country Code of the SIM
- */
- private void setTimezoneFromMccIfNeeded(int mcc) {
- String timezone = SystemProperties.get(TIMEZONE_PROPERTY);
- if (timezone == null || timezone.length() == 0) {
- String zoneId = MccTable.defaultTimeZoneForMcc(mcc);
-
- if (zoneId != null && zoneId.length() > 0) {
- // Set time zone based on MCC
- AlarmManager alarm =
- (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
- alarm.setTimeZone(zoneId);
- }
- }
- }
-
- /**
- * If the locale is not already set, set it based on the MCC of the SIM.
- * @param mcc Mobile Country Code of the SIM
- */
- private void setLocaleFromMccIfNeeded(int mcc) {
- String language = MccTable.defaultLanguageForMcc(mcc);
- String country = MccTable.countryCodeForMcc(mcc);
-
- phone.setSystemLocale(language, country);
- }
-
- /**
- * If the number of allowed wifi channels has not been set, set it based on
- * the MCC of the SIM.
- * @param mcc Mobile Country Code of the SIM
- */
- private void setWifiChannelsFromMccIfNeeded(int mcc) {
- int wifiChannels = MccTable.wifiChannelsForMcc(mcc);
-
- if (wifiChannels != 0) {
- Context context = phone.getContext();
- // only set to this default if the user hasn't manually set it
- try {
- Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS);
- } catch (Settings.SettingNotFoundException e) {
- WifiManager wM = (WifiManager)
- context.getSystemService(Context.WIFI_SERVICE);
- // don't persist
- wM.setNumAllowedChannels(wifiChannels, false);
- }
- }
- }
-
- //***** Overridden from Handler
+ // ***** Overridden from Handler
public void handleMessage(Message msg) {
AsyncResult ar;
AdnRecord adn;
@@ -564,14 +497,25 @@
}
Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx");
- ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi);
+
+ if (mncLength == UNKNOWN) {
+ // the SIM has told us all it knows, but it didn't know the mnc length.
+ // guess using the mcc
+ try {
+ int mcc = Integer.parseInt(imsi.substring(0,3));
+ mncLength = MccTable.smallestDigitsMccForMnc(mcc);
+ } catch (NumberFormatException e) {
+ mncLength = UNKNOWN;
+ Log.e(LOG_TAG, "SIMRecords: Corrupt IMSI!");
+ }
+ }
+
+ if (mncLength != UNKNOWN && mncLength != UNINITIALIZED) {
+ // finally have both the imsi and the mncLength and can parse the imsi properly
+ MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
+ }
((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
SimCard.INTENT_VALUE_ICC_IMSI, null);
-
- int mcc = Integer.parseInt(imsi.substring(0, 3));
- setTimezoneFromMccIfNeeded(mcc);
- setLocaleFromMccIfNeeded(mcc);
- setWifiChannelsFromMccIfNeeded(mcc);
break;
case EVENT_GET_MBI_DONE:
@@ -794,12 +738,25 @@
mncLength = (int)data[3] & 0xf;
if (mncLength == 0xf) {
- // Resetting mncLength to 0 to indicate that it is not
- // initialised
- mncLength = 0;
+ if (imsi != null) {
+ try {
+ int mcc = Integer.parseInt(imsi.substring(0,3));
- Log.d(LOG_TAG, "SIMRecords: MNC length not present in EF_AD");
- break;
+ mncLength = MccTable.smallestDigitsMccForMnc(mcc);
+ } catch (NumberFormatException e) {
+ mncLength = UNKNOWN;
+ Log.e(LOG_TAG, "SIMRecords: Corrupt IMSI!");
+ }
+ } else {
+ // Indicate we got this info, but it didn't contain the length.
+ mncLength = UNKNOWN;
+
+ Log.d(LOG_TAG, "SIMRecords: MNC length not present in EF_AD");
+ }
+ }
+ if (imsi != null && mncLength != UNKNOWN) {
+ // finally have both imsi and the length of the mnc and can parse it properly
+ MccTable.updateMccMncConfiguration(phone, imsi.substring(0, 3 + mncLength));
}
break;
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index 6c56682..835cb29 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -16,9 +16,6 @@
package com.android.internal.telephony.gsm;
-import android.app.ActivityManagerNative;
-import android.content.res.Configuration;
-import android.os.RemoteException;
import android.util.Log;
import com.android.internal.telephony.IccCard;
@@ -50,20 +47,4 @@
return ((GSMPhone)mPhone).mSIMRecords.getServiceProviderName();
}
- public void updateImsiConfiguration(String imsi) {
- if (imsi.length() >= 6) {
- Configuration config = new Configuration();
- config.mcc = ((imsi.charAt(0)-'0')*100)
- + ((imsi.charAt(1)-'0')*10)
- + (imsi.charAt(2)-'0');
- config.mnc = ((imsi.charAt(3)-'0')*100)
- + ((imsi.charAt(4)-'0')*10)
- + (imsi.charAt(5)-'0');
- try {
- ActivityManagerNative.getDefault().updateConfiguration(config);
- } catch (RemoteException e) {
- Log.e(mLogTag, "[SimCard] Remote Exception when updating imsi configuration");
- }
- }
- }
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java
index 30543c7..497cf5f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java
@@ -47,7 +47,6 @@
public boolean nextObject() {
if (!hasValidTlvObject) return false;
-
curOffset = curDataOffset + curDataLength;
hasValidTlvObject = parseCurrentTlvObject();
return hasValidTlvObject;
@@ -88,11 +87,12 @@
private boolean parseCurrentTlvObject() {
// 0x00 and 0xff are invalid tag values
- if (record[curOffset] == 0 || (record[curOffset] & 0xff) == 0xff) {
- return false;
- }
try {
+ if (record[curOffset] == 0 || (record[curOffset] & 0xff) == 0xff) {
+ return false;
+ }
+
if ((record[curOffset + 1] & 0xff) < 0x80) {
// one byte length 0 - 0x7f
curDataLength = record[curOffset + 1] & 0xff;
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
new file mode 100644
index 0000000..d27f240
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -0,0 +1,424 @@
+/*
+ * 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.telephony.gsm;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.internal.telephony.AdnRecord;
+import com.android.internal.telephony.AdnRecordCache;
+import com.android.internal.telephony.IccConstants;
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.PhoneBase;
+
+import org.apache.harmony.luni.lang.reflect.ListOfTypes;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class implements reading and parsing USIM records.
+ * Refer to Spec 3GPP TS 31.102 for more details.
+ *
+ * {@hide}
+ */
+public class UsimPhoneBookManager extends Handler implements IccConstants {
+ private static final String LOG_TAG = "GSM";
+ private static final boolean DBG = true;
+ private PbrFile mPbrFile;
+ private Boolean mIsPbrPresent;
+ private PhoneBase mPhone;
+ private AdnRecordCache mAdnCache;
+ private Object mLock = new Object();
+ private ArrayList<AdnRecord> mPhoneBookRecords;
+ private boolean mEmailPresentInIap = false;
+ private int mEmailTagNumberInIap = 0;
+ private ArrayList<byte[]> mIapFileRecord;
+ private ArrayList<byte[]> mEmailFileRecord;
+ private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
+
+ private static final int EVENT_PBR_LOAD_DONE = 1;
+ private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
+ private static final int EVENT_IAP_LOAD_DONE = 3;
+ private static final int EVENT_EMAIL_LOAD_DONE = 4;
+
+ private static final int USIM_TYPE1_TAG = 0xA8;
+ private static final int USIM_TYPE2_TAG = 0xA9;
+ private static final int USIM_TYPE3_TAG = 0xAA;
+ private static final int USIM_EFADN_TAG = 0xC0;
+ private static final int USIM_EFIAP_TAG = 0xC1;
+ private static final int USIM_EFEXT1_TAG = 0xC2;
+ private static final int USIM_EFSNE_TAG = 0xC3;
+ private static final int USIM_EFANR_TAG = 0xC4;
+ private static final int USIM_EFPBC_TAG = 0xC5;
+ private static final int USIM_EFGRP_TAG = 0xC6;
+ private static final int USIM_EFAAS_TAG = 0xC7;
+ private static final int USIM_EFGSD_TAG = 0xC8;
+ private static final int USIM_EFUID_TAG = 0xC9;
+ private static final int USIM_EFEMAIL_TAG = 0xCA;
+ private static final int USIM_EFCCP1_TAG = 0xCB;
+
+ public UsimPhoneBookManager(PhoneBase phone, AdnRecordCache cache) {
+ mPhone = phone;
+ mPhoneBookRecords = new ArrayList<AdnRecord>();
+ mPbrFile = null;
+ // We assume its present, after the first read this is updated.
+ // So we don't have to read from UICC if its not present on subsequent reads.
+ mIsPbrPresent = true;
+ mAdnCache = cache;
+ }
+
+ public void reset() {
+ mPhoneBookRecords.clear();
+ mIapFileRecord = null;
+ mEmailFileRecord = null;
+ mPbrFile = null;
+ mIsPbrPresent = true;
+ }
+
+ public ArrayList<AdnRecord> loadEfFilesFromUsim() {
+ synchronized (mLock) {
+ if (!mPhoneBookRecords.isEmpty()) return mPhoneBookRecords;
+ if (!mIsPbrPresent) return null;
+
+ // Check if the PBR file is present in the cache, if not read it
+ // from the USIM.
+ if (mPbrFile == null) {
+ readPbrFileAndWait();
+ }
+
+ if (mPbrFile == null) return null;
+
+ int numRecs = mPbrFile.mFileIds.size();
+ for (int i = 0; i < numRecs; i++) {
+ readAdnFileAndWait(i);
+ readEmailFileAndWait(i);
+ }
+ // All EF files are loaded, post the response.
+ }
+ return mPhoneBookRecords;
+ }
+
+ private void readPbrFileAndWait() {
+ mPhone.getIccFileHandler().loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
+ }
+ }
+
+ private void readEmailFileAndWait(int recNum) {
+ Map <Integer,Integer> fileIds;
+ fileIds = mPbrFile.mFileIds.get(recNum);
+ if (fileIds == null) return;
+
+ if (fileIds.containsKey(USIM_EFEMAIL_TAG)) {
+ int efid = fileIds.get(USIM_EFEMAIL_TAG);
+ // Check if the EFEmail is a Type 1 file or a type 2 file.
+ // If mEmailPresentInIap is true, its a type 2 file.
+ // So we read the IAP file and then read the email records.
+ // instead of reading directly.
+ if (mEmailPresentInIap) {
+ readIapFileAndWait(fileIds.get(USIM_EFIAP_TAG));
+ if (mIapFileRecord == null) {
+ Log.e(LOG_TAG, "Error: IAP file is empty");
+ return;
+ }
+ }
+ // Read the EFEmail file.
+ mPhone.getIccFileHandler().loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
+ obtainMessage(EVENT_EMAIL_LOAD_DONE));
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "Interrupted Exception in readEmailFileAndWait");
+ }
+
+ if (mEmailFileRecord == null) {
+ Log.e(LOG_TAG, "Error: Email file is empty");
+ return;
+ }
+ updatePhoneAdnRecord();
+ }
+
+ }
+
+ private void readIapFileAndWait(int efid) {
+ mPhone.getIccFileHandler().loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "Interrupted Exception in readIapFileAndWait");
+ }
+ }
+
+ private void updatePhoneAdnRecord() {
+ if (mEmailFileRecord == null) return;
+ int numAdnRecs = mPhoneBookRecords.size();
+ if (mIapFileRecord != null) {
+ // The number of records in the IAP file is same as the number of records in ADN file.
+ // The order of the pointers in an EFIAP shall be the same as the order of file IDs
+ // that appear in the TLV object indicated by Tag 'A9' in the reference file record.
+ // i.e value of mEmailTagNumberInIap
+
+ for (int i = 0; i < numAdnRecs; i++) {
+ byte[] record = null;
+ try {
+ record = mIapFileRecord.get(i);
+ } catch (IndexOutOfBoundsException e) {
+ Log.e(LOG_TAG, "Error: Improper ICC card: No IAP record for ADN, continuing");
+ break;
+ }
+ int recNum = record[mEmailTagNumberInIap];
+
+ if (recNum != -1) {
+ String[] emails = new String[1];
+ // SIM record numbers are 1 based
+ emails[0] = readEmailRecord(recNum - 1);
+ AdnRecord rec = mPhoneBookRecords.get(i);
+ if (rec != null) {
+ rec.setEmails(emails);
+ } else {
+ // might be a record with only email
+ rec = new AdnRecord("", "", emails);
+ }
+ mPhoneBookRecords.set(i, rec);
+ }
+ }
+ }
+
+ // ICC cards can be made such that they have an IAP file but all
+ // records are empty. So we read both type 1 and type 2 file
+ // email records, just to be sure.
+
+ int len = mPhoneBookRecords.size();
+ // Type 1 file, the number of records is the same as the number of
+ // records in the ADN file.
+ if (mEmailsForAdnRec == null) {
+ parseType1EmailFile(len);
+ }
+ for (int i = 0; i < numAdnRecs; i++) {
+ ArrayList<String> emailList = null;
+ try {
+ emailList = mEmailsForAdnRec.get(i);
+ } catch (IndexOutOfBoundsException e) {
+ break;
+ }
+ if (emailList == null) continue;
+
+ AdnRecord rec = mPhoneBookRecords.get(i);
+
+ String[] emails = new String[emailList.size()];
+ System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size());
+ rec.setEmails(emails);
+ mPhoneBookRecords.set(i, rec);
+ }
+ }
+
+ void parseType1EmailFile(int numRecs) {
+ mEmailsForAdnRec = new HashMap<Integer, ArrayList<String>>();
+ byte[] emailRec = null;
+ for (int i = 0; i < numRecs; i++) {
+ try {
+ emailRec = mEmailFileRecord.get(i);
+ } catch (IndexOutOfBoundsException e) {
+ Log.e(LOG_TAG, "Error: Improper ICC card: No email record for ADN, continuing");
+ break;
+ }
+ int adnRecNum = emailRec[emailRec.length - 1];
+
+ if (adnRecNum == -1) {
+ continue;
+ }
+
+ String email = readEmailRecord(i);
+
+ if (email == null || email.equals("")) {
+ continue;
+ }
+
+ // SIM record numbers are 1 based.
+ ArrayList<String> val = mEmailsForAdnRec.get(adnRecNum - 1);
+ if (val == null) {
+ val = new ArrayList<String>();
+ }
+ val.add(email);
+ // SIM record numbers are 1 based.
+ mEmailsForAdnRec.put(adnRecNum - 1, val);
+ }
+ }
+
+ private String readEmailRecord(int recNum) {
+ byte[] emailRec = null;
+ try {
+ emailRec = mEmailFileRecord.get(recNum);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+
+ // The length of the record is X+2 byte, where X bytes is the email address
+ String email = IccUtils.adnStringFieldToString(emailRec, 0, emailRec.length - 2);
+ return email;
+ }
+
+ private void readAdnFileAndWait(int recNum) {
+ Map <Integer,Integer> fileIds;
+ fileIds = mPbrFile.mFileIds.get(recNum);
+ if (fileIds == null) return;
+
+ mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
+ fileIds.get(USIM_EFEXT1_TAG), obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
+ }
+ }
+
+ private void createPbrFile(ArrayList<byte[]> records) {
+ if (records == null) {
+ mPbrFile = null;
+ mIsPbrPresent = false;
+ return;
+ }
+ mPbrFile = new PbrFile(records);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+
+ switch(msg.what) {
+ case EVENT_PBR_LOAD_DONE:
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception == null) {
+ createPbrFile((ArrayList<byte[]>)ar.result);
+ }
+ synchronized (mLock) {
+ mLock.notify();
+ }
+ break;
+ case EVENT_USIM_ADN_LOAD_DONE:
+ log("Loading USIM ADN records done");
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception == null) {
+ mPhoneBookRecords.addAll((ArrayList<AdnRecord>)ar.result);
+ }
+ synchronized (mLock) {
+ mLock.notify();
+ }
+ break;
+ case EVENT_IAP_LOAD_DONE:
+ log("Loading USIM IAP records done");
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception == null) {
+ mIapFileRecord = ((ArrayList<byte[]>)ar.result);
+ }
+ synchronized (mLock) {
+ mLock.notify();
+ }
+ break;
+ case EVENT_EMAIL_LOAD_DONE:
+ log("Loading USIM Email records done");
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception == null) {
+ mEmailFileRecord = ((ArrayList<byte[]>)ar.result);
+ }
+
+ synchronized (mLock) {
+ mLock.notify();
+ }
+ break;
+ }
+ }
+
+ private class PbrFile {
+ // RecNum <EF Tag, efid>
+ HashMap<Integer,Map<Integer,Integer>> mFileIds;
+
+ PbrFile(ArrayList<byte[]> records) {
+ mFileIds = new HashMap<Integer, Map<Integer, Integer>>();
+ SimTlv recTlv;
+ int recNum = 0;
+ for (byte[] record: records) {
+ recTlv = new SimTlv(record, 0, record.length);
+ parseTag(recTlv, recNum);
+ recNum ++;
+ }
+ }
+
+ void parseTag(SimTlv tlv, int recNum) {
+ SimTlv tlvEf;
+ int tag;
+ byte[] data;
+ Map<Integer, Integer> val = new HashMap<Integer, Integer>();
+ do {
+ tag = tlv.getTag();
+ switch(tag) {
+ case USIM_TYPE1_TAG: // A8
+ case USIM_TYPE3_TAG: // AA
+ case USIM_TYPE2_TAG: // A9
+ data = tlv.getData();
+ tlvEf = new SimTlv(data, 0, data.length);
+ parseEf(tlvEf, val, tag);
+ break;
+ }
+ } while (tlv.nextObject());
+ mFileIds.put(recNum, val);
+ }
+
+ void parseEf(SimTlv tlv, Map<Integer, Integer> val, int parentTag) {
+ int tag;
+ byte[] data;
+ int tagNumberWithinParentTag = 0;
+ do {
+ tag = tlv.getTag();
+ if (parentTag == USIM_TYPE2_TAG && tag == USIM_EFEMAIL_TAG) {
+ mEmailPresentInIap = true;
+ mEmailTagNumberInIap = tagNumberWithinParentTag;
+ }
+ switch(tag) {
+ case USIM_EFEMAIL_TAG:
+ case USIM_EFADN_TAG:
+ case USIM_EFEXT1_TAG:
+ case USIM_EFANR_TAG:
+ case USIM_EFPBC_TAG:
+ case USIM_EFGRP_TAG:
+ case USIM_EFAAS_TAG:
+ case USIM_EFGSD_TAG:
+ case USIM_EFUID_TAG:
+ case USIM_EFCCP1_TAG:
+ case USIM_EFIAP_TAG:
+ case USIM_EFSNE_TAG:
+ data = tlv.getData();
+ int efid = data[0] << 8 | data[1];
+ val.put(tag, efid);
+ break;
+ }
+ tagNumberWithinParentTag ++;
+ } while(tlv.nextObject());
+ }
+ }
+
+ private void log(String msg) {
+ if(DBG) Log.d(LOG_TAG, msg);
+ }
+}
diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java
index 4bd9528..5c66169 100644
--- a/test-runner/android/test/IsolatedContext.java
+++ b/test-runner/android/test/IsolatedContext.java
@@ -4,6 +4,7 @@
import android.accounts.AccountManager;
import android.accounts.OnAccountsUpdatedListener;
+import android.accounts.Account;
import android.content.ContextWrapper;
import android.content.ContentResolver;
import android.content.Intent;
@@ -101,6 +102,10 @@
Handler handler, boolean updateImmediately) {
// do nothing
}
+
+ public Account[] getAccounts() {
+ return new Account[]{};
+ }
}
@Override
public File getFilesDir() {
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java b/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
index 875376a..b2f1ded 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/MccTableTest.java
@@ -16,7 +16,7 @@
package com.android.unit_tests;
-import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.MccTable;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
diff --git a/tests/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk
new file mode 100644
index 0000000..f2c07b3
--- /dev/null
+++ b/tests/BrowserPowerTest/Android.mk
@@ -0,0 +1,30 @@
+# Copyright 2008, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := BrowserPowerTests
+
+#LOCAL_INSTRUMENTATION_FOR := browserpowertest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/BrowserPowerTest/AndroidManifest.xml b/tests/BrowserPowerTest/AndroidManifest.xml
new file mode 100644
index 0000000..43eeaad
--- /dev/null
+++ b/tests/BrowserPowerTest/AndroidManifest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.browserpowertest">
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="PowerTestActivity" android:label="Power">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.TEST" />
+ </intent-filter>
+ </activity>
+ </application>
+ <!--
+ This declares that this app uses the instrumentation test runner targeting
+ the package of browserpowertest. To run the tests use the command:
+ "adb shell am instrument -w com.android.browserpowertest/.PowerTestRunner"
+ -->
+ <instrumentation android:name=".PowerTestRunner"
+ android:targetPackage="com.android.browserpowertest"
+ android:label="Test runner for Browser Power Tests."
+ />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_SDCARD" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+</manifest>
diff --git a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java
new file mode 100644
index 0000000..74ac865f
--- /dev/null
+++ b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java
@@ -0,0 +1,51 @@
+package com.android.browserpowertest;
+
+import android.content.Intent;
+import android.app.Instrumentation;
+import android.os.Handler;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import junit.framework.*;
+
+public class PowerMeasurement extends ActivityInstrumentationTestCase2<PowerTestActivity> {
+
+ private static final String LOGTAG = "PowerMeasurement";
+ private static final String PKG_NAME = "com.android.browserpowertest";
+ private static final String TESTING_URL = "http://www.espn.com";
+ private static final int TIME_OUT = 2 * 60 * 1000;
+ private static final int DELAY = 0;
+
+ public PowerMeasurement() {
+ super(PKG_NAME, PowerTestActivity.class);
+ }
+
+ public void testPageLoad() throws Throwable {
+ Instrumentation mInst = getInstrumentation();
+ PowerTestActivity act = getActivity();
+
+ Intent intent = new Intent(mInst.getContext(), PowerTestActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ long start = System.currentTimeMillis();
+ PowerTestActivity activity = (PowerTestActivity)mInst.startActivitySync(
+ intent);
+ activity.reset();
+ //send a message with the new URL
+ Handler handler = activity.getHandler();
+ Message msg = handler.obtainMessage(
+ PowerTestActivity.MSG_NAVIGATE, TIME_OUT, DELAY);
+ msg.getData().putString(PowerTestActivity.MSG_NAV_URL, TESTING_URL);
+ msg.getData().putBoolean(PowerTestActivity.MSG_NAV_LOGTIME, true);
+
+ handler.sendMessage(msg);
+ boolean timeoutFlag = activity.waitUntilDone();
+ long end = System.currentTimeMillis();
+ assertFalse(TESTING_URL + " failed to load", timeoutFlag);
+ boolean pageErrorFlag = activity.getPageError();
+ assertFalse(TESTING_URL + " is not available, either network is down or the server is down",
+ pageErrorFlag);
+ Log.v(LOGTAG, "Page is loaded in " + activity.getPageLoadTime() + " ms.");
+
+ activity.finish();
+ }
+}
diff --git a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestActivity.java b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestActivity.java
new file mode 100644
index 0000000..77e390b
--- /dev/null
+++ b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestActivity.java
@@ -0,0 +1,253 @@
+package com.android.browserpowertest;
+
+import android.app.Activity;
+import android.app.ActivityThread;
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.webkit.WebSettings.LayoutAlgorithm;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+public class PowerTestActivity extends Activity {
+
+ public static final String LOGTAG = "PowerTestActivity";
+ public static final String PARAM_URL = "URL";
+ public static final String PARAM_TIMEOUT = "Timeout";
+ public static final int RESULT_TIMEOUT = 0xDEAD;
+ public static final int MSG_TIMEOUT = 0xC001;
+ public static final int MSG_NAVIGATE = 0xC002;
+ public static final String MSG_NAV_URL = "url";
+ public static final String MSG_NAV_LOGTIME = "logtime";
+
+ private WebView webView;
+ private SimpleWebViewClient webViewClient;
+ private SimpleChromeClient chromeClient;
+ private Handler handler;
+ private boolean timeoutFlag;
+ private boolean logTime;
+ private boolean pageDone;
+ private Object pageDoneLock;
+ private int pageStartCount;
+ private int manualDelay;
+ private long startTime;
+ private long pageLoadTime;
+ private PageDoneRunner pageDoneRunner = new PageDoneRunner();
+
+ public PowerTestActivity() {
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Log.v(LOGTAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
+
+ LinearLayout contentView = new LinearLayout(this);
+ contentView.setOrientation(LinearLayout.VERTICAL);
+ setContentView(contentView);
+ setTitle("Idle");
+
+ webView = new WebView(this);
+ webView.getSettings().setJavaScriptEnabled(true);
+ webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
+ webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
+
+ webViewClient = new SimpleWebViewClient();
+ chromeClient = new SimpleChromeClient();
+ webView.setWebViewClient(webViewClient);
+ webView.setWebChromeClient(chromeClient);
+
+ contentView.addView(webView, new LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
+
+ handler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_TIMEOUT:
+ handleTimeout();
+ return;
+ case MSG_NAVIGATE:
+ manualDelay = msg.arg2;
+ navigate(msg.getData().getString(MSG_NAV_URL), msg.arg1);
+ logTime = msg.getData().getBoolean(MSG_NAV_LOGTIME);
+ return;
+ }
+ }
+ };
+
+ pageDoneLock = new Object();
+ }
+
+ public void reset() {
+ synchronized (pageDoneLock) {
+ pageDone = false;
+ }
+ timeoutFlag = false;
+ pageStartCount = 0;
+ chromeClient.resetJsTimeout();
+ }
+
+ private void navigate(String url, int timeout) {
+ if(url == null) {
+ Log.v(LOGTAG, "URL is null, cancelling...");
+ finish();
+ }
+ webView.stopLoading();
+ if(logTime) {
+ webView.clearCache(true);
+ }
+ startTime = System.currentTimeMillis();
+ Log.v(LOGTAG, "Navigating to URL: " + url);
+ webView.loadUrl(url);
+
+ if(timeout != 0) {
+ //set a timer with specified timeout (in ms)
+ handler.sendMessageDelayed(handler.obtainMessage(MSG_TIMEOUT),
+ timeout);
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ Log.v(LOGTAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+ webView.clearCache(true);
+ webView.destroy();
+ }
+
+ private boolean isPageDone() {
+ synchronized (pageDoneLock) {
+ return pageDone;
+ }
+ }
+
+ private void setPageDone(boolean pageDone) {
+ synchronized (pageDoneLock) {
+ this.pageDone = pageDone;
+ pageDoneLock.notifyAll();
+ }
+ }
+
+ private void handleTimeout() {
+ int progress = webView.getProgress();
+ webView.stopLoading();
+ Log.v(LOGTAG, "Page timeout triggered, progress = " + progress);
+ timeoutFlag = true;
+ handler.postDelayed(pageDoneRunner, manualDelay);
+ }
+
+ public boolean waitUntilDone() {
+ validateNotAppThread();
+ synchronized (pageDoneLock) {
+ while(!isPageDone()) {
+ try {
+ pageDoneLock.wait();
+ } catch (InterruptedException ie) {
+ //no-op
+ }
+ }
+ }
+ return timeoutFlag;
+ }
+
+ public Handler getHandler() {
+ return handler;
+ }
+
+ private final void validateNotAppThread() {
+ if (ActivityThread.currentActivityThread() != null) {
+ throw new RuntimeException(
+ "This method can not be called from the main application thread");
+ }
+ }
+
+ public long getPageLoadTime() {
+ return pageLoadTime;
+ }
+
+ public boolean getPageError() {
+ return webViewClient.getPageErrorFlag();
+ }
+
+ class SimpleWebViewClient extends WebViewClient {
+
+ private boolean pageErrorFlag = false;
+
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description,
+ String failingUrl) {
+ pageErrorFlag = true;
+ Log.v(LOGTAG, "WebCore error: code=" + errorCode
+ + ", description=" + description
+ + ", url=" + failingUrl);
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ pageStartCount++;
+ Log.v(LOGTAG, "onPageStarted: " + url);
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ Log.v(LOGTAG, "onPageFinished: " + url);
+ // let handleTimeout take care of finishing the page
+ if(!timeoutFlag)
+ handler.postDelayed(new WebViewStatusChecker(), 500);
+ }
+
+ // return true if the URL is not available or the page is down
+ public boolean getPageErrorFlag() {
+ return pageErrorFlag;
+ }
+ }
+
+ class SimpleChromeClient extends WebChromeClient {
+
+ private int timeoutCounter = 0;
+
+ public void resetJsTimeout() {
+ timeoutCounter = 0;
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ PowerTestActivity.this.setTitle(title);
+ }
+ }
+
+ class WebViewStatusChecker implements Runnable {
+
+ private int initialStartCount;
+
+ public WebViewStatusChecker() {
+ initialStartCount = pageStartCount;
+ }
+
+ public void run() {
+ if (initialStartCount == pageStartCount && !isPageDone()) {
+ handler.removeMessages(MSG_TIMEOUT);
+ webView.stopLoading();
+ handler.postDelayed(pageDoneRunner, manualDelay);
+ }
+ }
+ }
+
+ class PageDoneRunner implements Runnable {
+
+ public void run() {
+ Log.v(LOGTAG, "Finishing URL: " + webView.getUrl());
+ pageLoadTime = System.currentTimeMillis() - startTime;
+ setPageDone(true);
+ }
+ }
+}
diff --git a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestRunner.java b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestRunner.java
new file mode 100644
index 0000000..4857209
--- /dev/null
+++ b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerTestRunner.java
@@ -0,0 +1,31 @@
+package com.android.browserpowertest;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import junit.framework.TestSuite;
+
+
+/**
+ * Instrumentation Test Runner for all browser power tests.
+ *
+ * Running power tests:
+ *
+ * adb shell am instrument \
+ * -w com.android.browserpowertest/.PowerTestRunner
+ */
+
+public class PowerTestRunner extends InstrumentationTestRunner {
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(PowerMeasurement.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return PowerTestRunner.class.getClassLoader();
+ }
+
+}