Merge "CameraService: (dis)connect from preview windows"
diff --git a/api/current.txt b/api/current.txt
index 2923805..c20f7e7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -377,9 +377,11 @@
field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
field public static final int drawable = 16843161; // 0x1010199
field public static final int drawableBottom = 16843118; // 0x101016e
+ field public static final int drawableEnd = 16843687; // 0x10103a7
field public static final int drawableLeft = 16843119; // 0x101016f
field public static final int drawablePadding = 16843121; // 0x1010171
field public static final int drawableRight = 16843120; // 0x1010170
+ field public static final int drawableStart = 16843686; // 0x10103a6
field public static final int drawableTop = 16843117; // 0x101016d
field public static final int drawingCacheQuality = 16842984; // 0x10100e8
field public static final int dropDownAnchor = 16843363; // 0x1010263
@@ -1821,6 +1823,7 @@
method public static java.lang.String feedbackTypeToString(int);
method public static java.lang.String flagToString(int);
method public boolean getCanRetrieveWindowContent();
+ method public java.lang.String getDescription();
method public java.lang.String getId();
method public android.content.pm.ResolveInfo getResolveInfo();
method public java.lang.String getSettingsActivityName();
@@ -2254,7 +2257,6 @@
method public abstract void setCustomView(android.view.View);
method public abstract void setCustomView(android.view.View, android.app.ActionBar.LayoutParams);
method public abstract void setCustomView(int);
- method public abstract void setDisplayDisableHomeEnabled(boolean);
method public abstract void setDisplayHomeAsUpEnabled(boolean);
method public abstract void setDisplayOptions(int);
method public abstract void setDisplayOptions(int, int);
@@ -2262,6 +2264,7 @@
method public abstract void setDisplayShowHomeEnabled(boolean);
method public abstract void setDisplayShowTitleEnabled(boolean);
method public abstract void setDisplayUseLogoEnabled(boolean);
+ method public abstract void setHomeButtonEnabled(boolean);
method public abstract void setIcon(int);
method public abstract void setIcon(android.graphics.drawable.Drawable);
method public abstract void setListNavigationCallbacks(android.widget.SpinnerAdapter, android.app.ActionBar.OnNavigationListener);
@@ -2274,7 +2277,6 @@
method public abstract void setTitle(java.lang.CharSequence);
method public abstract void setTitle(int);
method public abstract void show();
- field public static final int DISPLAY_DISABLE_HOME = 32; // 0x20
field public static final int DISPLAY_HOME_AS_UP = 4; // 0x4
field public static final int DISPLAY_SHOW_CUSTOM = 16; // 0x10
field public static final int DISPLAY_SHOW_HOME = 2; // 0x2
@@ -8936,6 +8938,8 @@
method public java.lang.String flatten();
method public java.lang.String get(java.lang.String);
method public java.lang.String getAntibanding();
+ method public boolean getAutoExposureLock();
+ method public boolean getAutoWhiteBalanceLock();
method public java.lang.String getColorEffect();
method public int getExposureCompensation();
method public float getExposureCompensationStep();
@@ -8981,6 +8985,8 @@
method public java.lang.String getWhiteBalance();
method public int getZoom();
method public java.util.List<java.lang.Integer> getZoomRatios();
+ method public boolean isAutoExposureLockSupported();
+ method public boolean isAutoWhiteBalanceLockSupported();
method public boolean isSmoothZoomSupported();
method public boolean isZoomSupported();
method public void remove(java.lang.String);
@@ -8988,6 +8994,8 @@
method public void set(java.lang.String, java.lang.String);
method public void set(java.lang.String, int);
method public void setAntibanding(java.lang.String);
+ method public void setAutoExposureLock(boolean);
+ method public void setAutoWhiteBalanceLock(boolean);
method public void setColorEffect(java.lang.String);
method public void setExposureCompensation(int);
method public void setFlashMode(java.lang.String);
@@ -11956,6 +11964,8 @@
public final class NdefRecord implements android.os.Parcelable {
ctor public NdefRecord(short, byte[], byte[], byte[]);
ctor public NdefRecord(byte[]) throws android.nfc.FormatException;
+ method public static android.nfc.NdefRecord createUri(android.net.Uri);
+ method public static android.nfc.NdefRecord createUri(java.lang.String);
method public int describeContents();
method public byte[] getId();
method public byte[] getPayload();
@@ -13918,6 +13928,10 @@
public static class Debug.MemoryInfo implements android.os.Parcelable {
ctor public Debug.MemoryInfo();
method public int describeContents();
+ method public static java.lang.String getOtherLabel(int);
+ method public int getOtherPrivateDirty(int);
+ method public int getOtherPss(int);
+ method public int getOtherSharedDirty(int);
method public int getTotalPrivateDirty();
method public int getTotalPss();
method public int getTotalSharedDirty();
@@ -14026,6 +14040,7 @@
method public void dispatchMessage(android.os.Message);
method public final void dump(android.util.Printer, java.lang.String);
method public final android.os.Looper getLooper();
+ method public java.lang.String getMessageName(android.os.Message);
method public void handleMessage(android.os.Message);
method public final boolean hasMessages(int);
method public final boolean hasMessages(int, java.lang.Object);
@@ -14095,13 +14110,13 @@
public class Looper {
method public void dump(android.util.Printer, java.lang.String);
- method public static final synchronized android.os.Looper getMainLooper();
+ method public static synchronized android.os.Looper getMainLooper();
method public java.lang.Thread getThread();
- method public static final void loop();
- method public static final android.os.Looper myLooper();
- method public static final android.os.MessageQueue myQueue();
- method public static final void prepare();
- method public static final void prepareMainLooper();
+ method public static void loop();
+ method public static android.os.Looper myLooper();
+ method public static android.os.MessageQueue myQueue();
+ method public static void prepare();
+ method public static void prepareMainLooper();
method public void quit();
method public void setMessageLogging(android.util.Printer);
}
@@ -14392,7 +14407,7 @@
method public static final void sendSignal(int, int);
method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
- method public static final boolean supportsProcesses();
+ method public static final deprecated boolean supportsProcesses();
field public static final int BLUETOOTH_GID = 2000; // 0x7d0
field public static final int FIRST_APPLICATION_UID = 10000; // 0x2710
field public static final int LAST_APPLICATION_UID = 99999; // 0x1869f
@@ -15748,6 +15763,7 @@
public static final class ContactsContract.CommonDataKinds.Photo implements android.provider.ContactsContract.DataColumnsWithJoins {
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
field public static final java.lang.String PHOTO = "data15";
+ field public static final java.lang.String PHOTO_FILE_ID = "data14";
}
public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
@@ -15858,6 +15874,7 @@
method public static android.net.Uri getLookupUri(long, java.lang.String);
method public static android.net.Uri lookupContact(android.content.ContentResolver, android.net.Uri);
method public static void markAsContacted(android.content.ContentResolver, long);
+ method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri, boolean);
method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri);
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final android.net.Uri CONTENT_GROUP_URI;
@@ -15887,7 +15904,9 @@
public static final class ContactsContract.Contacts.Photo implements android.provider.BaseColumns android.provider.ContactsContract.DataColumnsWithJoins {
field public static final java.lang.String CONTENT_DIRECTORY = "photo";
+ field public static final java.lang.String DISPLAY_PHOTO = "display_photo";
field public static final java.lang.String PHOTO = "data15";
+ field public static final java.lang.String PHOTO_FILE_ID = "data14";
}
public static final class ContactsContract.Contacts.StreamItems implements android.provider.ContactsContract.StreamItemsColumns {
@@ -15900,6 +15919,7 @@
field public static final java.lang.String IN_VISIBLE_GROUP = "in_visible_group";
field public static final java.lang.String IS_USER_PROFILE = "is_user_profile";
field public static final java.lang.String LOOKUP_KEY = "lookup";
+ field public static final java.lang.String PHOTO_FILE_ID = "photo_file_id";
field public static final java.lang.String PHOTO_ID = "photo_id";
field public static final java.lang.String PHOTO_THUMBNAIL_URI = "photo_thumb_uri";
field public static final java.lang.String PHOTO_URI = "photo_uri";
@@ -15988,6 +16008,13 @@
field public static final int UNDEFINED = 0; // 0x0
}
+ public static final class ContactsContract.DisplayPhoto {
+ field public static final android.net.Uri CONTENT_MAX_DIMENSIONS_URI;
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String DISPLAY_MAX_DIM = "display_max_dim";
+ field public static final java.lang.String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
+ }
+
public static abstract interface ContactsContract.FullNameStyle {
field public static final int CHINESE = 3; // 0x3
field public static final int CJK = 2; // 0x2
@@ -16006,7 +16033,10 @@
}
protected static abstract interface ContactsContract.GroupsColumns {
+ field public static final java.lang.String ACTION = "action";
+ field public static final java.lang.String ACTION_URI = "action_uri";
field public static final java.lang.String AUTO_ADD = "auto_add";
+ field public static final java.lang.String DATA_SET = "data_set";
field public static final java.lang.String DELETED = "deleted";
field public static final java.lang.String FAVORITES = "favorites";
field public static final java.lang.String GROUP_IS_READ_ONLY = "group_is_read_only";
@@ -16122,6 +16152,10 @@
field public static final java.lang.String CONTENT_DIRECTORY = "data";
}
+ public static final class ContactsContract.RawContacts.DisplayPhoto {
+ field public static final java.lang.String CONTENT_DIRECTORY = "display_photo";
+ }
+
public static final class ContactsContract.RawContacts.Entity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns {
field public static final java.lang.String CONTENT_DIRECTORY = "entity";
field public static final java.lang.String DATA_ID = "data_id";
@@ -16134,6 +16168,7 @@
protected static abstract interface ContactsContract.RawContactsColumns {
field public static final java.lang.String AGGREGATION_MODE = "aggregation_mode";
field public static final java.lang.String CONTACT_ID = "contact_id";
+ field public static final java.lang.String DATA_SET = "data_set";
field public static final java.lang.String DELETED = "deleted";
field public static final java.lang.String RAW_CONTACT_IS_READ_ONLY = "raw_contact_is_read_only";
field public static final java.lang.String RAW_CONTACT_IS_USER_PROFILE = "raw_contact_is_user_profile";
@@ -16668,6 +16703,7 @@
field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
field public static final java.lang.String SYS_PROP_SETTING_VERSION = "sys.settings_secure_version";
+ field public static final java.lang.String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
field public static final java.lang.String TTS_DEFAULT_COUNTRY = "tts_default_country";
field public static final java.lang.String TTS_DEFAULT_LANG = "tts_default_lang";
field public static final java.lang.String TTS_DEFAULT_PITCH = "tts_default_pitch";
@@ -17996,7 +18032,6 @@
public abstract interface SynthesisCallback {
method public abstract int audioAvailable(byte[], int, int);
- method public abstract int completeAudioAvailable(int, int, int, byte[], int, int);
method public abstract int done();
method public abstract void error();
method public abstract int getMaxBufferSize();
@@ -20698,11 +20733,12 @@
method public void set(T, V);
}
- public class SparseArray {
+ public class SparseArray implements java.lang.Cloneable {
ctor public SparseArray();
ctor public SparseArray(int);
method public void append(int, E);
method public void clear();
+ method public android.util.SparseArray<E> clone();
method public void delete(int);
method public E get(int);
method public E get(int, E);
@@ -20717,11 +20753,12 @@
method public E valueAt(int);
}
- public class SparseBooleanArray {
+ public class SparseBooleanArray implements java.lang.Cloneable {
ctor public SparseBooleanArray();
ctor public SparseBooleanArray(int);
method public void append(int, boolean);
method public void clear();
+ method public android.util.SparseBooleanArray clone();
method public void delete(int);
method public boolean get(int);
method public boolean get(int, boolean);
@@ -20733,11 +20770,12 @@
method public boolean valueAt(int);
}
- public class SparseIntArray {
+ public class SparseIntArray implements java.lang.Cloneable {
ctor public SparseIntArray();
ctor public SparseIntArray(int);
method public void append(int, int);
method public void clear();
+ method public android.util.SparseIntArray clone();
method public void delete(int);
method public int get(int);
method public int get(int, int);
@@ -20902,8 +20940,10 @@
public abstract class ActionProvider {
ctor public ActionProvider(android.content.Context);
+ method public boolean hasSubMenu();
method public abstract android.view.View onCreateActionView();
- method public void onPerformDefaultAction(android.view.View);
+ method public boolean onPerformDefaultAction();
+ method public void onPrepareSubMenu(android.view.SubMenu);
}
public abstract interface ContextMenu implements android.view.Menu {
@@ -21999,9 +22039,12 @@
method public android.graphics.SurfaceTexture getSurfaceTexture();
method public android.view.TextureView.SurfaceTextureListener getSurfaceTextureListener();
method public boolean isAvailable();
+ method public android.graphics.Canvas lockCanvas();
+ method public android.graphics.Canvas lockCanvas(android.graphics.Rect);
method protected final void onDraw(android.graphics.Canvas);
method public void setOpaque(boolean);
method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
+ method public void unlockCanvasAndPost(android.graphics.Canvas);
}
public static abstract interface TextureView.SurfaceTextureListener {
@@ -22050,6 +22093,7 @@
method public void buildDrawingCache();
method public void buildDrawingCache(boolean);
method public void buildLayer();
+ method protected boolean canResolveLayoutDirection();
method public boolean canScrollHorizontally(int);
method public boolean canScrollVertically(int);
method public void cancelLongPress();
@@ -22612,8 +22656,10 @@
ctor public ViewDebug();
method public static void dumpCapturedView(java.lang.String, java.lang.Object);
method public static void startHierarchyTracing(java.lang.String, android.view.View);
+ method public static void startLooperProfiling(java.io.File);
method public static void startRecyclerTracing(java.lang.String, android.view.View);
method public static void stopHierarchyTracing();
+ method public static void stopLooperProfiling();
method public static void stopRecyclerTracing();
method public static void trace(android.view.View, android.view.ViewDebug.RecyclerTraceType, int...);
method public static void trace(android.view.View, android.view.ViewDebug.HierarchyTraceType);
@@ -23227,6 +23273,7 @@
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
method public void interrupt();
method public boolean isEnabled();
+ method public boolean isTouchExplorationEnabled();
method public boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
method public void sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
}
@@ -23263,6 +23310,7 @@
method public boolean isSelected();
method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
method public static android.view.accessibility.AccessibilityNodeInfo obtain();
+ method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo);
method public boolean performAction(int);
method public void recycle();
method public void setBoundsInParent(android.graphics.Rect);
@@ -25251,6 +25299,10 @@
method public void setRowCount(int);
method public void setRowOrderPreserved(boolean);
method public void setUseDefaultMargins(boolean);
+ method public static android.widget.GridLayout.Spec spec(int, int, android.widget.GridLayout.Alignment, int);
+ method public static android.widget.GridLayout.Spec spec(int, android.widget.GridLayout.Alignment, int);
+ method public static android.widget.GridLayout.Spec spec(int, int, android.widget.GridLayout.Alignment);
+ method public static android.widget.GridLayout.Spec spec(int, android.widget.GridLayout.Alignment);
field public static final int ALIGN_BOUNDS = 0; // 0x0
field public static final int ALIGN_MARGINS = 1; // 0x1
field public static final android.widget.GridLayout.Alignment BASELINE;
@@ -25269,23 +25321,19 @@
public static abstract class GridLayout.Alignment {
}
- public static class GridLayout.Group {
- ctor public GridLayout.Group(int, int, android.widget.GridLayout.Alignment);
- ctor public GridLayout.Group(int, android.widget.GridLayout.Alignment);
- field public final android.widget.GridLayout.Alignment alignment;
- field public int flexibility;
- }
-
public static class GridLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
- ctor public GridLayout.LayoutParams(android.widget.GridLayout.Group, android.widget.GridLayout.Group);
+ ctor public GridLayout.LayoutParams(android.widget.GridLayout.Spec, android.widget.GridLayout.Spec);
ctor public GridLayout.LayoutParams();
ctor public GridLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
ctor public GridLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
ctor public GridLayout.LayoutParams(android.widget.GridLayout.LayoutParams);
ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
method public void setGravity(int);
- field public android.widget.GridLayout.Group columnGroup;
- field public android.widget.GridLayout.Group rowGroup;
+ field public android.widget.GridLayout.Spec columnSpec;
+ field public android.widget.GridLayout.Spec rowSpec;
+ }
+
+ public static class GridLayout.Spec {
}
public class GridView extends android.widget.AbsListView {
@@ -26076,7 +26124,7 @@
ctor public ShareActionProvider(android.content.Context);
method public android.view.View onCreateActionView();
method public void setShareHistoryFileName(java.lang.String);
- method public void setShareIntent(android.view.View, android.content.Intent);
+ method public void setShareIntent(android.content.Intent);
field public static final java.lang.String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
}
@@ -26417,7 +26465,9 @@
method protected void onTextChanged(java.lang.CharSequence, int, int, int);
method public boolean onTextContextMenuItem(int);
method public void removeTextChangedListener(android.text.TextWatcher);
+ method protected void resetResolvedDrawables();
method protected void resetResolvedLayoutDirection();
+ method protected void resolveDrawables();
method public void setAllCaps(boolean);
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 479b70a..3fb1736 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -157,6 +157,11 @@
String value = nextArgRequired();
intent.putExtra(key, Integer.valueOf(value));
hasIntentInfo = true;
+ } else if (opt.equals("--eu")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ intent.putExtra(key, Uri.parse(value));
+ hasIntentInfo = true;
} else if (opt.equals("--eia")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -1119,6 +1124,7 @@
" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" +
" [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" +
" [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" +
+ " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" +
" [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
" [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 152a7cb..f2be29f 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -82,35 +82,27 @@
virtual void onStarted()
{
sp<ProcessState> proc = ProcessState::self();
- if (proc->supportsProcesses()) {
- LOGV("App process: starting thread pool.\n");
- proc->startThreadPool();
- }
+ LOGV("App process: starting thread pool.\n");
+ proc->startThreadPool();
AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgC, mArgV);
- if (ProcessState::self()->supportsProcesses()) {
- IPCThreadState::self()->stopProcess();
- }
+ IPCThreadState::self()->stopProcess();
}
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
- if (proc->supportsProcesses()) {
- LOGV("App process: starting thread pool.\n");
- proc->startThreadPool();
- }
+ LOGV("App process: starting thread pool.\n");
+ proc->startThreadPool();
}
virtual void onExit(int code)
{
if (mClassName == NULL) {
// if zygote
- if (ProcessState::self()->supportsProcesses()) {
- IPCThreadState::self()->stopProcess();
- }
+ IPCThreadState::self()->stopProcess();
}
AndroidRuntime::onExit(code);
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index a00a212..7d39912 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -5,13 +5,6 @@
bootanimation_main.cpp \
BootAnimation.cpp
-# need "-lrt" on Linux simulator to pick up clock_gettime
-ifeq ($(TARGET_SIMULATOR),true)
- ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt
- endif
-endif
-
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_SHARED_LIBRARIES := \
diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk
index 631c219..f476f5e 100644
--- a/cmds/bugreport/Android.mk
+++ b/cmds/bugreport/Android.mk
@@ -1,5 +1,3 @@
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -10,5 +8,3 @@
LOCAL_SHARED_LIBRARIES := libcutils
include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 431a556..56f1324 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -1,5 +1,3 @@
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -14,5 +12,3 @@
LOCAL_SHARED_LIBRARIES := libcutils
include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index d7a9ef6..f277339 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -1,5 +1,3 @@
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH := $(call my-dir)
common_src_files := \
@@ -41,5 +39,3 @@
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
-
-endif # !simulator
diff --git a/cmds/installd/tests/Android.mk b/cmds/installd/tests/Android.mk
index e53378d..315acdb 100644
--- a/cmds/installd/tests/Android.mk
+++ b/cmds/installd/tests/Android.mk
@@ -2,8 +2,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-ifneq ($(TARGET_SIMULATOR),true)
-
# Build the unit tests.
test_src_files := \
installd_utils_test.cpp
@@ -38,5 +36,3 @@
$(eval LOCAL_MODULE_TAGS := $(module_tags)) \
$(eval include $(BUILD_EXECUTABLE)) \
)
-
-endif
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index bbf6b14..e9ee95d 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -17,19 +17,135 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
-#include <cutils/properties.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/route.h>
+#define LOG_TAG "ip-up-vpn"
+#include <cutils/log.h>
+
+#define DIR "/data/misc/vpn/"
+
+static const char *env(const char *name) {
+ const char *value = getenv(name);
+ return value ? value : "";
+}
+
+static int set_address(struct sockaddr *sa, const char *address) {
+ sa->sa_family = AF_INET;
+ return inet_pton(AF_INET, address, &((struct sockaddr_in *)sa)->sin_addr);
+}
+
+/*
+ * The primary goal is to create a file with VPN parameters. Currently they
+ * are interface, addresses, routes, DNS servers, and search domains. Each
+ * parameter occupies one line in the file, and it can be an empty string or
+ * space-separated values. The order and the format must be consistent with
+ * com.android.server.connectivity.Vpn. Here is an example.
+ *
+ * ppp0
+ * 192.168.1.100/24
+ * 0.0.0.0/0
+ * 192.168.1.1 192.168.1.2
+ * example.org
+ *
+ * The secondary goal is to unify the outcome of VPN. The current baseline
+ * is to have an interface configured with the given address and netmask
+ * and maybe add a host route to protect the tunnel. PPP-based VPN already
+ * does this, but others might not. Routes, DNS servers, and search domains
+ * are handled by the framework since they can be overridden by the users.
+ */
int main(int argc, char **argv)
{
- if (argc > 1 && strlen(argv[1]) > 0) {
- char dns[PROPERTY_VALUE_MAX];
- char *dns1 = getenv("DNS1");
- char *dns2 = getenv("DNS2");
+ FILE *state = fopen(DIR ".tmp", "wb");
+ if (!state) {
+ LOGE("Cannot create state: %s", strerror(errno));
+ return 1;
+ }
- snprintf(dns, sizeof(dns), "%s %s", dns1 ? dns1 : "", dns2 ? dns2 : "");
- property_set("vpn.dns", dns);
- property_set("vpn.via", argv[1]);
+ if (argc >= 6) {
+ /* Invoked by pppd. */
+ fprintf(state, "%s\n", argv[1]);
+ fprintf(state, "%s/32\n", argv[4]);
+ fprintf(state, "0.0.0.0/0\n");
+ fprintf(state, "%s %s\n", env("DNS1"), env("DNS2"));
+ fprintf(state, "\n");
+ } else if (argc == 2) {
+ /* Invoked by racoon. */
+ const char *interface = env("INTERFACE");
+ const char *address = env("INTERNAL_ADDR4");
+ const char *routes = env("SPLIT_INCLUDE_CIDR");
+
+ int s = socket(AF_INET, SOCK_DGRAM, 0);
+ struct rtentry rt;
+ struct ifreq ifr;
+
+ memset(&rt, 0, sizeof(rt));
+ memset(&ifr, 0, sizeof(ifr));
+
+ /* Remove the old host route. There could be more than one. */
+ rt.rt_flags |= RTF_UP | RTF_HOST;
+ if (set_address(&rt.rt_dst, env("REMOTE_ADDR"))) {
+ while (!ioctl(s, SIOCDELRT, &rt));
+ }
+ if (errno != ESRCH) {
+ LOGE("Cannot remove host route: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Create a new host route. */
+ rt.rt_flags |= RTF_GATEWAY;
+ if (!set_address(&rt.rt_gateway, argv[1]) ||
+ (ioctl(s, SIOCADDRT, &rt) && errno != EEXIST)) {
+ LOGE("Cannot create host route: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Bring up the interface. */
+ ifr.ifr_flags = IFF_UP;
+ strncpy(ifr.ifr_name, interface, IFNAMSIZ);
+ if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
+ LOGE("Cannot bring up %s: %s", interface, strerror(errno));
+ return 1;
+ }
+
+ /* Set the address. */
+ if (!set_address(&ifr.ifr_addr, address) ||
+ ioctl(s, SIOCSIFADDR, &ifr)) {
+ LOGE("Cannot set address: %s", strerror(errno));
+ return 1;
+ }
+
+ /* Set the netmask. */
+ if (!set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4")) ||
+ ioctl(s, SIOCSIFNETMASK, &ifr)) {
+ LOGE("Cannot set netmask: %s", strerror(errno));
+ return 1;
+ }
+
+ /* TODO: Send few packets to trigger phase 2? */
+
+ fprintf(state, "%s\n", interface);
+ fprintf(state, "%s/%s\n", address, env("INTERNAL_CIDR4"));
+ fprintf(state, "%s\n", routes[0] ? routes : "0.0.0.0/0");
+ fprintf(state, "%s\n", env("INTERNAL_DNS4_LIST"));
+ fprintf(state, "%s\n", env("DEFAULT_DOMAIN"));
+ } else {
+ LOGE("Cannot parse parameters");
+ return 1;
+ }
+
+ fclose(state);
+ if (chmod(DIR ".tmp", 0444) || rename(DIR ".tmp", DIR "state")) {
+ LOGE("Cannot write state: %s", strerror(errno));
+ return 1;
}
return 0;
}
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
index 67dd9f8..5a9b979 100644
--- a/cmds/keystore/Android.mk
+++ b/cmds/keystore/Android.mk
@@ -14,8 +14,6 @@
# limitations under the License.
#
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -32,5 +30,3 @@
LOCAL_MODULE:= keystore_cli
LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/cmds/rawbu/Android.mk b/cmds/rawbu/Android.mk
index c1be8a4..b580390 100644
--- a/cmds/rawbu/Android.mk
+++ b/cmds/rawbu/Android.mk
@@ -1,7 +1,5 @@
# Copyright 2009 The Android Open Source Project
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -15,5 +13,3 @@
LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk
deleted file mode 100644
index 6a72d10..0000000
--- a/cmds/runtime/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-ifeq ($(TARGET_SIMULATOR),true)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- ServiceManager.cpp \
- SignalHandler.cpp \
- main_runtime.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libutils \
- libbinder \
- libandroid_runtime \
- libcutils \
- libui \
- libsystem_server \
- libhardware_legacy
-
-LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE)
-
-ifeq ($(TARGET_OS),linux)
- LOCAL_CFLAGS += -DXP_UNIX
-endif
-
-LOCAL_MODULE:= runtime
-
-include $(BUILD_EXECUTABLE)
-endif
diff --git a/cmds/runtime/MODULE_LICENSE_APACHE2 b/cmds/runtime/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/cmds/runtime/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/cmds/runtime/NOTICE b/cmds/runtime/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/cmds/runtime/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp
deleted file mode 100644
index b2bef07..0000000
--- a/cmds/runtime/ServiceManager.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-
-#define LOG_TAG "ServiceManager"
-
-#include "ServiceManager.h"
-#include "SignalHandler.h"
-
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-#include <utils/String8.h>
-#include <binder/ProcessState.h>
-
-#include <private/utils/Static.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-
-namespace android {
-
-BServiceManager::BServiceManager()
-{
-}
-
-sp<IBinder> BServiceManager::getService(const String16& name) const
-{
- AutoMutex _l(mLock);
- ssize_t i = mServices.indexOfKey(name);
- LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
- if (i >= 0) return mServices.valueAt(i);
- return NULL;
-}
-
-sp<IBinder> BServiceManager::checkService(const String16& name) const
-{
- AutoMutex _l(mLock);
- ssize_t i = mServices.indexOfKey(name);
- LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i);
- if (i >= 0) return mServices.valueAt(i);
- return NULL;
-}
-
-status_t BServiceManager::addService(const String16& name, const sp<IBinder>& service)
-{
- AutoMutex _l(mLock);
- LOGI("ServiceManager: addService(%s, %p)\n", String8(name).string(), service.get());
- const ssize_t res = mServices.add(name, service);
- if (res >= NO_ERROR) {
- mChanged.broadcast();
- return NO_ERROR;
- }
- return res;
-}
-
-Vector<String16> BServiceManager::listServices()
-{
- Vector<String16> res;
-
- AutoMutex _l(mLock);
- const size_t N = mServices.size();
- for (size_t i=0; i<N; i++) {
- res.add(mServices.keyAt(i));
- }
-
- return res;
-}
-
-}; // namespace android
diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h
deleted file mode 100644
index 090ca6d..0000000
--- a/cmds/runtime/ServiceManager.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-#ifndef ANDROID_SERVICE_MANAGER_H
-#define ANDROID_SERVICE_MANAGER_H
-
-#include <binder/IServiceManager.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BServiceManager : public BnServiceManager
-{
-public:
- BServiceManager();
-
- virtual sp<IBinder> getService( const String16& name) const;
- virtual sp<IBinder> checkService( const String16& name) const;
- virtual status_t addService( const String16& name,
- const sp<IBinder>& service);
- virtual Vector<String16> listServices();
-
-
-private:
- mutable Mutex mLock;
- mutable Condition mChanged;
- sp<IPermissionController> mPermissionController;
- KeyedVector<String16, sp<IBinder> > mServices;
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_SERVICE_MANAGER_H
diff --git a/cmds/runtime/SignalHandler.cpp b/cmds/runtime/SignalHandler.cpp
deleted file mode 100644
index cccaabf..0000000
--- a/cmds/runtime/SignalHandler.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-
-#define LOG_TAG "SignalHandler"
-
-#include "SignalHandler.h"
-
-#include <utils/Atomic.h>
-#include <utils/Debug.h>
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-namespace android {
-
-class SignalHandler::ProcessThread : public Thread
-{
-public:
- ProcessThread(SignalHandler& sh)
- : Thread(false)
- , mOwner(sh)
- {
- }
-
- virtual bool threadLoop()
- {
- char buffer[32];
- read(mOwner.mAvailMsg[0], buffer, sizeof(buffer));
-
- LOGV("Signal command processing thread woke up!");
-
- if (mOwner.mLostCommands) {
- LOGE("Lost %d signals!", mOwner.mLostCommands);
- mOwner.mLostCommands = 0;
- }
-
- int cur;
- while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) {
- if (mOwner.mCommands[cur].filled == 0) {
- LOGV("Command at %d is not yet filled", cur);
- break;
- }
-
- LOGV("Processing command at %d, top is %d",
- cur, mOwner.mCommandTop);
- processCommand(mOwner.mCommands[cur]);
- mOwner.mCommands[cur].filled = 0;
-
- int next = mOwner.mCommandBottom+1;
- if (next >= COMMAND_QUEUE_SIZE) {
- next = 0;
- }
-
- mOwner.mCommandBottom = next;
- }
-
- return true;
- }
-
- void processCommand(const CommandEntry& entry)
- {
- switch (entry.signum) {
- case SIGCHLD: {
- mOwner.mLock.lock();
- ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid);
- ChildHandler ch;
- if (i >= 0) {
- ch = mOwner.mChildHandlers.valueAt(i);
- mOwner.mChildHandlers.removeItemsAt(i);
- }
- mOwner.mLock.unlock();
-
- LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i);
-
- if (i >= 0) {
- int res = waitpid(entry.info.si_pid, NULL, WNOHANG);
- LOGW_IF(res == 0,
- "Received SIGCHLD, but pid %d is not yet stopped",
- entry.info.si_pid);
- if (ch.handler) {
- ch.handler(entry.info.si_pid, ch.userData);
- }
- } else {
- LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid);
- }
- } break;
- }
- }
-
- SignalHandler& mOwner;
-};
-
-
-Mutex SignalHandler::mInstanceLock;
-SignalHandler* SignalHandler::mInstance = NULL;
-
-status_t SignalHandler::setChildHandler(pid_t childPid,
- int tag,
- child_callback_t handler,
- void* userData)
-{
- SignalHandler* const self = getInstance();
-
- self->mLock.lock();
-
- // First make sure this child hasn't already exited.
- pid_t res = waitpid(childPid, NULL, WNOHANG);
- if (res != 0) {
- if (res < 0) {
- LOGW("setChildHandler waitpid of %d failed: %d (%s)",
- childPid, res, strerror(errno));
- } else {
- LOGW("setChildHandler waitpid of %d said %d already dead",
- childPid, res);
- }
-
- // Some kind of error... just handle the exit now.
- self->mLock.unlock();
-
- if (handler) {
- handler(childPid, userData);
- }
-
- // Return an error code -- 0 means it already exited.
- return (status_t)res;
- }
-
- ChildHandler entry;
- entry.childPid = childPid;
- entry.tag = tag;
- entry.handler = handler;
- entry.userData = userData;
-
- // Note: this replaces an existing entry for this pid, if there already
- // is one. This is the required behavior.
- LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p",
- childPid, tag, handler, userData);
- self->mChildHandlers.add(childPid, entry);
-
- self->mLock.unlock();
-
- return NO_ERROR;
-}
-
-void SignalHandler::killAllChildren(int tag)
-{
- SignalHandler* const self = getInstance();
-
- AutoMutex _l (self->mLock);
- const size_t N = self->mChildHandlers.size();
- for (size_t i=0; i<N; i++) {
- const ChildHandler& ch(self->mChildHandlers.valueAt(i));
- if (tag == 0 || ch.tag == tag) {
- const pid_t pid = ch.childPid;
- LOGI("Killing child %d (tag %d)\n", pid, ch.tag);
- kill(pid, SIGKILL);
- }
- }
-}
-
-SignalHandler::SignalHandler()
- : mCommandTop(0)
- , mCommandBottom(0)
- , mLostCommands(0)
-{
- memset(mCommands, 0, sizeof(mCommands));
-
- int res = pipe(mAvailMsg);
- LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno));
-
- mProcessThread = new ProcessThread(*this);
- mProcessThread->run("SignalHandler", PRIORITY_HIGHEST);
-
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_sigaction = sigAction;
- sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO;
- sigaction(SIGCHLD, &sa, NULL);
-}
-
-SignalHandler::~SignalHandler()
-{
-}
-
-SignalHandler* SignalHandler::getInstance()
-{
- AutoMutex _l(mInstanceLock);
- if (mInstance == NULL) {
- mInstance = new SignalHandler();
- }
- return mInstance;
-}
-
-void SignalHandler::sigAction(int signum, siginfo_t* info, void*)
-{
- static const char wakeupMsg[1] = { 0xff };
-
- // If our signal handler is being called, then we know we have
- // already initialized the SignalHandler class and thus mInstance
- // is valid.
- SignalHandler* const self = mInstance;
-
- // XXX This is not safe!
- #if 0
- LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n",
- signum,
- info->si_signo, info->si_errno, info->si_code,
- info->si_pid);
- #endif
-
- int32_t oldTop, newTop;
-
- // Find the next command slot...
- do {
- oldTop = self->mCommandTop;
-
- newTop = oldTop + 1;
- if (newTop >= COMMAND_QUEUE_SIZE) {
- newTop = 0;
- }
-
- if (newTop == self->mCommandBottom) {
- // The buffer is filled up! Ouch!
- // XXX This is not safe!
- #if 0
- LOGE("Command buffer overflow! newTop=%d\n", newTop);
- #endif
- android_atomic_add(1, &self->mLostCommands);
- write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
- return;
- }
- } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop)));
-
- // Fill in the command data...
- self->mCommands[oldTop].signum = signum;
- self->mCommands[oldTop].info = *info;
-
- // And now make this command available.
- self->mCommands[oldTop].filled = 1;
-
- // Wake up the processing thread.
- write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg));
-}
-
-}; // namespace android
-
diff --git a/cmds/runtime/SignalHandler.h b/cmds/runtime/SignalHandler.h
deleted file mode 100644
index 7f4ef8e..0000000
--- a/cmds/runtime/SignalHandler.h
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-#ifndef ANDROID_SIGNAL_HANDLER_H
-#define ANDROID_SIGNAL_HANDLER_H
-
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-#include <signal.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-enum {
- DEFAULT_PROCESS_TAG = 1
-};
-
-class SignalHandler
-{
-public:
- typedef void (*child_callback_t)(pid_t child, void* userData);
-
- /**
- * Set a handler for when a child process exits. By calling
- * this, a waitpid() will be done when the child exits to remove
- * it from the zombie state. You can also optionally specify a
- * handler to be called when the child exits.
- *
- * If there is already a handler for this child process, it is
- * replaced by this new handler. In this case the old handler's
- * function is not called.
- *
- * @param childPid Process ID of child to watch.
- * @param childTag User-defined tag for this child. Must be
- * greater than zero.
- * @param handler If non-NULL, this will be called when the
- * child exits. It may be called in either a
- * separate signal handling thread, or
- * immediately if the child has already exited.
- * @param userData Propageted as-is to handler.
- *
- * @return status_t NO_ERROR if all is well.
- */
- static status_t setChildHandler(pid_t childPid,
- int childTag = DEFAULT_PROCESS_TAG,
- child_callback_t handler = NULL,
- void* userData = NULL);
-
- /**
- * Kill all of the child processes for which we have a waiting
- * handler, whose tag is the given value. If tag is 0, all
- * children are killed.
- *
- * @param tag
- */
- static void killAllChildren(int tag = 0);
-
-private:
- SignalHandler();
- ~SignalHandler();
-
- static SignalHandler* getInstance();
-
- static void sigAction(int, siginfo_t*, void*);
-
- // --------------------------------------------------
- // Shared state... all of this is protected by mLock.
- // --------------------------------------------------
-
- mutable Mutex mLock;
-
- struct ChildHandler
- {
- pid_t childPid;
- int tag;
- child_callback_t handler;
- void* userData;
- };
- KeyedVector<pid_t, ChildHandler> mChildHandlers;
-
- // --------------------------------------------------
- // Commmand queue... data is inserted by the signal
- // handler using atomic ops, and retrieved by the
- // signal processing thread. Because these are touched
- // by the signal handler, no lock is used.
- // --------------------------------------------------
-
- enum {
- COMMAND_QUEUE_SIZE = 64
- };
- struct CommandEntry
- {
- int filled;
- int signum;
- siginfo_t info;
- };
-
- // The top of the queue. This is incremented atomically by the
- // signal handler before placing a command in the queue.
- volatile int32_t mCommandTop;
-
- // The bottom of the queue. Only modified by the processing
- // thread; the signal handler reads it only to determine if the
- // queue is full.
- int32_t mCommandBottom;
-
- // Incremented each time we receive a signal and don't have room
- // for it on the command queue.
- volatile int32_t mLostCommands;
-
- // The command processing thread.
- class ProcessThread;
- sp<Thread> mProcessThread;
-
- // Pipe used to tell command processing thread when new commands.
- // are available. The thread blocks on the read end, the signal
- // handler writes when it enqueues new commands.
- int mAvailMsg[2];
-
- // The commands.
- CommandEntry mCommands[COMMAND_QUEUE_SIZE];
-
- // --------------------------------------------------
- // Singleton.
- // --------------------------------------------------
-
- static Mutex mInstanceLock;
- static SignalHandler* mInstance;
-};
-
-// ----------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_SIGNAL_HANDLER_H
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
deleted file mode 100644
index dbff095..0000000
--- a/cmds/runtime/main_runtime.cpp
+++ /dev/null
@@ -1,515 +0,0 @@
-//
-// Copyright 2005 The Android Open Source Project
-//
-// Main entry point for runtime.
-//
-
-#include "ServiceManager.h"
-#include "SignalHandler.h"
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <utils/Log.h>
-#include <cutils/zygote.h>
-
-#include <cutils/properties.h>
-
-#include <private/utils/Static.h>
-
-#include <surfaceflinger/ISurfaceComposer.h>
-
-#include <android_runtime/AndroidRuntime.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <getopt.h>
-#include <signal.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <linux/capability.h>
-#include <linux/ioctl.h>
-#ifdef HAVE_ANDROID_OS
-# include <linux/android_alarm.h>
-#endif
-
-#undef LOG_TAG
-#define LOG_TAG "runtime"
-
-static const char* ZYGOTE_ARGV[] = {
- "--setuid=1000",
- "--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
- /* CAP_SYS_TTY_CONFIG & CAP_SYS_RESOURCE & CAP_NET_BROADCAST &
- * CAP_NET_ADMIN & CAP_NET_RAW & CAP_NET_BIND_SERVICE & CAP_KILL &
- * CAP_SYS_BOOT CAP_SYS_NICE
- */
- "--capabilities=96549920,96549920",
- "--runtime-init",
- "--nice-name=system_server",
- "com.android.server.SystemServer"
-};
-
-using namespace android;
-
-extern "C" status_t system_init();
-
-enum {
- SYSTEM_PROCESS_TAG = DEFAULT_PROCESS_TAG+1
-};
-
-extern Mutex gEventQMutex;
-extern Condition gEventQCondition;
-
-namespace android {
-
-extern void set_finish_init_func(void (*func)());
-
-
-/**
- * This class is used to kill this process (runtime) when the system_server dies.
- */
-class GrimReaper : public IBinder::DeathRecipient {
-public:
- GrimReaper() { }
-
- virtual void binderDied(const wp<IBinder>& who)
- {
- LOGI("Grim Reaper killing runtime...");
- kill(getpid(), SIGKILL);
- }
-};
-
-extern void QuickTests();
-
-/*
- * Print usage info.
- */
-static void usage(const char* argv0)
-{
- fprintf(stderr,
- "Usage: runtime [-g gamma] [-l logfile] [-n] [-s]\n"
- " [-j app-component] [-v app-verb] [-d app-data]\n"
- "\n"
- "-l: File to send log messages to\n"
- "-n: Don't print to stdout/stderr\n"
- "-s: Force single-process mode\n"
- "-j: Custom home app component name\n"
- "-v: Custom home app intent verb\n"
- "-d: Custom home app intent data\n"
- );
- exit(1);
-}
-
-// Selected application to run.
-static const char* gInitialApplication = NULL;
-static const char* gInitialVerb = NULL;
-static const char* gInitialData = NULL;
-
-static void writeStringToParcel(Parcel& parcel, const char* str)
-{
- if (str) {
- parcel.writeString16(String16(str));
- } else {
- parcel.writeString16(NULL, 0);
- }
-}
-
-/*
- * Starting point for program logic.
- *
- * Returns with an exit status code (0 on success, nonzero on error).
- */
-static int run(sp<ProcessState>& proc)
-{
- // Temporary hack to call startRunning() on the activity manager.
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> am;
- while ((am = sm->getService(String16("activity"))) == NULL) {
- LOGI("Waiting for activity manager...");
- }
- Parcel data, reply;
- // XXX Need to also supply a package name for this to work again.
- // IActivityManager::getInterfaceDescriptor() is the token for invoking on this interface;
- // hardcoding it here avoids having to link with the full Activity Manager library
- data.writeInterfaceToken(String16("android.app.IActivityManager"));
- writeStringToParcel(data, NULL);
- writeStringToParcel(data, gInitialApplication);
- writeStringToParcel(data, gInitialVerb);
- writeStringToParcel(data, gInitialData);
-LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager");
- am->transact(IBinder::FIRST_CALL_TRANSACTION, data, &reply);
-
- if (proc->supportsProcesses()) {
- // Now we link to the Activity Manager waiting for it to die. If it does kill ourself.
- // initd will restart this process and bring the system back up.
- sp<GrimReaper> grim = new GrimReaper();
- am->linkToDeath(grim, grim.get(), 0);
-
- // Now join the thread pool. Note this is needed so that the message enqueued in the driver
- // for the linkToDeath gets processed.
- IPCThreadState::self()->joinThreadPool();
- } else {
- // Keep this thread running forever...
- while (1) {
- usleep(100000);
- }
- }
- return 1;
-}
-
-
-}; // namespace android
-
-
-/*
- * Post-system-process initialization.
- *
- * This function continues initialization after the system process
- * has been initialized. It needs to be separate because the system
- * initialization needs to care of starting the Android runtime if it is not
- * running in its own process, which doesn't return until the runtime is
- * being shut down. So it will call back to here from inside of Dalvik,
- * to allow us to continue booting up.
- */
-static void finish_system_init(sp<ProcessState>& proc)
-{
- // If we are running multiprocess, we now need to have the
- // thread pool started here. We don't do this in boot_init()
- // because when running single process we need to start the
- // thread pool after the Android runtime has been started (so
- // the pool uses Dalvik threads).
- if (proc->supportsProcesses()) {
- proc->startThreadPool();
- }
-}
-
-
-// This function can be used to enforce security to different
-// root contexts. For now, we just give every access.
-static bool contextChecker(
- const String16& name, const sp<IBinder>& caller, void* userData)
-{
- return true;
-}
-
-/*
- * Initialization of boot services.
- *
- * This is where we perform initialization of all of our low-level
- * boot services. Most importantly, here we become the context
- * manager and use that to publish the service manager that will provide
- * access to all other services.
- */
-static void boot_init()
-{
- LOGI("Entered boot_init()!\n");
-
- sp<ProcessState> proc(ProcessState::self());
- LOGD("ProcessState: %p\n", proc.get());
- proc->becomeContextManager(contextChecker, NULL);
-
- if (proc->supportsProcesses()) {
- LOGI("Binder driver opened. Multiprocess enabled.\n");
- } else {
- LOGI("Binder driver not found. Processes not supported.\n");
- }
-
- sp<BServiceManager> sm = new BServiceManager;
- proc->setContextObject(sm);
-}
-
-/*
- * Redirect stdin/stdout/stderr to /dev/null.
- */
-static void redirectStdFds(void)
-{
- int fd = open("/dev/null", O_RDWR, 0);
- if (fd < 0) {
- LOGW("Unable to open /dev/null: %s\n", strerror(errno));
- } else {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- close(fd);
- }
-}
-
-static int hasDir(const char* dir)
-{
- struct stat s;
- int res = stat(dir, &s);
- if (res == 0) {
- return S_ISDIR(s.st_mode);
- }
- return 0;
-}
-
-static void validateTime()
-{
-#if HAVE_ANDROID_OS
- int fd;
- int res;
- time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
- struct timespec ts;
-
- fd = open("/dev/alarm", O_RDWR);
- if(fd < 0) {
- LOGW("Unable to open alarm driver: %s\n", strerror(errno));
- return;
- }
- res = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts);
- if(res < 0) {
- LOGW("Unable to read rtc, %s\n", strerror(errno));
- }
- else if(ts.tv_sec >= min_time) {
- goto done;
- }
- LOGW("Invalid time detected, %ld set to %ld\n", ts.tv_sec, min_time);
- ts.tv_sec = min_time;
- ts.tv_nsec = 0;
- res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
- if(res < 0) {
- LOGW("Unable to set rtc to %ld: %s\n", ts.tv_sec, strerror(errno));
- }
-done:
- close(fd);
-#endif
-}
-
-#ifndef HAVE_ANDROID_OS
-class QuickRuntime : public AndroidRuntime
-{
-public:
- QuickRuntime() {}
-
- virtual void onStarted()
- {
- printf("QuickRuntime: onStarted\n");
- }
-};
-#endif
-
-static status_t start_process(const char* name);
-
-static void restart_me(pid_t child, void* userData)
-{
- start_process((const char*)userData);
-}
-
-static status_t start_process(const char* name)
-{
- String8 path(name);
- Vector<const char*> args;
- String8 leaf(path.getPathLeaf());
- String8 parentDir(path.getPathDir());
- args.insertAt(leaf.string(), 0);
- args.add(parentDir.string());
- args.add(NULL);
- pid_t child = fork();
- if (child < 0) {
- status_t err = errno;
- LOGE("*** fork of child %s failed: %s", leaf.string(), strerror(err));
- return -errno;
- } else if (child == 0) {
- LOGI("Executing: %s", path.string());
- execv(path.string(), const_cast<char**>(args.array()));
- int err = errno;
- LOGE("Exec failed: %s\n", strerror(err));
- _exit(err);
- } else {
- SignalHandler::setChildHandler(child, DEFAULT_PROCESS_TAG,
- restart_me, (void*)name);
- }
- return -errno;
-}
-
-/*
- * Application entry point.
- *
- * Parse arguments, set some values, and pass control off to Run().
- *
- * This is redefined to "SDL_main" on SDL simulator builds, and
- * "runtime_main" on wxWidgets builds.
- */
-extern "C"
-int main(int argc, char* const argv[])
-{
- bool singleProcess = false;
- const char* logFile = NULL;
- int ic;
- int result = 1;
- pid_t systemPid;
-
- sp<ProcessState> proc;
-
-#ifndef HAVE_ANDROID_OS
- /* Set stdout/stderr to unbuffered for MinGW/MSYS. */
- //setvbuf(stdout, NULL, _IONBF, 0);
- //setvbuf(stderr, NULL, _IONBF, 0);
-
- LOGI("commandline args:\n");
- for (int i = 0; i < argc; i++)
- LOGI(" %2d: '%s'\n", i, argv[i]);
-#endif
-
- while (1) {
- ic = getopt(argc, argv, "g:j:v:d:l:ns");
- if (ic < 0)
- break;
-
- switch (ic) {
- case 'g':
- break;
- case 'j':
- gInitialApplication = optarg;
- break;
- case 'v':
- gInitialVerb = optarg;
- break;
- case 'd':
- gInitialData = optarg;
- break;
- case 'l':
- logFile = optarg;
- break;
- case 'n':
- redirectStdFds();
- break;
- case 's':
- singleProcess = true;
- break;
- case '?':
- default:
- LOGE("runtime: unrecognized flag -%c\n", ic);
- usage(argv[0]);
- break;
- }
- }
- if (optind < argc) {
- LOGE("runtime: extra stuff: %s\n", argv[optind]);
- usage(argv[0]);
- }
-
- if (singleProcess) {
- ProcessState::setSingleProcess(true);
- }
-
- if (logFile != NULL) {
- android_logToFile(NULL, logFile);
- }
-
- /*
- * Set up ANDROID_* environment variables.
- *
- * TODO: the use of $ANDROID_PRODUCT_OUT will go away soon.
- */
- static const char* kSystemDir = "/system";
- static const char* kDataDir = "/data";
- static const char* kAppSubdir = "/app";
- const char* out = NULL;
-#ifndef HAVE_ANDROID_OS
- //out = getenv("ANDROID_PRODUCT_OUT");
-#endif
- if (out == NULL)
- out = "";
-
- char* systemDir = (char*) malloc(strlen(out) + strlen(kSystemDir) +1);
- char* dataDir = (char*) malloc(strlen(out) + strlen(kDataDir) +1);
-
- sprintf(systemDir, "%s%s", out, kSystemDir);
- sprintf(dataDir, "%s%s", out, kDataDir);
- setenv("ANDROID_ROOT", systemDir, 1);
- setenv("ANDROID_DATA", dataDir, 1);
-
- char* assetDir = (char*) malloc(strlen(systemDir) + strlen(kAppSubdir) +1);
- sprintf(assetDir, "%s%s", systemDir, kAppSubdir);
-
- LOGI("Startup: sys='%s' asset='%s' data='%s'\n",
- systemDir, assetDir, dataDir);
- free(systemDir);
- free(dataDir);
-
-#ifdef HAVE_ANDROID_OS
- /* set up a process group for easier killing on the device */
- setpgid(0, getpid());
-#endif
-
- // Change to asset dir. This is only necessary if we've changed to
- // a different directory, but there's little harm in doing it regardless.
- //
- // Expecting assets to live in the current dir is not a great idea,
- // because some of our code or one of our libraries could change the
- // directory out from under us. Preserve the behavior for now.
- if (chdir(assetDir) != 0) {
- LOGW("WARNING: could not change dir to '%s': %s\n",
- assetDir, strerror(errno));
- }
- free(assetDir);
-
-#if 0
- // Hack to keep libc from beating the filesystem to death. It's
- // hitting /etc/localtime frequently,
- //
- // This statement locks us into Pacific time. We could do better,
- // but there's not much point until we're sure that the library
- // can't be changed to do more along the lines of what we want.
-#ifndef XP_WIN
- setenv("TZ", "PST+8PDT,M4.1.0/2,M10.5.0/2", true);
-#endif
-#endif
-
- /* track our progress through the boot sequence */
- const int LOG_BOOT_PROGRESS_START = 3000;
- LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
- ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
-
- validateTime();
-
- proc = ProcessState::self();
-
- boot_init();
-
- /* If we are in multiprocess mode, have zygote spawn the system
- * server process and call system_init(). If we are running in
- * single process mode just call system_init() directly.
- */
- if (proc->supportsProcesses()) {
- // If stdio logging is on, system_server should not inherit our stdio
- // The dalvikvm instance will copy stdio to the log on its own
- char propBuf[PROPERTY_VALUE_MAX];
- bool logStdio = false;
- property_get("log.redirect-stdio", propBuf, "");
- logStdio = (strcmp(propBuf, "true") == 0);
-
- zygote_run_oneshot((int)(!logStdio),
- sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
- ZYGOTE_ARGV);
-
- //start_process("/system/bin/mediaserver");
-
- } else {
-#ifndef HAVE_ANDROID_OS
- QuickRuntime* runt = new QuickRuntime();
- runt->start("com/android/server/SystemServer",
- "" /* spontaneously fork system server from zygote */);
-#endif
- }
-
- //printf("+++ post-zygote\n");
-
- finish_system_init(proc);
- run(proc);
-
-bail:
- if (proc != NULL) {
- proc->setContextObject(NULL);
- }
-
- return 0;
-}
diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk
index 99c7aeb..73a8e22 100644
--- a/cmds/screenshot/Android.mk
+++ b/cmds/screenshot/Android.mk
@@ -1,5 +1,3 @@
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -12,5 +10,3 @@
LOCAL_C_INCLUDES += external/zlib
include $(BUILD_EXECUTABLE)
-
-endif
diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk
index fe5929b..ea80c7d 100644
--- a/cmds/servicemanager/Android.mk
+++ b/cmds/servicemanager/Android.mk
@@ -1,4 +1,3 @@
-ifneq ($(TARGET_SIMULATOR),true)
LOCAL_PATH:= $(call my-dir)
#include $(CLEAR_VARS)
@@ -14,4 +13,3 @@
LOCAL_CFLAGS += -DLVMX
endif
include $(BUILD_EXECUTABLE)
-endif
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 1a5b7f3..b42f1c5 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -793,7 +793,9 @@
MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
- MEDIA_MIMETYPE_AUDIO_MPEG
+ MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
+ MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
+ MEDIA_MIMETYPE_VIDEO_VPX
};
for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]);
@@ -803,6 +805,7 @@
Vector<CodecCapabilities> results;
CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
true, // queryDecoders
+ false, // hwCodecOnly
&results), (status_t)OK);
for (size_t i = 0; i < results.size(); ++i) {
@@ -842,7 +845,12 @@
for (List<IOMX::ComponentInfo>::iterator it = list.begin();
it != list.end(); ++it) {
- printf("%s\n", (*it).mName.string());
+ printf("%s\t Roles: ", (*it).mName.string());
+ for (List<String8>::iterator itRoles = (*it).mRoles.begin() ;
+ itRoles != (*it).mRoles.end() ; ++itRoles) {
+ printf("%s\t", (*itRoles).string());
+ }
+ printf("\n");
}
}
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index a19711e..59360d3 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -76,23 +76,6 @@
SensorService::instantiate();
}
- // On the simulator, audioflinger et al don't get started the
- // same way as on the device, and we need to start them here
- if (!proc->supportsProcesses()) {
-
- // Start the AudioFlinger
- AudioFlinger::instantiate();
-
- // Start the media playback service
- MediaPlayerService::instantiate();
-
- // Start the camera service
- CameraService::instantiate();
-
- // Start the audio policy service
- AudioPolicyService::instantiate();
- }
-
// And now start the Android runtime. We have to do this bit
// of nastiness because the Android runtime initialization requires
// some of the core system services to already be started.
@@ -117,14 +100,10 @@
}
env->CallStaticVoidMethod(clazz, methodId);
- // If running in our own process, just go into the thread
- // pool. Otherwise, call the initialization finished
- // func to let this process continue its initilization.
- if (proc->supportsProcesses()) {
- LOGI("System server: entering thread pool.\n");
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- LOGI("System server: exiting thread pool.\n");
- }
+ LOGI("System server: entering thread pool.\n");
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ LOGI("System server: exiting thread pool.\n");
+
return NO_ERROR;
}
diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp
index 543f650..d67329d 100644
--- a/cmds/system_server/system_main.cpp
+++ b/cmds/system_server/system_main.cpp
@@ -52,10 +52,5 @@
LOGW("*** Current priority: %d\n", getpriority(PRIO_PROCESS, 0));
setpriority(PRIO_PROCESS, 0, -1);
- #if HAVE_ANDROID_OS
- //setgid(GID_SYSTEM);
- //setuid(UID_SYSTEM);
- #endif
-
system_init();
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index ef4adca..a09607a 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -171,6 +171,11 @@
private boolean mCanRetrieveWindowContent;
/**
+ * Description of the accessibility service.
+ */
+ private String mDescription;
+
+ /**
* Creates a new instance.
*/
public AccessibilityServiceInfo() {
@@ -193,8 +198,6 @@
mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
mResolveInfo = resolveInfo;
- String settingsActivityName = null;
- boolean retrieveScreenContent = false;
XmlResourceParser parser = null;
try {
@@ -242,6 +245,8 @@
mCanRetrieveWindowContent = asAttributes.getBoolean(
com.android.internal.R.styleable.AccessibilityService_canRetrieveWindowContent,
false);
+ mDescription = asAttributes.getString(
+ com.android.internal.R.styleable.AccessibilityService_description);
asAttributes.recycle();
} catch (NameNotFoundException e) {
throw new XmlPullParserException( "Unable to create context for: "
@@ -315,6 +320,18 @@
}
/**
+ * Description of the accessibility service.
+ * <p>
+ * <strong>Statically set from
+ * {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
+ * </p>
+ * @return The description.
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
* {@inheritDoc}
*/
public int describeContents() {
@@ -331,6 +348,7 @@
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
parcel.writeInt(mCanRetrieveWindowContent ? 1 : 0);
+ parcel.writeString(mDescription);
}
private void initFromParcel(Parcel parcel) {
@@ -343,6 +361,7 @@
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
mCanRetrieveWindowContent = (parcel.readInt() == 1);
+ mDescription = parcel.readString();
}
@Override
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index d77dbdc..e6c2a0f 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -87,11 +87,13 @@
private AnimatorSetListener mSetListener = null;
/**
- * Flag indicating that the AnimatorSet has been canceled (by calling cancel() or end()).
+ * Flag indicating that the AnimatorSet has been manually
+ * terminated (by calling cancel() or end()).
* This flag is used to avoid starting other animations when currently-playing
- * child animations of this AnimatorSet end.
+ * child animations of this AnimatorSet end. It also determines whether cancel/end
+ * notifications are sent out via the normal AnimatorSetListener mechanism.
*/
- boolean mCanceled = false;
+ boolean mTerminated = false;
// The amount of time in ms to delay starting the animation after start() is called
private long mStartDelay = 0;
@@ -271,31 +273,29 @@
@SuppressWarnings("unchecked")
@Override
public void cancel() {
- mCanceled = true;
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- for (AnimatorListener listener : tmpListeners) {
- listener.onAnimationCancel(this);
- }
- }
- if (mDelayAnim != null && mDelayAnim.isRunning()) {
- // If we're currently in the startDelay period, just cancel that animator and
- // send out the end event to all listeners
- mDelayAnim.cancel();
+ mTerminated = true;
+ if (isRunning()) {
+ ArrayList<AnimatorListener> tmpListeners = null;
if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
+ tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
+ for (AnimatorListener listener : tmpListeners) {
+ listener.onAnimationCancel(this);
+ }
+ }
+ if (mDelayAnim != null && mDelayAnim.isRunning()) {
+ // If we're currently in the startDelay period, just cancel that animator and
+ // send out the end event to all listeners
+ mDelayAnim.cancel();
+ } else if (mSortedNodes.size() > 0) {
+ for (Node node : mSortedNodes) {
+ node.animation.cancel();
+ }
+ }
+ if (tmpListeners != null) {
for (AnimatorListener listener : tmpListeners) {
listener.onAnimationEnd(this);
}
}
- return;
- }
- if (mSortedNodes.size() > 0) {
- for (Node node : mSortedNodes) {
- node.animation.cancel();
- }
}
}
@@ -307,23 +307,32 @@
*/
@Override
public void end() {
- mCanceled = true;
- if (mSortedNodes.size() != mNodes.size()) {
- // hasn't been started yet - sort the nodes now, then end them
- sortNodes();
- for (Node node : mSortedNodes) {
- if (mSetListener == null) {
- mSetListener = new AnimatorSetListener(this);
+ mTerminated = true;
+ if (isRunning()) {
+ if (mSortedNodes.size() != mNodes.size()) {
+ // hasn't been started yet - sort the nodes now, then end them
+ sortNodes();
+ for (Node node : mSortedNodes) {
+ if (mSetListener == null) {
+ mSetListener = new AnimatorSetListener(this);
+ }
+ node.animation.addListener(mSetListener);
}
- node.animation.addListener(mSetListener);
}
- }
- if (mDelayAnim != null) {
- mDelayAnim.cancel();
- }
- if (mSortedNodes.size() > 0) {
- for (Node node : mSortedNodes) {
- node.animation.end();
+ if (mDelayAnim != null) {
+ mDelayAnim.cancel();
+ }
+ if (mSortedNodes.size() > 0) {
+ for (Node node : mSortedNodes) {
+ node.animation.end();
+ }
+ }
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ for (AnimatorListener listener : tmpListeners) {
+ listener.onAnimationEnd(this);
+ }
}
}
}
@@ -424,7 +433,7 @@
@SuppressWarnings("unchecked")
@Override
public void start() {
- mCanceled = false;
+ mTerminated = false;
// First, sort the nodes (if necessary). This will ensure that sortedNodes
// contains the animation nodes in the correct order.
@@ -437,7 +446,8 @@
ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
if (oldListeners != null && oldListeners.size() > 0) {
for (AnimatorListener listener : oldListeners) {
- if (listener instanceof DependencyListener) {
+ if (listener instanceof DependencyListener ||
+ listener instanceof AnimatorSetListener) {
node.animation.removeListener(listener);
}
}
@@ -522,7 +532,7 @@
* and will populate any appropriate lists, when it is started.
*/
anim.mNeedsSort = true;
- anim.mCanceled = false;
+ anim.mTerminated = false;
anim.mPlayingSet = new ArrayList<Animator>();
anim.mNodeMap = new HashMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>();
@@ -640,7 +650,7 @@
* @param dependencyAnimation the animation that sent the event.
*/
private void startIfReady(Animator dependencyAnimation) {
- if (mAnimatorSet.mCanceled) {
+ if (mAnimatorSet.mTerminated) {
// if the parent AnimatorSet was canceled, then don't start any dependent anims
return;
}
@@ -676,11 +686,15 @@
}
public void onAnimationCancel(Animator animation) {
- if (mPlayingSet.size() == 0) {
- if (mListeners != null) {
- int numListeners = mListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- mListeners.get(i).onAnimationCancel(mAnimatorSet);
+ if (!mTerminated) {
+ // Listeners are already notified of the AnimatorSet canceling in cancel().
+ // The logic below only kicks in when animations end normally
+ if (mPlayingSet.size() == 0) {
+ if (mListeners != null) {
+ int numListeners = mListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ mListeners.get(i).onAnimationCancel(mAnimatorSet);
+ }
}
}
}
@@ -692,24 +706,28 @@
mPlayingSet.remove(animation);
Node animNode = mAnimatorSet.mNodeMap.get(animation);
animNode.done = true;
- ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
- boolean allDone = true;
- int numSortedNodes = sortedNodes.size();
- for (int i = 0; i < numSortedNodes; ++i) {
- if (!sortedNodes.get(i).done) {
- allDone = false;
- break;
+ if (!mTerminated) {
+ // Listeners are already notified of the AnimatorSet ending in cancel() or
+ // end(); the logic below only kicks in when animations end normally
+ ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
+ boolean allDone = true;
+ int numSortedNodes = sortedNodes.size();
+ for (int i = 0; i < numSortedNodes; ++i) {
+ if (!sortedNodes.get(i).done) {
+ allDone = false;
+ break;
+ }
}
- }
- if (allDone) {
- // If this was the last child animation to end, then notify listeners that this
- // AnimatorSet has ended
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
+ if (allDone) {
+ // If this was the last child animation to end, then notify listeners that this
+ // AnimatorSet has ended
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
+ }
}
}
}
@@ -791,6 +809,8 @@
}
}
}
+ // nodes are 'done' by default; they become un-done when started, and done
+ // again when ended
node.done = false;
}
}
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index d25de97..06d18ec 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
/**
@@ -178,14 +179,17 @@
* the transition. The reason for this is that a further layout event should cause
* existing animations to stop where they are prior to starting new animations. So
* we cache all of the current animations in this map for possible cancellation on
- * another layout event.
+ * another layout event. LinkedHashMaps are used to preserve the order in which animations
+ * are inserted, so that we process events (such as setting up start values) in the same order.
*/
- private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>();
- private final HashMap<View, Animator> currentChangingAnimations = new HashMap<View, Animator>();
- private final HashMap<View, Animator> currentAppearingAnimations =
+ private final HashMap<View, Animator> pendingAnimations =
new HashMap<View, Animator>();
- private final HashMap<View, Animator> currentDisappearingAnimations =
- new HashMap<View, Animator>();
+ private final LinkedHashMap<View, Animator> currentChangingAnimations =
+ new LinkedHashMap<View, Animator>();
+ private final LinkedHashMap<View, Animator> currentAppearingAnimations =
+ new LinkedHashMap<View, Animator>();
+ private final LinkedHashMap<View, Animator> currentDisappearingAnimations =
+ new LinkedHashMap<View, Animator>();
/**
* This hashmap is used to track the listeners that have been added to the children of
@@ -235,7 +239,7 @@
PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1);
PropertyValuesHolder pvhScrollX = PropertyValuesHolder.ofInt("scrollX", 0, 1);
PropertyValuesHolder pvhScrollY = PropertyValuesHolder.ofInt("scrollY", 0, 1);
- defaultChangeIn = ObjectAnimator.ofPropertyValuesHolder(this,
+ defaultChangeIn = ObjectAnimator.ofPropertyValuesHolder((Object)null,
pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScrollX, pvhScrollY);
defaultChangeIn.setDuration(DEFAULT_DURATION);
defaultChangeIn.setStartDelay(mChangingAppearingDelay);
@@ -244,11 +248,11 @@
defaultChangeOut.setStartDelay(mChangingDisappearingDelay);
defaultChangeOut.setInterpolator(mChangingDisappearingInterpolator);
- defaultFadeIn = ObjectAnimator.ofFloat(this, "alpha", 0f, 1f);
+ defaultFadeIn = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
defaultFadeIn.setDuration(DEFAULT_DURATION);
defaultFadeIn.setStartDelay(mAppearingDelay);
defaultFadeIn.setInterpolator(mAppearingInterpolator);
- defaultFadeOut = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f);
+ defaultFadeOut = ObjectAnimator.ofFloat(null, "alpha", 1f, 0f);
defaultFadeOut.setDuration(DEFAULT_DURATION);
defaultFadeOut.setStartDelay(mDisappearingDelay);
defaultFadeOut.setInterpolator(mDisappearingInterpolator);
@@ -547,7 +551,7 @@
}
/**
- * This function sets up runs animations on all of the views that change during layout.
+ * This function sets up animations on all of the views that change during layout.
* For every child in the parent, we create a change animation of the appropriate
* type (appearing or disappearing) and ask it to populate its start values from its
* target view. We add layout listeners to all child views and listen for changes. For
@@ -821,24 +825,24 @@
*/
public void cancel() {
if (currentChangingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentChangingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.cancel();
}
currentChangingAnimations.clear();
}
if (currentAppearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentAppearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
currentAppearingAnimations.clear();
}
if (currentDisappearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
@@ -859,8 +863,8 @@
case CHANGE_APPEARING:
case CHANGE_DISAPPEARING:
if (currentChangingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentChangingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.cancel();
}
@@ -869,8 +873,8 @@
break;
case APPEARING:
if (currentAppearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentAppearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentAppearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
@@ -879,8 +883,8 @@
break;
case DISAPPEARING:
if (currentDisappearingAnimations.size() > 0) {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+ LinkedHashMap<View, Animator> currentAnimCopy =
+ (LinkedHashMap<View, Animator>) currentDisappearingAnimations.clone();
for (Animator anim : currentAnimCopy.values()) {
anim.end();
}
@@ -1113,4 +1117,4 @@
View view, int transitionType);
}
-}
\ No newline at end of file
+}
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 1dcaa04..90d676e 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -933,17 +933,17 @@
@Override
public void cancel() {
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- for (AnimatorListener listener : tmpListeners) {
- listener.onAnimationCancel(this);
- }
- }
// Only cancel if the animation is actually running or has been started and is about
// to run
if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) ||
sDelayedAnims.get().contains(this)) {
+ if (mListeners != null) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ for (AnimatorListener listener : tmpListeners) {
+ listener.onAnimationCancel(this);
+ }
+ }
endAnimation();
}
}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3ec5edb..36940c2 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -81,6 +81,9 @@
* Set this flag if selecting the 'home' button in the action bar to return
* up by a single level in your UI rather than back to the top level or front page.
*
+ * <p>Setting this option will implicitly enable interaction with the home/up
+ * button. See {@link #setHomeButtonEnabled(boolean)}.
+ *
* @see #setDisplayOptions(int)
* @see #setDisplayOptions(int, int)
*/
@@ -107,18 +110,6 @@
public static final int DISPLAY_SHOW_CUSTOM = 0x10;
/**
- * Disable the 'home' element. This may be combined with
- * {@link #DISPLAY_SHOW_HOME} to create a non-focusable/non-clickable
- * 'home' element. Useful for a level of your app's navigation hierarchy
- * where clicking 'home' doesn't do anything.
- *
- * @see #setDisplayOptions(int)
- * @see #setDisplayOptions(int, int)
- * @see #setDisplayDisableHomeEnabled(boolean)
- */
- public static final int DISPLAY_DISABLE_HOME = 0x20;
-
- /**
* Set the action bar into custom navigation mode, supplying a view
* for custom navigation.
*
@@ -405,21 +396,6 @@
public abstract void setDisplayShowCustomEnabled(boolean showCustom);
/**
- * Set whether the 'home' affordance on the action bar should be disabled.
- * If set, the 'home' element will not be focusable or clickable, useful if
- * the user is at the top level of the app's navigation hierarchy.
- *
- * <p>To set several display options at once, see the setDisplayOptions methods.
- *
- * @param disableHome true to disable the 'home' element.
- *
- * @see #setDisplayOptions(int)
- * @see #setDisplayOptions(int, int)
- * @see #DISPLAY_DISABLE_HOME
- */
- public abstract void setDisplayDisableHomeEnabled(boolean disableHome);
-
- /**
* Set the ActionBar's background.
*
* @param d Background drawable
@@ -632,6 +608,22 @@
public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);
/**
+ * Enable or disable the "home" button in the corner of the action bar. (Note that this
+ * is the application home/up affordance on the action bar, not the systemwide home
+ * button.)
+ *
+ * <p>This defaults to true for packages targeting < API 14. For packages targeting
+ * API 14 or greater, the application should call this method to enable interaction
+ * with the home/up affordance.
+ *
+ * <p>Setting the {@link #DISPLAY_HOME_AS_UP} display option will automatically enable
+ * the home button.
+ *
+ * @param enabled true to enable the home button, false to disable the home button.
+ */
+ public abstract void setHomeButtonEnabled(boolean enabled);
+
+ /**
* Listener interface for ActionBar navigation events.
*/
public interface OnNavigationListener {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index a6658cc..d207a0a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1471,6 +1471,24 @@
}
/**
+ * Returns the usage statistics of each installed package.
+ *
+ * @hide
+ */
+ public PkgUsageStats[] getAllPackageUsageStats() {
+ try {
+ IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
+ ServiceManager.getService("usagestats"));
+ if (usageStatsService != null) {
+ return usageStatsService.getAllPkgUsageStats();
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not query usage stats", e);
+ }
+ return new PkgUsageStats[0];
+ }
+
+ /**
* @param userid the user's id. Zero indicates the default user
* @hide
*/
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index eee14fb..c6a746b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -413,10 +413,10 @@
native private void dumpGraphicsInfo(FileDescriptor fd);
private final class ApplicationThread extends ApplicationThreadNative {
- private static final String HEAP_COLUMN = "%17s %8s %8s %8s %8s";
- private static final String ONE_COUNT_COLUMN = "%17s %8d";
- private static final String TWO_COUNT_COLUMNS = "%17s %8d %17s %8d";
- private static final String TWO_COUNT_COLUMNS_DB = "%20s %8d %20s %8d";
+ private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
+ private static final String ONE_COUNT_COLUMN = "%21s %8d";
+ private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
+ private static final String TWO_COUNT_COLUMNS_DB = "%21s %8d %21s %8d";
private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";
// Formatting for checkin service - update version if row format changes
@@ -729,12 +729,17 @@
}
@Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (args != null && args.length == 1 && args[0].equals("graphics")) {
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) {
+ FileOutputStream fout = new FileOutputStream(fd);
+ PrintWriter pw = new PrintWriter(fout);
+ try {
+ return dumpMemInfo(fd, pw, args);
+ } finally {
pw.flush();
- dumpGraphicsInfo(fd);
- return;
}
+ }
+
+ private Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, PrintWriter pw, String[] args) {
long nativeMax = Debug.getNativeHeapSize() / 1024;
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -742,14 +747,6 @@
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
- final int nativeShared = memInfo.nativeSharedDirty;
- final int dalvikShared = memInfo.dalvikSharedDirty;
- final int otherShared = memInfo.otherSharedDirty;
-
- final int nativePrivate = memInfo.nativePrivateDirty;
- final int dalvikPrivate = memInfo.dalvikPrivateDirty;
- final int otherPrivate = memInfo.otherPrivateDirty;
-
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.totalMemory() / 1024;
@@ -813,16 +810,18 @@
pw.print(memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); pw.print(',');
// Heap info - shared
- pw.print(nativeShared); pw.print(',');
- pw.print(dalvikShared); pw.print(',');
- pw.print(otherShared); pw.print(',');
- pw.print(nativeShared + dalvikShared + otherShared); pw.print(',');
+ pw.print(memInfo.nativeSharedDirty); pw.print(',');
+ pw.print(memInfo.dalvikSharedDirty); pw.print(',');
+ pw.print(memInfo.otherSharedDirty); pw.print(',');
+ pw.print(memInfo.nativeSharedDirty + memInfo.dalvikSharedDirty
+ + memInfo.otherSharedDirty); pw.print(',');
// Heap info - private
- pw.print(nativePrivate); pw.print(',');
- pw.print(dalvikPrivate); pw.print(',');
- pw.print(otherPrivate); pw.print(',');
- pw.print(nativePrivate + dalvikPrivate + otherPrivate); pw.print(',');
+ pw.print(memInfo.nativePrivateDirty); pw.print(',');
+ pw.print(memInfo.dalvikPrivateDirty); pw.print(',');
+ pw.print(memInfo.otherPrivateDirty); pw.print(',');
+ pw.print(memInfo.nativePrivateDirty + memInfo.dalvikPrivateDirty
+ + memInfo.otherPrivateDirty); pw.print(',');
// Object counts
pw.print(viewInstanceCount); pw.print(',');
@@ -850,24 +849,38 @@
pw.print(',');
}
- return;
+ return memInfo;
}
// otherwise, show human-readable format
- printRow(pw, HEAP_COLUMN, "", "native", "dalvik", "other", "total");
- printRow(pw, HEAP_COLUMN, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax);
- printRow(pw, HEAP_COLUMN, "allocated:", nativeAllocated, dalvikAllocated, "N/A",
- nativeAllocated + dalvikAllocated);
- printRow(pw, HEAP_COLUMN, "free:", nativeFree, dalvikFree, "N/A",
- nativeFree + dalvikFree);
+ printRow(pw, HEAP_COLUMN, "", "", "Shared", "Private", "Heap", "Heap", "Heap");
+ printRow(pw, HEAP_COLUMN, "", "Pss", "Dirty", "Dirty", "Size", "Alloc", "Free");
+ printRow(pw, HEAP_COLUMN, "", "------", "------", "------", "------", "------",
+ "------");
+ printRow(pw, HEAP_COLUMN, "Native", memInfo.nativePss, memInfo.nativeSharedDirty,
+ memInfo.nativePrivateDirty, nativeMax, nativeAllocated, nativeFree);
+ printRow(pw, HEAP_COLUMN, "Dalvik", memInfo.dalvikPss, memInfo.dalvikSharedDirty,
+ memInfo.dalvikPrivateDirty, dalvikMax, dalvikAllocated, dalvikFree);
- printRow(pw, HEAP_COLUMN, "(Pss):", memInfo.nativePss, memInfo.dalvikPss,
- memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss);
+ int otherPss = memInfo.otherPss;
+ int otherSharedDirty = memInfo.otherSharedDirty;
+ int otherPrivateDirty = memInfo.otherPrivateDirty;
- printRow(pw, HEAP_COLUMN, "(shared dirty):", nativeShared, dalvikShared, otherShared,
- nativeShared + dalvikShared + otherShared);
- printRow(pw, HEAP_COLUMN, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate,
- nativePrivate + dalvikPrivate + otherPrivate);
+ for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
+ printRow(pw, HEAP_COLUMN, memInfo.getOtherLabel(i),
+ memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i),
+ memInfo.getOtherPrivateDirty(i), "", "", "");
+ otherPss -= memInfo.getOtherPss(i);
+ otherSharedDirty -= memInfo.getOtherSharedDirty(i);
+ otherPrivateDirty -= memInfo.getOtherPrivateDirty(i);
+ }
+
+ printRow(pw, HEAP_COLUMN, "Unknown", otherPss, otherSharedDirty,
+ otherPrivateDirty, "", "", "");
+ printRow(pw, HEAP_COLUMN, "TOTAL", memInfo.getTotalPss(),
+ memInfo.getTotalSharedDirty(), memInfo.getTotalPrivateDirty(),
+ nativeMax+dalvikMax, nativeAllocated+dalvikAllocated,
+ nativeFree+dalvikFree);
pw.println(" ");
pw.println(" Objects");
@@ -916,6 +929,13 @@
pw.println(" Asset Allocations");
pw.print(assetAlloc);
}
+
+ return memInfo;
+ }
+
+ @Override
+ public void dumpGfxInfo(FileDescriptor fd, String[] args) {
+ dumpGraphicsInfo(fd);
}
private void printRow(PrintWriter pw, String format, Object...objs) {
@@ -932,6 +952,10 @@
ucd.info = info;
queueOrSendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd);
}
+
+ public void scheduleTrimMemory(int level) {
+ queueOrSendMessage(H.TRIM_MEMORY, level);
+ }
}
private final class H extends Handler {
@@ -975,6 +999,7 @@
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
+ public static final int TRIM_MEMORY = 140;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -1018,6 +1043,7 @@
case SLEEPING: return "SLEEPING";
case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
case UPDATE_PACKAGE_COMPATIBILITY_INFO: return "UPDATE_PACKAGE_COMPATIBILITY_INFO";
+ case TRIM_MEMORY: return "TRIM_MEMORY";
}
}
return "(unknown)";
@@ -1158,6 +1184,8 @@
break;
case UPDATE_PACKAGE_COMPATIBILITY_INFO:
handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
+ case TRIM_MEMORY:
+ handleTrimMemory(msg.arg1);
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
}
@@ -3529,6 +3557,9 @@
BinderInternal.forceGc("mem");
}
+ final void handleTrimMemory(int level) {
+ }
+
private final void handleBindApplication(AppBindData data) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
@@ -4093,11 +4124,6 @@
});
}
- private final void detach()
- {
- sThreadLocal.set(null);
- }
-
public static final ActivityThread systemMain() {
HardwareRenderer.disable();
ActivityThread thread = new ActivityThread();
@@ -4105,10 +4131,9 @@
return thread;
}
- public final void installSystemProviders(List providers) {
+ public final void installSystemProviders(List<ProviderInfo> providers) {
if (providers != null) {
- installContentProviders(mInitialApplication,
- (List<ProviderInfo>)providers);
+ installContentProviders(mInitialApplication, providers);
}
}
@@ -4147,14 +4172,6 @@
Looper.loop();
- if (Process.supportsProcesses()) {
- throw new RuntimeException("Main thread loop unexpectedly exited");
- }
-
- thread.detach();
- String name = (thread.mInitialApplication != null)
- ? thread.mInitialApplication.getPackageName()
- : "<unknown>";
- Slog.i(TAG, "Main thread of " + name + " is now exiting");
+ throw new RuntimeException("Main thread loop unexpectedly exited");
}
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index dc0f529..942f245 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -478,6 +478,55 @@
updatePackageCompatibilityInfo(pkg, compat);
return true;
}
+
+ case SCHEDULE_TRIM_MEMORY_TRANSACTION: {
+ data.enforceInterface(IApplicationThread.descriptor);
+ int level = data.readInt();
+ scheduleTrimMemory(level);
+ return true;
+ }
+
+ case DUMP_MEM_INFO_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ ParcelFileDescriptor fd = data.readFileDescriptor();
+ String[] args = data.readStringArray();
+ Debug.MemoryInfo mi = null;
+ if (fd != null) {
+ try {
+ mi = dumpMemInfo(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // swallowed, not propagated back to the caller
+ }
+ }
+ }
+ reply.writeNoException();
+ mi.writeToParcel(reply, 0);
+ return true;
+ }
+
+ case DUMP_GFX_INFO_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ ParcelFileDescriptor fd = data.readFileDescriptor();
+ String[] args = data.readStringArray();
+ if (fd != null) {
+ try {
+ dumpGfxInfo(fd.getFileDescriptor(), args);
+ } finally {
+ try {
+ fd.close();
+ } catch (IOException e) {
+ // swallowed, not propagated back to the caller
+ }
+ }
+ }
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -989,4 +1038,36 @@
mRemote.transact(UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
}
+
+ public void scheduleTrimMemory(int level) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeInt(level);
+ mRemote.transact(SCHEDULE_TRIM_MEMORY_TRANSACTION, data, null,
+ IBinder.FLAG_ONEWAY);
+ }
+
+ public Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
+ reply.readException();
+ Debug.MemoryInfo info = new Debug.MemoryInfo();
+ info.readFromParcel(reply);
+ data.recycle();
+ reply.recycle();
+ return info;
+ }
+
+ public void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeFileDescriptor(fd);
+ data.writeStringArray(args);
+ mRemote.transact(DUMP_GFX_INFO_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 8749d3e..d2323e7 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1163,9 +1163,6 @@
throw new IllegalArgumentException("permission is null");
}
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
try {
return ActivityManagerNative.getDefault().checkPermission(
permission, pid, uid);
@@ -1180,9 +1177,6 @@
throw new IllegalArgumentException("permission is null");
}
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
int pid = Binder.getCallingPid();
if (pid != Process.myPid()) {
return checkPermission(permission, pid,
@@ -1263,9 +1257,6 @@
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
try {
return ActivityManagerNative.getDefault().checkUriPermission(
uri, pid, uid, modeFlags);
@@ -1276,9 +1267,6 @@
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
int pid = Binder.getCallingPid();
if (pid != Process.myPid()) {
return checkUriPermission(uri, pid,
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 285f1c1..c82c9ec 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1307,6 +1307,7 @@
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
+ mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 05a68a8..9de0bf4 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -119,6 +119,9 @@
throws RemoteException;
void setCoreSettings(Bundle coreSettings) throws RemoteException;
void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
+ void scheduleTrimMemory(int level) throws RemoteException;
+ Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, String[] args) throws RemoteException;
+ void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -162,4 +165,7 @@
int SET_HTTP_PROXY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
int SET_CORE_SETTINGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+39;
int UPDATE_PACKAGE_COMPATIBILITY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+40;
+ int SCHEDULE_TRIM_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+41;
+ int DUMP_MEM_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+42;
+ int DUMP_GFX_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+43;
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index dce0a97..436fdf8 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -28,6 +28,7 @@
import android.util.Log;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
@@ -533,6 +534,16 @@
Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
throw ex;
} finally {
+ // Send the EOD marker indicating that there is no more data
+ // forthcoming from this agent.
+ try {
+ FileOutputStream out = new FileOutputStream(data.getFileDescriptor());
+ byte[] buf = new byte[4];
+ out.write(buf);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to finalize backup stream!");
+ }
+
Binder.restoreCallingIdentity(ident);
try {
callbackBinder.opComplete(token);
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 52efc07..0a01dcf 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -16,7 +16,6 @@
package android.bluetooth;
-import android.annotation.SdkConstant;
import android.content.Context;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -67,9 +66,6 @@
*/
public static final int CHANNEL_TYPE_ANY = 12;
- private final ArrayList<BluetoothHealthAppConfiguration> mAppConfigs =
- new ArrayList<BluetoothHealthAppConfiguration>();
-
/**
* Register an application configuration that acts as a Health SINK.
* This is the configuration that will be used to communicate with health devices
@@ -86,7 +82,7 @@
* @return If true, callback will be called.
*/
public boolean registerSinkAppConfiguration(String name, int dataType,
- IBluetoothHealthCallback callback) {
+ BluetoothHealthCallback callback) {
if (!isEnabled() || name == null) return false;
if (DBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
@@ -111,18 +107,18 @@
* @hide
*/
public boolean registerAppConfiguration(String name, int dataType, int role,
- int channelType, IBluetoothHealthCallback callback) {
+ int channelType, BluetoothHealthCallback callback) {
boolean result = false;
if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
if (DBG) log("registerApplication(" + name + ":" + dataType + ")");
+ BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
BluetoothHealthAppConfiguration config =
- new BluetoothHealthAppConfiguration(name, dataType, role, channelType,
- callback);
+ new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
if (mService != null) {
try {
- result = mService.registerAppConfiguration(config);
+ result = mService.registerAppConfiguration(config, wrapper);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -130,8 +126,6 @@
Log.w(TAG, "Proxy not attached to service");
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
}
-
- if (result) mAppConfigs.add(config);
return result;
}
@@ -147,7 +141,7 @@
*/
public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
boolean result = false;
- if (mService != null && isEnabled() && isValidAppConfig(config)) {
+ if (mService != null && isEnabled() && config != null) {
try {
result = mService.unregisterAppConfiguration(config);
} catch (RemoteException e) {
@@ -157,26 +151,26 @@
Log.w(TAG, "Proxy not attached to service");
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
}
- if (result) mAppConfigs.remove(config);
+
return result;
}
/**
* Connect to a health device which has the {@link #SOURCE_ROLE}.
- * This is an asynchrnous call. If this function returns true, the callback
+ * This is an asynchronous call. If this function returns true, the callback
* associated with the application configuration will be called.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device The remote Bluetooth device.
- * @param config The application configuration which has been registed using
- * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @param config The application configuration which has been registered using
+ * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
* @return If true, the callback associated with the application config will be called.
*/
public boolean connectChannelToSource(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.connectChannelToSource(device, config);
} catch (RemoteException e) {
@@ -197,15 +191,15 @@
*<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device The remote Bluetooth device.
- * @param config The application configuration which has been registed using
- * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @param config The application configuration which has been registered using
+ * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
* @return If true, the callback associated with the application config will be called.
* @hide
*/
public boolean connectChannelToSink(BluetoothDevice device,
BluetoothHealthAppConfiguration config, int channelType) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.connectChannelToSink(device, config, channelType);
} catch (RemoteException e) {
@@ -226,8 +220,8 @@
*<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
*
* @param device The remote Bluetooth device.
- * @param config The application configuration which has been registed using
- * {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
+ * @param config The application configuration which has been registered using
+ * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
* @param fd The file descriptor that was associated with the channel.
* @return If true, the callback associated with the application config will be called.
* @hide
@@ -235,7 +229,7 @@
public boolean disconnectChannel(BluetoothDevice device,
BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.disconnectChannel(device, config, fd);
} catch (RemoteException e) {
@@ -262,7 +256,7 @@
public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
BluetoothHealthAppConfiguration config) {
if (mService != null && isEnabled() && isValidDevice(device) &&
- isValidAppConfig(config)) {
+ config != null) {
try {
return mService.getMainChannelFd(device, config);
} catch (RemoteException e) {
@@ -290,6 +284,7 @@
* {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/
+ @Override
public int getConnectionState(BluetoothDevice device) {
if (mService != null && isEnabled() && isValidDevice(device)) {
try {
@@ -317,6 +312,7 @@
* local adapter.
* @return List of devices. The list will be empty on error.
*/
+ @Override
public List<BluetoothDevice> getConnectedDevices() {
if (mService != null && isEnabled()) {
try {
@@ -348,6 +344,7 @@
* {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
* @return List of devices. The list will be empty on error.
*/
+ @Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (mService != null && isEnabled()) {
try {
@@ -361,6 +358,27 @@
return new ArrayList<BluetoothDevice>();
}
+ private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
+ private BluetoothHealthCallback mCallback;
+
+ public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
+ int status) {
+ mCallback.onHealthAppConfigurationStatusChange(config, status);
+ }
+
+ @Override
+ public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
+ BluetoothDevice device, int prevState, int newState,
+ ParcelFileDescriptor fd) {
+ mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd);
+ }
+ }
+
/** Health Channel Connection State - Disconnected */
public static final int STATE_CHANNEL_DISCONNECTED = 0;
/** Health Channel Connection State - Connecting */
@@ -379,7 +397,6 @@
/** Health App Configuration un-registration failure */
public static final int APPLICATION_UNREGISTRATION_FAILURE = 3;
- private Context mContext;
private ServiceListener mServiceListener;
private IBluetooth mService;
BluetoothAdapter mAdapter;
@@ -420,14 +437,8 @@
return false;
}
- private boolean isValidAppConfig(BluetoothHealthAppConfiguration config) {
- if (!mAppConfigs.isEmpty() && mAppConfigs.contains(config)) return true;
- log("Not a valid config: " + config);
- return false;
- }
-
private boolean checkAppParam(String name, int role, int channelType,
- IBluetoothHealthCallback callback) {
+ BluetoothHealthCallback callback) {
if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
(channelType != CHANNEL_TYPE_RELIABLE &&
channelType != CHANNEL_TYPE_STREAMING &&
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index b87aea5..7020249 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -17,7 +17,6 @@
package android.bluetooth;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,21 +33,18 @@
private final int mDataType;
private final int mRole;
private final int mChannelType;
- private final IBluetoothHealthCallback mCallback;
/**
* Constructor to register the SINK role
*
* @param name Friendly name associated with the application configuration
* @param dataType Data Type of the remote Bluetooth Health device
- * @param callback Callback associated with the application configuration.
*/
- BluetoothHealthAppConfiguration(String name, int dataType, IBluetoothHealthCallback callback) {
+ BluetoothHealthAppConfiguration(String name, int dataType) {
mName = name;
mDataType = dataType;
mRole = BluetoothHealth.SINK_ROLE;
mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
- mCallback = callback;
}
/**
@@ -56,17 +52,15 @@
*
* @param name Friendly name associated with the application configuration
* @param dataType Data Type of the remote Bluetooth Health device
- * @param role {@link BluetoothHealth.SOURCE_ROLE} or
- * {@link BluetoothHealth.SINK_ROLE}
- * @param callback Callback associated with the application configuration.
+ * @param role {@link BluetoothHealth#SOURCE_ROLE} or
+ * {@link BluetoothHealth#SINK_ROLE}
*/
- BluetoothHealthAppConfiguration(String name, int dataType, int role, int channelType,
- IBluetoothHealthCallback callback) {
+ BluetoothHealthAppConfiguration(String name, int dataType, int role, int
+ channelType) {
mName = name;
mDataType = dataType;
mRole = role;
mChannelType = channelType;
- mCallback = callback;
}
@Override
@@ -77,8 +71,7 @@
return mName.equals(config.getName()) &&
mDataType == config.getDataType() &&
mRole == config.getRole() &&
- mChannelType == config.getChannelType() &&
- mCallback.equals(config.getCallback());
+ mChannelType == config.getChannelType();
}
return false;
}
@@ -90,7 +83,6 @@
result = 31 * result + mDataType;
result = 31 * result + mRole;
result = 31 * result + mChannelType;
- result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
return result;
}
@@ -98,9 +90,10 @@
public String toString() {
return "BluetoothHealthAppConfiguration [mName = " + mName +
",mDataType = " + mDataType + ", mRole = " + mRole + ",mChannelType = " +
- mChannelType + ",callback=" + mCallback +"]";
+ mChannelType + "]";
}
+ @Override
public int describeContents() {
return 0;
}
@@ -144,37 +137,31 @@
return mChannelType;
}
- /**
- * Return the callback associated with this application configuration.
- *
- * @return IBluetoothHealthCallback
- */
- public IBluetoothHealthCallback getCallback() {
- return mCallback;
- }
-
public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
+ @Override
public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
String name = in.readString();
int type = in.readInt();
int role = in.readInt();
int channelType = in.readInt();
- IBluetoothHealthCallback callback =
- IBluetoothHealthCallback.Stub.asInterface(in.readStrongBinder());
- return new BluetoothHealthAppConfiguration(name, type, role, channelType,
- callback);
+ return new BluetoothHealthAppConfiguration(name, type, role,
+ channelType);
}
+
+ @Override
public BluetoothHealthAppConfiguration[] newArray(int size) {
return new BluetoothHealthAppConfiguration[size];
}
};
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(mName);
out.writeInt(mDataType);
out.writeInt(mRole);
out.writeInt(mChannelType);
- out.writeStrongInterface(mCallback);
}
+
+
}
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
new file mode 100644
index 0000000..0d11bb5
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothHealthCallback.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.bluetooth;
+
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+/**
+ * This class is used for all the {@link BluetoothHealth} callbacks.
+ * @hide
+ */
+public abstract class BluetoothHealthCallback {
+
+ private static final String TAG = "BluetoothHealthCallback";
+
+ public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
+ int status) {
+ Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + " Status:" + status);
+ }
+
+ public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
+ BluetoothDevice device, int prevState, int newState,
+ ParcelFileDescriptor fd) {
+ Log.d(TAG, "onHealthChannelStateChange: " + config + " Device:" + device +
+ "PrevState:" + prevState + "NewState:" + newState + "FileDescriptor:" + fd);
+ }
+}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 6ca6c2e..183772d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothHealthCallback;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHealthAppConfiguration;
import android.os.ParcelUuid;
@@ -102,7 +103,8 @@
boolean disconnectPanDevice(in BluetoothDevice device);
// HDP profile APIs
- boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config);
+ boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config,
+ in IBluetoothHealthCallback callback);
boolean unregisterAppConfiguration(in BluetoothHealthAppConfiguration config);
boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index dad60b0..92b98fd 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -51,4 +51,16 @@
* The system will perform a gc for you after returning from this method.
*/
void onLowMemory();
+
+ /** @hide */
+ static final int TRIM_MEMORY_COMPLETE = 80;
+
+ /** @hide */
+ static final int TRIM_MEMORY_MODERATE = 60;
+
+ /** @hide */
+ static final int TRIM_MEMORY_BACKGROUND = 40;
+
+ /** @hide */
+ static final int TRIM_MEMORY_INVISIBLE = 20;
}
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index a2af558..0e83dc0 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -20,17 +20,21 @@
import android.database.IContentObserver;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
+import android.util.SparseIntArray;
import android.Manifest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
@@ -70,6 +74,40 @@
} else {
mSyncManager.dump(fd, pw);
}
+ pw.println();
+ pw.println("Observer tree:");
+ synchronized (mRootNode) {
+ int[] counts = new int[2];
+ final SparseIntArray pidCounts = new SparseIntArray();
+ mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts);
+ pw.println();
+ ArrayList<Integer> sorted = new ArrayList<Integer>();
+ for (int i=0; i<pidCounts.size(); i++) {
+ sorted.add(pidCounts.keyAt(i));
+ }
+ Collections.sort(sorted, new Comparator<Integer>() {
+ @Override
+ public int compare(Integer lhs, Integer rhs) {
+ int lc = pidCounts.get(lhs);
+ int rc = pidCounts.get(rhs);
+ if (lc < rc) {
+ return 1;
+ } else if (lc > rc) {
+ return -1;
+ }
+ return 0;
+ }
+
+ });
+ for (int i=0; i<sorted.size(); i++) {
+ int pid = sorted.get(i);
+ pw.print(" pid "); pw.print(pid); pw.print(": ");
+ pw.print(pidCounts.get(pid)); pw.println(" observers");
+ }
+ pw.println();
+ pw.print(" Total number of nodes: "); pw.println(counts[0]);
+ pw.print(" Total number of observers: "); pw.println(counts[1]);
+ }
} finally {
restoreCallingIdentity(identityToken);
}
@@ -102,7 +140,8 @@
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
synchronized (mRootNode) {
- mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode);
+ mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode,
+ Binder.getCallingUid(), Binder.getCallingPid());
if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
" with notifyForDescendents " + notifyForDescendents);
}
@@ -465,12 +504,17 @@
public static final class ObserverNode {
private class ObserverEntry implements IBinder.DeathRecipient {
public final IContentObserver observer;
+ public final int uid;
+ public final int pid;
public final boolean notifyForDescendents;
private final Object observersLock;
- public ObserverEntry(IContentObserver o, boolean n, Object observersLock) {
+ public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
+ int _uid, int _pid) {
this.observersLock = observersLock;
observer = o;
+ uid = _uid;
+ pid = _pid;
notifyForDescendents = n;
try {
observer.asBinder().linkToDeath(this, 0);
@@ -484,6 +528,16 @@
removeObserverLocked(observer);
}
}
+
+ public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ String name, String prefix, SparseIntArray pidCounts) {
+ pidCounts.put(pid, pidCounts.get(pid)+1);
+ pw.print(prefix); pw.print(name); pw.print(": pid=");
+ pw.print(pid); pw.print(" uid=");
+ pw.print(uid); pw.print(" target=");
+ pw.println(Integer.toHexString(System.identityHashCode(
+ observer != null ? observer.asBinder() : null)));
+ }
}
public static final int INSERT_TYPE = 0;
@@ -498,6 +552,37 @@
mName = name;
}
+ public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ String name, String prefix, int[] counts, SparseIntArray pidCounts) {
+ String innerName = null;
+ if (mObservers.size() > 0) {
+ if ("".equals(name)) {
+ innerName = mName;
+ } else {
+ innerName = name + "/" + mName;
+ }
+ for (int i=0; i<mObservers.size(); i++) {
+ counts[1]++;
+ mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
+ pidCounts);
+ }
+ }
+ if (mChildren.size() > 0) {
+ if (innerName == null) {
+ if ("".equals(name)) {
+ innerName = mName;
+ } else {
+ innerName = name + "/" + mName;
+ }
+ }
+ for (int i=0; i<mChildren.size(); i++) {
+ counts[0]++;
+ mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
+ counts, pidCounts);
+ }
+ }
+ }
+
private String getUriSegment(Uri uri, int index) {
if (uri != null) {
if (index == 0) {
@@ -518,15 +603,16 @@
}
public void addObserverLocked(Uri uri, IContentObserver observer,
- boolean notifyForDescendents, Object observersLock) {
- addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock);
+ boolean notifyForDescendents, Object observersLock, int uid, int pid) {
+ addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock, uid, pid);
}
private void addObserverLocked(Uri uri, int index, IContentObserver observer,
- boolean notifyForDescendents, Object observersLock) {
+ boolean notifyForDescendents, Object observersLock, int uid, int pid) {
// If this is the leaf node add the observer
if (index == countUriSegments(uri)) {
- mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock));
+ mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock,
+ uid, pid));
return;
}
@@ -539,7 +625,8 @@
for (int i = 0; i < N; i++) {
ObserverNode node = mChildren.get(i);
if (node.mName.equals(segment)) {
- node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
+ node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
+ observersLock, uid, pid);
return;
}
}
@@ -547,7 +634,8 @@
// No child found, create one
ObserverNode node = new ObserverNode(segment);
mChildren.add(node);
- node.addObserverLocked(uri, index + 1, observer, notifyForDescendents, observersLock);
+ node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
+ observersLock, uid, pid);
}
public boolean removeObserverLocked(IContentObserver observer) {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 8a42693..7d67e11 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -720,8 +720,20 @@
* onAutoFocus will be called immediately with a fake value of
* <code>success</code> set to <code>true</code>.
*
+ * The auto-focus routine may lock auto-exposure and auto-white balance
+ * after it completes. To check for the state of these locks, use the
+ * {@link android.hardware.Camera.Parameters#getAutoExposureLock()} and
+ * {@link android.hardware.Camera.Parameters#getAutoWhiteBalanceLock()}
+ * methods. If such locking is undesirable, use
+ * {@link android.hardware.Camera.Parameters#setAutoExposureLock(boolean)}
+ * and
+ * {@link android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)}
+ * to release the locks.
+ *
* @param success true if focus was successful, false if otherwise
* @param camera the Camera service object
+ * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
+ * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
*/
void onAutoFocus(boolean success, Camera camera);
};
@@ -747,8 +759,21 @@
* {@link android.hardware.Camera.Parameters#FLASH_MODE_OFF}, flash may be
* fired during auto-focus, depending on the driver and camera hardware.<p>
*
+ * The auto-focus routine may lock auto-exposure and auto-white balance
+ * after it completes. To check for the state of these locks, use the
+ * {@link android.hardware.Camera.Parameters#getAutoExposureLock()} and
+ * {@link android.hardware.Camera.Parameters#getAutoWhiteBalanceLock()}
+ * methods after the {@link AutoFocusCallback#onAutoFocus(boolean, Camera)}
+ * callback is invoked. If such locking is undesirable, use
+ * {@link android.hardware.Camera.Parameters#setAutoExposureLock(boolean)}
+ * and
+ * {@link android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)}
+ * to release the locks.
+ *
* @param cb the callback to run
* @see #cancelAutoFocus()
+ * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
+ * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
*/
public final void autoFocus(AutoFocusCallback cb)
{
@@ -763,7 +788,13 @@
* this function will return the focus position to the default.
* If the camera does not support auto-focus, this is a no-op.
*
+ * Canceling auto-focus will return the auto-exposure lock and auto-white
+ * balance lock to their state before {@link #autoFocus(AutoFocusCallback)}
+ * was called.
+ *
* @see #autoFocus(Camera.AutoFocusCallback)
+ * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
+ * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
*/
public final void cancelAutoFocus()
{
@@ -2562,8 +2593,6 @@
* routine is free to run normally.
*
* @see #getAutoExposureLock()
- *
- * @hide
*/
public void setAutoExposureLock(boolean toggle) {
set(KEY_AUTO_EXPOSURE_LOCK, toggle ? TRUE : FALSE);
@@ -2583,7 +2612,6 @@
*
* @see #setAutoExposureLock(boolean)
*
- * @hide
*/
public boolean getAutoExposureLock() {
String str = get(KEY_AUTO_EXPOSURE_LOCK);
@@ -2598,7 +2626,6 @@
* @return true if auto-exposure lock is supported.
* @see #setAutoExposureLock(boolean)
*
- * @hide
*/
public boolean isAutoExposureLockSupported() {
String str = get(KEY_AUTO_EXPOSURE_LOCK_SUPPORTED);
@@ -2645,8 +2672,6 @@
* auto-white balance routine is free to run normally.
*
* @see #getAutoWhiteBalanceLock()
- *
- * @hide
*/
public void setAutoWhiteBalanceLock(boolean toggle) {
set(KEY_AUTO_WHITEBALANCE_LOCK, toggle ? TRUE : FALSE);
@@ -2668,7 +2693,6 @@
*
* @see #setAutoWhiteBalanceLock(boolean)
*
- * @hide
*/
public boolean getAutoWhiteBalanceLock() {
String str = get(KEY_AUTO_WHITEBALANCE_LOCK);
@@ -2683,7 +2707,6 @@
* @return true if auto-white balance lock is supported.
* @see #setAutoWhiteBalanceLock(boolean)
*
- * @hide
*/
public boolean isAutoWhiteBalanceLockSupported() {
String str = get(KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED);
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 3447e76c..44e7e52 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -98,11 +98,8 @@
}
@Override public boolean onTextContextMenuItem(int id) {
- // Horrible hack: select word option has to be handled by original view to work.
- if (mIME != null && id != android.R.id.startSelectingText) {
- if (mIME.onExtractTextContextMenuItem(id)) {
- return true;
- }
+ if (mIME != null && mIME.onExtractTextContextMenuItem(id)) {
+ return true;
}
return super.onTextContextMenuItem(id);
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d6f5643..d95fc8d 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -100,7 +100,7 @@
void setDataDependency(int networkType, boolean met);
- void protectVpn(in ParcelFileDescriptor socket);
+ boolean protectVpn(in ParcelFileDescriptor socket);
boolean prepareVpn(String oldPackage, String newPackage);
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 19894a0..9826bec 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -52,11 +52,26 @@
public class LinkProperties implements Parcelable {
String mIfaceName;
- private Collection<LinkAddress> mLinkAddresses;
- private Collection<InetAddress> mDnses;
- private Collection<RouteInfo> mRoutes;
+ private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
+ private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
+ private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
private ProxyProperties mHttpProxy;
+ public static class CompareResult<T> {
+ public ArrayList<T> removed = new ArrayList<T>();
+ public ArrayList<T> added = new ArrayList<T>();
+
+ @Override
+ public String toString() {
+ String retVal = "removed=[";
+ for (T addr : removed) retVal += addr.toString() + ",";
+ retVal += "] added=[";
+ for (T addr : added) retVal += addr.toString() + ",";
+ retVal += "]";
+ return retVal;
+ }
+ }
+
public LinkProperties() {
clear();
}
@@ -121,9 +136,9 @@
public void clear() {
mIfaceName = null;
- mLinkAddresses = new ArrayList<LinkAddress>();
- mDnses = new ArrayList<InetAddress>();
- mRoutes = new ArrayList<RouteInfo>();
+ mLinkAddresses.clear();
+ mDnses.clear();
+ mRoutes.clear();
mHttpProxy = null;
}
@@ -155,6 +170,63 @@
return ifaceName + linkAddresses + routes + dns + proxy;
}
+ /**
+ * Compares this {@code LinkProperties} interface name against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalInterfaceName(LinkProperties target) {
+ return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
+ }
+
+ /**
+ * Compares this {@code LinkProperties} interface name against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalAddresses(LinkProperties target) {
+ Collection<InetAddress> targetAddresses = target.getAddresses();
+ Collection<InetAddress> sourceAddresses = getAddresses();
+ return (sourceAddresses.size() == targetAddresses.size()) ?
+ sourceAddresses.containsAll(targetAddresses) : false;
+ }
+
+ /**
+ * Compares this {@code LinkProperties} DNS addresses against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalDnses(LinkProperties target) {
+ Collection<InetAddress> targetDnses = target.getDnses();
+ return (mDnses.size() == targetDnses.size()) ?
+ mDnses.containsAll(targetDnses) : false;
+ }
+
+ /**
+ * Compares this {@code LinkProperties} Routes against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalRoutes(LinkProperties target) {
+ Collection<RouteInfo> targetRoutes = target.getRoutes();
+ return (mRoutes.size() == targetRoutes.size()) ?
+ mRoutes.containsAll(targetRoutes) : false;
+ }
+
+ /**
+ * Compares this {@code LinkProperties} HttpProxy against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalHttpProxy(LinkProperties target) {
+ return getHttpProxy() == null ? target.getHttpProxy() == null :
+ getHttpProxy().equals(target.getHttpProxy());
+ }
@Override
/**
@@ -176,32 +248,107 @@
if (!(obj instanceof LinkProperties)) return false;
- boolean sameAddresses;
- boolean sameDnses;
- boolean sameRoutes;
-
LinkProperties target = (LinkProperties) obj;
- Collection<InetAddress> targetAddresses = target.getAddresses();
- Collection<InetAddress> sourceAddresses = getAddresses();
- sameAddresses = (sourceAddresses.size() == targetAddresses.size()) ?
- sourceAddresses.containsAll(targetAddresses) : false;
-
- Collection<InetAddress> targetDnses = target.getDnses();
- sameDnses = (mDnses.size() == targetDnses.size()) ?
- mDnses.containsAll(targetDnses) : false;
-
- Collection<RouteInfo> targetRoutes = target.getRoutes();
- sameRoutes = (mRoutes.size() == targetRoutes.size()) ?
- mRoutes.containsAll(targetRoutes) : false;
-
- return
- sameAddresses && sameDnses && sameRoutes
- && TextUtils.equals(getInterfaceName(), target.getInterfaceName())
- && (getHttpProxy() == null ? target.getHttpProxy() == null :
- getHttpProxy().equals(target.getHttpProxy()));
+ return isIdenticalInterfaceName(target) &&
+ isIdenticalAddresses(target) &&
+ isIdenticalDnses(target) &&
+ isIdenticalRoutes(target) &&
+ isIdenticalHttpProxy(target);
}
+ /**
+ * Return two lists, a list of addresses that would be removed from
+ * mLinkAddresses and a list of addresses that would be added to
+ * mLinkAddress which would then result in target and mLinkAddresses
+ * being the same list.
+ *
+ * @param target is a LinkProperties with the new list of addresses
+ * @return the removed and added lists.
+ */
+ public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
+ /*
+ * Duplicate the LinkAddresses into removed, we will be removing
+ * address which are common between mLinkAddresses and target
+ * leaving the addresses that are different. And address which
+ * are in target but not in mLinkAddresses are placed in the
+ * addedAddresses.
+ */
+ CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
+ result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
+ result.added.clear();
+ if (target != null) {
+ for (LinkAddress newAddress : target.getLinkAddresses()) {
+ if (! result.removed.remove(newAddress)) {
+ result.added.add(newAddress);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return two lists, a list of dns addresses that would be removed from
+ * mDnses and a list of addresses that would be added to
+ * mDnses which would then result in target and mDnses
+ * being the same list.
+ *
+ * @param target is a LinkProperties with the new list of dns addresses
+ * @return the removed and added lists.
+ */
+ public CompareResult<InetAddress> compareDnses(LinkProperties target) {
+ /*
+ * Duplicate the InetAddresses into removed, we will be removing
+ * dns address which are common between mDnses and target
+ * leaving the addresses that are different. And dns address which
+ * are in target but not in mDnses are placed in the
+ * addedAddresses.
+ */
+ CompareResult<InetAddress> result = new CompareResult<InetAddress>();
+
+ result.removed = new ArrayList<InetAddress>(mDnses);
+ result.added.clear();
+ if (target != null) {
+ for (InetAddress newAddress : target.getDnses()) {
+ if (! result.removed.remove(newAddress)) {
+ result.added.add(newAddress);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return two lists, a list of routes that would be removed from
+ * mRoutes and a list of routes that would be added to
+ * mRoutes which would then result in target and mRoutes
+ * being the same list.
+ *
+ * @param target is a LinkProperties with the new list of routes
+ * @return the removed and added lists.
+ */
+ public CompareResult<RouteInfo> compareRoutes(LinkProperties target) {
+ /*
+ * Duplicate the RouteInfos into removed, we will be removing
+ * routes which are common between mDnses and target
+ * leaving the routes that are different. And route address which
+ * are in target but not in mRoutes are placed in added.
+ */
+ CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
+
+ result.removed = new ArrayList<RouteInfo>(mRoutes);
+ result.added.clear();
+ if (target != null) {
+ for (RouteInfo r : target.getRoutes()) {
+ if (! result.removed.remove(r)) {
+ result.added.add(r);
+ }
+ }
+ }
+ return result;
+ }
+
+
@Override
/**
* generate hashcode based on significant fields
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index ccef122..aa6400bb 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -19,6 +19,7 @@
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import android.content.Context;
+import android.os.Build;
import android.telephony.TelephonyManager;
import com.android.internal.util.Objects;
@@ -68,7 +69,7 @@
subTypeName = Integer.toString(mSubType);
}
- final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+ final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
final String roaming = mRoaming ? ", ROAMING" : "";
return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId="
+ scrubSubscriberId + roaming + "]";
@@ -91,6 +92,17 @@
}
/**
+ * Scrub given IMSI on production builds.
+ */
+ public static String scrubSubscriberId(String subscriberId) {
+ if ("eng".equals(Build.TYPE)) {
+ return subscriberId;
+ } else {
+ return subscriberId != null ? "valid" : "null";
+ }
+ }
+
+ /**
* Build a {@link NetworkIdentity} from the given {@link NetworkState},
* assuming that any mobile networks are using the current IMSI.
*/
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 9d40c42..fbff7d8 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -47,13 +47,39 @@
* {@link SystemClock#elapsedRealtime()} timestamp when this data was
* generated.
*/
- public final long elapsedRealtime;
- public int size;
- public String[] iface;
- public int[] uid;
- public int[] tag;
- public long[] rx;
- public long[] tx;
+ private final long elapsedRealtime;
+ private int size;
+ private String[] iface;
+ private int[] uid;
+ private int[] tag;
+ private long[] rxBytes;
+ private long[] rxPackets;
+ private long[] txBytes;
+ private long[] txPackets;
+
+ public static class Entry {
+ public String iface;
+ public int uid;
+ public int tag;
+ public long rxBytes;
+ public long rxPackets;
+ public long txBytes;
+ public long txPackets;
+
+ public Entry() {
+ }
+
+ public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes,
+ long txPackets) {
+ this.iface = iface;
+ this.uid = uid;
+ this.tag = tag;
+ this.rxBytes = rxBytes;
+ this.rxPackets = rxPackets;
+ this.txBytes = txBytes;
+ this.txPackets = txPackets;
+ }
+ }
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
@@ -61,8 +87,10 @@
this.iface = new String[initialSize];
this.uid = new int[initialSize];
this.tag = new int[initialSize];
- this.rx = new long[initialSize];
- this.tx = new long[initialSize];
+ this.rxBytes = new long[initialSize];
+ this.rxPackets = new long[initialSize];
+ this.txBytes = new long[initialSize];
+ this.txPackets = new long[initialSize];
}
public NetworkStats(Parcel parcel) {
@@ -71,46 +99,93 @@
iface = parcel.createStringArray();
uid = parcel.createIntArray();
tag = parcel.createIntArray();
- rx = parcel.createLongArray();
- tx = parcel.createLongArray();
+ rxBytes = parcel.createLongArray();
+ rxPackets = parcel.createLongArray();
+ txBytes = parcel.createLongArray();
+ txPackets = parcel.createLongArray();
+ }
+
+ public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
+ long txBytes, long txPackets) {
+ return addValues(new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets));
}
/**
- * Add new stats entry with given values.
+ * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
+ * object can be recycled across multiple calls.
*/
- public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) {
+ public NetworkStats addValues(Entry entry) {
if (size >= this.iface.length) {
- final int newLength = Math.max(this.iface.length, 10) * 3 / 2;
- this.iface = Arrays.copyOf(this.iface, newLength);
- this.uid = Arrays.copyOf(this.uid, newLength);
- this.tag = Arrays.copyOf(this.tag, newLength);
- this.rx = Arrays.copyOf(this.rx, newLength);
- this.tx = Arrays.copyOf(this.tx, newLength);
+ final int newLength = Math.max(iface.length, 10) * 3 / 2;
+ iface = Arrays.copyOf(iface, newLength);
+ uid = Arrays.copyOf(uid, newLength);
+ tag = Arrays.copyOf(tag, newLength);
+ rxBytes = Arrays.copyOf(rxBytes, newLength);
+ rxPackets = Arrays.copyOf(rxPackets, newLength);
+ txBytes = Arrays.copyOf(txBytes, newLength);
+ txPackets = Arrays.copyOf(txPackets, newLength);
}
- this.iface[size] = iface;
- this.uid[size] = uid;
- this.tag[size] = tag;
- this.rx[size] = rx;
- this.tx[size] = tx;
+ iface[size] = entry.iface;
+ uid[size] = entry.uid;
+ tag[size] = entry.tag;
+ rxBytes[size] = entry.rxBytes;
+ rxPackets[size] = entry.rxPackets;
+ txBytes[size] = entry.txBytes;
+ txPackets[size] = entry.txPackets;
size++;
return this;
}
/**
+ * Return specific stats entry.
+ */
+ public Entry getValues(int i, Entry recycle) {
+ final Entry entry = recycle != null ? recycle : new Entry();
+ entry.iface = iface[i];
+ entry.uid = uid[i];
+ entry.tag = tag[i];
+ entry.rxBytes = rxBytes[i];
+ entry.rxPackets = rxPackets[i];
+ entry.txBytes = txBytes[i];
+ entry.txPackets = txPackets[i];
+ return entry;
+ }
+
+ public long getElapsedRealtime() {
+ return elapsedRealtime;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ // @VisibleForTesting
+ public int internalSize() {
+ return iface.length;
+ }
+
+ public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
+ long txBytes, long txPackets) {
+ return combineValues(new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets));
+ }
+
+ /**
* Combine given values with an existing row, or create a new row if
* {@link #findIndex(String, int, int)} is unable to find match. Can also be
* used to subtract values from existing rows.
*/
- public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) {
- final int i = findIndex(iface, uid, tag);
+ public NetworkStats combineValues(Entry entry) {
+ final int i = findIndex(entry.iface, entry.uid, entry.tag);
if (i == -1) {
// only create new entry when positive contribution
- addEntry(iface, uid, tag, rx, tx);
+ addValues(entry);
} else {
- this.rx[i] += rx;
- this.tx[i] += tx;
+ rxBytes[i] += entry.rxBytes;
+ rxPackets[i] += entry.rxPackets;
+ txBytes[i] += entry.txBytes;
+ txPackets[i] += entry.txPackets;
}
return this;
}
@@ -199,30 +274,41 @@
}
// result will have our rows, and elapsed time between snapshots
+ final Entry entry = new Entry();
final NetworkStats result = new NetworkStats(deltaRealtime, size);
for (int i = 0; i < size; i++) {
- final String iface = this.iface[i];
- final int uid = this.uid[i];
- final int tag = this.tag[i];
+ entry.iface = iface[i];
+ entry.uid = uid[i];
+ entry.tag = tag[i];
// find remote row that matches, and subtract
- final int j = value.findIndex(iface, uid, tag);
+ final int j = value.findIndex(entry.iface, entry.uid, entry.tag);
if (j == -1) {
// newly appearing row, return entire value
- result.addEntry(iface, uid, tag, this.rx[i], this.tx[i]);
+ entry.rxBytes = rxBytes[i];
+ entry.rxPackets = rxPackets[i];
+ entry.txBytes = txBytes[i];
+ entry.txPackets = txPackets[i];
} else {
// existing row, subtract remote value
- long rx = this.rx[i] - value.rx[j];
- long tx = this.tx[i] - value.tx[j];
- if (enforceMonotonic && (rx < 0 || tx < 0)) {
+ entry.rxBytes = rxBytes[i] - value.rxBytes[j];
+ entry.rxPackets = rxPackets[i] - value.rxPackets[j];
+ entry.txBytes = txBytes[i] - value.txBytes[j];
+ entry.txPackets = txPackets[i] - value.txPackets[j];
+ if (enforceMonotonic
+ && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
+ || entry.txPackets < 0)) {
throw new IllegalArgumentException("found non-monotonic values");
}
if (clampNegative) {
- rx = Math.max(0, rx);
- tx = Math.max(0, tx);
+ entry.rxBytes = Math.max(0, entry.rxBytes);
+ entry.rxPackets = Math.max(0, entry.rxPackets);
+ entry.txBytes = Math.max(0, entry.txBytes);
+ entry.txPackets = Math.max(0, entry.txPackets);
}
- result.addEntry(iface, uid, tag, rx, tx);
}
+
+ result.addValues(entry);
}
return result;
@@ -235,13 +321,15 @@
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime);
- for (int i = 0; i < iface.length; i++) {
+ for (int i = 0; i < size; i++) {
pw.print(prefix);
pw.print(" iface="); pw.print(iface[i]);
pw.print(" uid="); pw.print(uid[i]);
pw.print(" tag="); pw.print(tag[i]);
- pw.print(" rx="); pw.print(rx[i]);
- pw.print(" tx="); pw.println(tx[i]);
+ pw.print(" rxBytes="); pw.print(rxBytes[i]);
+ pw.print(" rxPackets="); pw.print(rxPackets[i]);
+ pw.print(" txBytes="); pw.print(txBytes[i]);
+ pw.print(" txPackets="); pw.println(txPackets[i]);
}
}
@@ -264,8 +352,10 @@
dest.writeStringArray(iface);
dest.writeIntArray(uid);
dest.writeIntArray(tag);
- dest.writeLongArray(rx);
- dest.writeLongArray(tx);
+ dest.writeLongArray(rxBytes);
+ dest.writeLongArray(rxPackets);
+ dest.writeLongArray(txBytes);
+ dest.writeLongArray(txPackets);
}
public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index dd2945c..8bd1738 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -43,13 +43,20 @@
private static final int VERSION_INIT = 1;
// TODO: teach about varint encoding to use less disk space
+ // TODO: extend to record rxPackets/txPackets
- public final long bucketDuration;
+ private final long bucketDuration;
+ private int bucketCount;
+ private long[] bucketStart;
+ private long[] rxBytes;
+ private long[] txBytes;
- public int bucketCount;
- public long[] bucketStart;
- public long[] rx;
- public long[] tx;
+ public static class Entry {
+ public long bucketStart;
+ public long bucketDuration;
+ public long rxBytes;
+ public long txBytes;
+ }
public NetworkStatsHistory(long bucketDuration) {
this(bucketDuration, 10);
@@ -58,16 +65,16 @@
public NetworkStatsHistory(long bucketDuration, int initialSize) {
this.bucketDuration = bucketDuration;
bucketStart = new long[initialSize];
- rx = new long[initialSize];
- tx = new long[initialSize];
+ rxBytes = new long[initialSize];
+ txBytes = new long[initialSize];
bucketCount = 0;
}
public NetworkStatsHistory(Parcel in) {
bucketDuration = in.readLong();
bucketStart = readLongArray(in);
- rx = in.createLongArray();
- tx = in.createLongArray();
+ rxBytes = in.createLongArray();
+ txBytes = in.createLongArray();
bucketCount = bucketStart.length;
}
@@ -75,8 +82,8 @@
public void writeToParcel(Parcel out, int flags) {
out.writeLong(bucketDuration);
writeLongArray(out, bucketStart, bucketCount);
- writeLongArray(out, rx, bucketCount);
- writeLongArray(out, tx, bucketCount);
+ writeLongArray(out, rxBytes, bucketCount);
+ writeLongArray(out, txBytes, bucketCount);
}
public NetworkStatsHistory(DataInputStream in) throws IOException {
@@ -85,8 +92,8 @@
case VERSION_INIT: {
bucketDuration = in.readLong();
bucketStart = readLongArray(in);
- rx = readLongArray(in);
- tx = readLongArray(in);
+ rxBytes = readLongArray(in);
+ txBytes = readLongArray(in);
bucketCount = bucketStart.length;
break;
}
@@ -100,8 +107,8 @@
out.writeInt(VERSION_INIT);
out.writeLong(bucketDuration);
writeLongArray(out, bucketStart, bucketCount);
- writeLongArray(out, rx, bucketCount);
- writeLongArray(out, tx, bucketCount);
+ writeLongArray(out, rxBytes, bucketCount);
+ writeLongArray(out, txBytes, bucketCount);
}
/** {@inheritDoc} */
@@ -109,6 +116,42 @@
return 0;
}
+ public int size() {
+ return bucketCount;
+ }
+
+ public long getBucketDuration() {
+ return bucketDuration;
+ }
+
+ public long getStart() {
+ if (bucketCount > 0) {
+ return bucketStart[0];
+ } else {
+ return Long.MAX_VALUE;
+ }
+ }
+
+ public long getEnd() {
+ if (bucketCount > 0) {
+ return bucketStart[bucketCount - 1] + bucketDuration;
+ } else {
+ return Long.MIN_VALUE;
+ }
+ }
+
+ /**
+ * Return specific stats entry.
+ */
+ public Entry getValues(int i, Entry recycle) {
+ final Entry entry = recycle != null ? recycle : new Entry();
+ entry.bucketStart = bucketStart[i];
+ entry.bucketDuration = bucketDuration;
+ entry.rxBytes = rxBytes[i];
+ entry.txBytes = txBytes[i];
+ return entry;
+ }
+
/**
* Record that data traffic occurred in the given time range. Will
* distribute across internal buckets, creating new buckets as needed.
@@ -135,8 +178,8 @@
final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
if (overlap > 0) {
- this.rx[i] += rx * overlap / duration;
- this.tx[i] += tx * overlap / duration;
+ this.rxBytes[i] += rx * overlap / duration;
+ this.txBytes[i] += tx * overlap / duration;
}
}
}
@@ -149,7 +192,7 @@
for (int i = 0; i < input.bucketCount; i++) {
final long start = input.bucketStart[i];
final long end = start + input.bucketDuration;
- recordData(start, end, input.rx[i], input.tx[i]);
+ recordData(start, end, input.rxBytes[i], input.txBytes[i]);
}
}
@@ -179,8 +222,8 @@
if (bucketCount >= bucketStart.length) {
final int newLength = Math.max(bucketStart.length, 10) * 3 / 2;
bucketStart = Arrays.copyOf(bucketStart, newLength);
- rx = Arrays.copyOf(rx, newLength);
- tx = Arrays.copyOf(tx, newLength);
+ rxBytes = Arrays.copyOf(rxBytes, newLength);
+ txBytes = Arrays.copyOf(txBytes, newLength);
}
// create gap when inserting bucket in middle
@@ -189,13 +232,13 @@
final int length = bucketCount - index;
System.arraycopy(bucketStart, index, bucketStart, dstPos, length);
- System.arraycopy(rx, index, rx, dstPos, length);
- System.arraycopy(tx, index, tx, dstPos, length);
+ System.arraycopy(rxBytes, index, rxBytes, dstPos, length);
+ System.arraycopy(txBytes, index, txBytes, dstPos, length);
}
bucketStart[index] = start;
- rx[index] = 0;
- tx[index] = 0;
+ rxBytes[index] = 0;
+ txBytes[index] = 0;
bucketCount++;
}
@@ -216,8 +259,8 @@
if (i > 0) {
final int length = bucketStart.length;
bucketStart = Arrays.copyOfRange(bucketStart, i, length);
- rx = Arrays.copyOfRange(rx, i, length);
- tx = Arrays.copyOfRange(tx, i, length);
+ rxBytes = Arrays.copyOfRange(rxBytes, i, length);
+ txBytes = Arrays.copyOfRange(txBytes, i, length);
bucketCount -= i;
}
}
@@ -226,9 +269,20 @@
* Return interpolated data usage across the requested range. Interpolates
* across buckets, so values may be rounded slightly.
*/
- public long[] getTotalData(long start, long end, long[] outTotal) {
- long rx = 0;
- long tx = 0;
+ public Entry getValues(long start, long end, Entry recycle) {
+ return getValues(start, end, Long.MAX_VALUE, recycle);
+ }
+
+ /**
+ * Return interpolated data usage across the requested range. Interpolates
+ * across buckets, so values may be rounded slightly.
+ */
+ public Entry getValues(long start, long end, long now, Entry recycle) {
+ final Entry entry = recycle != null ? recycle : new Entry();
+ entry.bucketStart = start;
+ entry.bucketDuration = end - start;
+ entry.rxBytes = 0;
+ entry.txBytes = 0;
for (int i = bucketCount - 1; i >= 0; i--) {
final long curStart = bucketStart[i];
@@ -239,19 +293,19 @@
// bucket is newer than record; keep looking
if (curStart > end) continue;
+ // include full value for active buckets, otherwise only fractional
+ final boolean activeBucket = curStart < now && curEnd > now;
final long overlap = Math.min(curEnd, end) - Math.max(curStart, start);
- if (overlap > 0) {
- rx += this.rx[i] * overlap / bucketDuration;
- tx += this.tx[i] * overlap / bucketDuration;
+ if (activeBucket || overlap == bucketDuration) {
+ entry.rxBytes += rxBytes[i];
+ entry.txBytes += txBytes[i];
+ } else if (overlap > 0) {
+ entry.rxBytes += rxBytes[i] * overlap / bucketDuration;
+ entry.txBytes += txBytes[i] * overlap / bucketDuration;
}
}
- if (outTotal == null || outTotal.length != 2) {
- outTotal = new long[2];
- }
- outTotal[0] = rx;
- outTotal[1] = tx;
- return outTotal;
+ return entry;
}
/**
@@ -292,8 +346,8 @@
for (int i = start; i < bucketCount; i++) {
pw.print(prefix);
pw.print(" bucketStart="); pw.print(bucketStart[i]);
- pw.print(" rx="); pw.print(rx[i]);
- pw.print(" tx="); pw.println(tx[i]);
+ pw.print(" rxBytes="); pw.print(rxBytes[i]);
+ pw.print(" txBytes="); pw.println(txBytes[i]);
}
}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 9381f1d..cd49023 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -16,9 +16,11 @@
package android.net;
+import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkIdentity.scrubSubscriberId;
import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
@@ -38,41 +40,69 @@
*/
public class NetworkTemplate implements Parcelable {
+ /** {@hide} */
+ public static final int MATCH_MOBILE_ALL = 1;
+ /** {@hide} */
+ public static final int MATCH_MOBILE_3G_LOWER = 2;
+ /** {@hide} */
+ public static final int MATCH_MOBILE_4G = 3;
+ /** {@hide} */
+ public static final int MATCH_WIFI = 4;
+ /** {@hide} */
+ public static final int MATCH_ETHERNET = 5;
+
/**
* Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
* networks together. Only uses statistics for requested IMSI.
*/
- public static final int MATCH_MOBILE_ALL = 1;
+ public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
+ return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
+ }
/**
* Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
* networks together that roughly meet a "3G" definition, or lower. Only
* uses statistics for requested IMSI.
*/
- public static final int MATCH_MOBILE_3G_LOWER = 2;
+ public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
+ return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId);
+ }
/**
* Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
* networks together that meet a "4G" definition. Only uses statistics for
* requested IMSI.
*/
- public static final int MATCH_MOBILE_4G = 3;
+ public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
+ return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId);
+ }
/**
* Template to combine all {@link ConnectivityManager#TYPE_WIFI} style
* networks together.
*/
- public static final int MATCH_WIFI = 4;
+ public static NetworkTemplate buildTemplateWifi() {
+ return new NetworkTemplate(MATCH_WIFI, null);
+ }
- final int mMatchRule;
- final String mSubscriberId;
+ /**
+ * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style
+ * networks together.
+ */
+ public static NetworkTemplate buildTemplateEthernet() {
+ return new NetworkTemplate(MATCH_ETHERNET, null);
+ }
+ private final int mMatchRule;
+ private final String mSubscriberId;
+
+ /** {@hide} */
public NetworkTemplate(int matchRule, String subscriberId) {
this.mMatchRule = matchRule;
this.mSubscriberId = subscriberId;
}
- public NetworkTemplate(Parcel in) {
+ private NetworkTemplate(Parcel in) {
mMatchRule = in.readInt();
mSubscriberId = in.readString();
}
@@ -90,7 +120,7 @@
@Override
public String toString() {
- final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null";
+ final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId="
+ scrubSubscriberId;
}
@@ -110,16 +140,18 @@
return false;
}
+ /** {@hide} */
public int getMatchRule() {
return mMatchRule;
}
+ /** {@hide} */
public String getSubscriberId() {
return mSubscriberId;
}
/**
- * Test if this network matches the given template and IMEI.
+ * Test if this network matches the given template and IMSI.
*/
public boolean matches(NetworkIdentity ident) {
switch (mMatchRule) {
@@ -131,13 +163,15 @@
return matchesMobile4g(ident);
case MATCH_WIFI:
return matchesWifi(ident);
+ case MATCH_ETHERNET:
+ return matchesEthernet(ident);
default:
throw new IllegalArgumentException("unknown network template");
}
}
/**
- * Check if mobile network with matching IMEI. Also matches
+ * Check if mobile network with matching IMSI. Also matches
* {@link #TYPE_WIMAX}.
*/
private boolean matchesMobile(NetworkIdentity ident) {
@@ -150,7 +184,7 @@
}
/**
- * Check if mobile network classified 3G or lower with matching IMEI.
+ * Check if mobile network classified 3G or lower with matching IMSI.
*/
private boolean matchesMobile3gLower(NetworkIdentity ident) {
if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) {
@@ -165,7 +199,7 @@
}
/**
- * Check if mobile network classified 4G with matching IMEI. Also matches
+ * Check if mobile network classified 4G with matching IMSI. Also matches
* {@link #TYPE_WIMAX}.
*/
private boolean matchesMobile4g(NetworkIdentity ident) {
@@ -190,7 +224,17 @@
return false;
}
- public static String getMatchRuleName(int matchRule) {
+ /**
+ * Check if matches Ethernet network template.
+ */
+ private boolean matchesEthernet(NetworkIdentity ident) {
+ if (ident.mType == TYPE_ETHERNET) {
+ return true;
+ }
+ return false;
+ }
+
+ private static String getMatchRuleName(int matchRule) {
switch (matchRule) {
case MATCH_MOBILE_3G_LOWER:
return "MOBILE_3G_LOWER";
@@ -200,6 +244,8 @@
return "MOBILE_ALL";
case MATCH_WIFI:
return "WIFI";
+ case MATCH_ETHERNET:
+ return "ETHERNET";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 8e5ddda..275f32a 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -43,6 +43,7 @@
private final InetAddress mGateway;
private final boolean mIsDefault;
+ private final boolean mIsHost;
public RouteInfo(LinkAddress destination, InetAddress gateway) {
if (destination == null) {
@@ -68,6 +69,7 @@
destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
mGateway = gateway;
mIsDefault = isDefault();
+ mIsHost = isHost();
}
public RouteInfo(InetAddress gateway) {
@@ -88,6 +90,10 @@
}
}
+ private boolean isHost() {
+ return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY));
+ }
+
private boolean isDefault() {
boolean val = false;
if (mGateway != null) {
@@ -100,6 +106,7 @@
return val;
}
+
public LinkAddress getDestination() {
return mDestination;
}
@@ -112,6 +119,10 @@
return mIsDefault;
}
+ public boolean isHostRoute() {
+ return mIsHost;
+ }
+
public String toString() {
String val = "";
if (mDestination != null) val = mDestination.toString();
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 641a576..c534e58 100644
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -65,7 +65,7 @@
import android.util.Log;
/**
- * Subclass of the Apache {@link DefaultHttpClient} that is configured with
+ * Implementation of the Apache {@link DefaultHttpClient} that is configured with
* reasonable default settings and registered schemes for Android, and
* also lets the user add {@link HttpRequestInterceptor} classes.
* Don't create this directly, use the {@link #newInstance} factory method.
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 0eb8cd8..b668f30 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -334,8 +334,6 @@
/**
* Creates an NDEF record of well known type URI.
- * TODO: Make a public API
- * @hide
*/
public static NdefRecord createUri(Uri uri) {
return createUri(uri.toString());
@@ -343,8 +341,6 @@
/**
* Creates an NDEF record of well known type URI.
- * TODO: Make a public API
- * @hide
*/
public static NdefRecord createUri(String uriString) {
byte prefix = 0x0;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index ba69246..da2afb6 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -129,6 +129,11 @@
/** The shared dirty pages used by everything else. */
public int otherSharedDirty;
+ /** @hide */
+ public static final int NUM_OTHER_STATS = 9;
+
+ private int[] otherStats = new int[NUM_OTHER_STATS*3];
+
public MemoryInfo() {
}
@@ -153,6 +158,38 @@
return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
}
+ /* @hide */
+ public int getOtherPss(int which) {
+ return otherStats[which*3];
+ }
+
+ /* @hide */
+ public int getOtherPrivateDirty(int which) {
+ return otherStats[which*3 + 1];
+ }
+
+ /* @hide */
+ public int getOtherSharedDirty(int which) {
+ return otherStats[which*3 + 2];
+ }
+
+
+ /* @hide */
+ public static String getOtherLabel(int which) {
+ switch (which) {
+ case 0: return "Cursor";
+ case 1: return "Ashmem";
+ case 2: return "Other dev";
+ case 3: return ".so mmap";
+ case 4: return ".jar mmap";
+ case 5: return ".apk mmap";
+ case 6: return ".ttf mmap";
+ case 7: return ".dex mmap";
+ case 8: return "Other mmap";
+ default: return "????";
+ }
+ }
+
public int describeContents() {
return 0;
}
@@ -167,6 +204,7 @@
dest.writeInt(otherPss);
dest.writeInt(otherPrivateDirty);
dest.writeInt(otherSharedDirty);
+ dest.writeIntArray(otherStats);
}
public void readFromParcel(Parcel source) {
@@ -179,6 +217,7 @@
otherPss = source.readInt();
otherPrivateDirty = source.readInt();
otherSharedDirty = source.readInt();
+ otherStats = source.createIntArray();
}
public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 165e438..cd39d5c 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -169,6 +169,21 @@
}
/**
+ * Returns a string representing the name of the specified message.
+ * The default implementation will either return the class name of the
+ * message callback if any, or the hexadecimal representation of the
+ * message "what" field.
+ *
+ * @param message The message whose name is being queried
+ */
+ public String getMessageName(Message message) {
+ if (message.callback != null) {
+ return message.callback.getClass().getName();
+ }
+ return "0x" + Integer.toHexString(message.what);
+ }
+
+ /**
* Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
* If you don't want that facility, just call Message.obtain() instead.
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 3edd692..720e802b 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -52,7 +52,6 @@
*/
public class Looper {
private static final String TAG = "Looper";
- private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE);
// sThreadLocal.get() will return null unless you've called prepare().
private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
@@ -70,7 +69,7 @@
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
- public static final void prepare() {
+ public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
@@ -83,12 +82,10 @@
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
- public static final void prepareMainLooper() {
+ public static void prepareMainLooper() {
prepare();
setMainLooper(myLooper());
- if (Process.supportsProcesses()) {
- myLooper().mQueue.mQuitAllowed = false;
- }
+ myLooper().mQueue.mQuitAllowed = false;
}
private synchronized static void setMainLooper(Looper looper) {
@@ -97,7 +94,7 @@
/** Returns the application's main looper, which lives in the main thread of the application.
*/
- public synchronized static final Looper getMainLooper() {
+ public synchronized static Looper getMainLooper() {
return mMainLooper;
}
@@ -105,7 +102,7 @@
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
- public static final void loop() {
+ public static void loop() {
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
@@ -124,20 +121,36 @@
// No target is a magic identifier for the quit message.
return;
}
- if (me.mLogging != null) me.mLogging.println(
- ">>>>> Dispatching to " + msg.target + " "
- + msg.callback + ": " + msg.what
- );
+
+ long wallStart = 0;
+ long threadStart = 0;
+
+ // This must be in a local variable, in case a UI event sets the logger
+ Printer logging = me.mLogging;
+ if (logging != null) {
+ logging.println(">>>>> Dispatching to " + msg.target + " " +
+ msg.callback + ": " + msg.what);
+ wallStart = System.currentTimeMillis();
+ threadStart = SystemClock.currentThreadTimeMillis();
+ }
+
msg.target.dispatchMessage(msg);
- if (me.mLogging != null) me.mLogging.println(
- "<<<<< Finished to " + msg.target + " "
- + msg.callback);
-
+
+ if (logging != null) {
+ long wallTime = System.currentTimeMillis() - wallStart;
+ long threadTime = SystemClock.currentThreadTimeMillis() - threadStart;
+
+ logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
+ if (logging instanceof Profiler) {
+ ((Profiler) logging).profile(msg, wallStart, wallTime, threadTime);
+ }
+ }
+
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
- Log.wtf("Looper", "Thread identity changed from 0x"
+ Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
@@ -153,7 +166,7 @@
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
- public static final Looper myLooper() {
+ public static Looper myLooper() {
return sThreadLocal.get();
}
@@ -175,7 +188,7 @@
* thread. This must be called from a thread running a Looper, or a
* NullPointerException will be thrown.
*/
- public static final MessageQueue myQueue() {
+ public static MessageQueue myQueue() {
return myLooper().mQueue;
}
@@ -227,23 +240,13 @@
}
public String toString() {
- return "Looper{"
- + Integer.toHexString(System.identityHashCode(this))
- + "}";
+ return "Looper{" + Integer.toHexString(System.identityHashCode(this)) + "}";
}
- static class HandlerException extends Exception {
-
- HandlerException(Message message, Throwable cause) {
- super(createMessage(cause), cause);
- }
-
- static String createMessage(Throwable cause) {
- String causeMsg = cause.getMessage();
- if (causeMsg == null) {
- causeMsg = cause.toString();
- }
- return causeMsg;
- }
+ /**
+ * @hide
+ */
+ public static interface Profiler {
+ void profile(Message message, long wallStart, long wallTime, long threadTime);
}
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index dbefb1f..3362575 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -86,6 +86,12 @@
public static final int WIFI_UID = 1010;
/**
+ * Defines the UID/GID for the mediaserver process.
+ * @hide
+ */
+ public static final int MEDIA_UID = 1013;
+
+ /**
* Defines the GID for the group that allows write access to the SD card.
* @hide
*/
@@ -270,82 +276,25 @@
* @param targetSdkVersion The target SDK version for the app.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
- * @return int If > 0 the pid of the new process; if 0 the process is
- * being emulated by a thread
+ * @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*
* {@hide}
*/
- public static final int start(final String processClass,
+ public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int targetSdkVersion,
- String[] zygoteArgs)
- {
- if (supportsProcesses()) {
- try {
- return startViaZygote(processClass, niceName, uid, gid, gids,
- debugFlags, targetSdkVersion, zygoteArgs);
- } catch (ZygoteStartFailedEx ex) {
- Log.e(LOG_TAG,
- "Starting VM process through Zygote failed");
- throw new RuntimeException(
- "Starting VM process through Zygote failed", ex);
- }
- } else {
- // Running in single-process mode
-
- Runnable runnable = new Runnable() {
- public void run() {
- Process.invokeStaticMain(processClass);
- }
- };
-
- // Thread constructors must not be called with null names (see spec).
- if (niceName != null) {
- new Thread(runnable, niceName).start();
- } else {
- new Thread(runnable).start();
- }
-
- return 0;
- }
- }
-
- /**
- * Start a new process. Don't supply a custom nice name.
- * {@hide}
- */
- public static final int start(String processClass, int uid, int gid,
- int[] gids, int debugFlags, int targetSdkVersion,
- String[] zygoteArgs) {
- return start(processClass, "", uid, gid, gids,
- debugFlags, targetSdkVersion, zygoteArgs);
- }
-
- private static void invokeStaticMain(String className) {
- Class cl;
- Object args[] = new Object[1];
-
- args[0] = new String[0]; //this is argv
-
+ String[] zygoteArgs) {
try {
- cl = Class.forName(className);
- cl.getMethod("main", new Class[] { String[].class })
- .invoke(null, args);
- } catch (Exception ex) {
- // can be: ClassNotFoundException,
- // NoSuchMethodException, SecurityException,
- // IllegalAccessException, IllegalArgumentException
- // InvocationTargetException
- // or uncaught exception from main()
-
- Log.e(LOG_TAG, "Exception invoking static main on "
- + className, ex);
-
- throw new RuntimeException(ex);
+ return startViaZygote(processClass, niceName, uid, gid, gids,
+ debugFlags, targetSdkVersion, zygoteArgs);
+ } catch (ZygoteStartFailedEx ex) {
+ Log.e(LOG_TAG,
+ "Starting VM process through Zygote failed");
+ throw new RuntimeException(
+ "Starting VM process through Zygote failed", ex);
}
-
}
/** retry interval for opening a zygote socket */
@@ -432,14 +381,11 @@
* and returns the child's pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
* @param args argument list
- * @return PID of new child process
+ * @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
- private static int zygoteSendArgsAndGetPid(ArrayList<String> args)
+ private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
-
- int pid;
-
openZygoteSocketIfNeeded();
try {
@@ -450,7 +396,8 @@
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
- * the child or -1 on failure.
+ * the child or -1 on failure, followed by boolean to
+ * indicate whether a wrapper process was used.
*/
sZygoteWriter.write(Integer.toString(args.size()));
@@ -470,11 +417,13 @@
sZygoteWriter.flush();
// Should there be a timeout on this?
- pid = sZygoteInputStream.readInt();
-
- if (pid < 0) {
+ ProcessStartResult result = new ProcessStartResult();
+ result.pid = sZygoteInputStream.readInt();
+ if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
+ result.usingWrapper = sZygoteInputStream.readBoolean();
+ return result;
} catch (IOException ex) {
try {
if (sZygoteSocket != null) {
@@ -489,8 +438,6 @@
throw new ZygoteStartFailedEx(ex);
}
-
- return pid;
}
/**
@@ -505,18 +452,16 @@
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param extraArgs Additional arguments to supply to the zygote process.
- * @return PID
+ * @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
- private static int startViaZygote(final String processClass,
+ private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int targetSdkVersion,
String[] extraArgs)
throws ZygoteStartFailedEx {
- int pid;
-
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();
@@ -572,15 +517,9 @@
argsForZygote.add(arg);
}
}
-
- pid = zygoteSendArgsAndGetPid(argsForZygote);
- }
- if (pid <= 0) {
- throw new ZygoteStartFailedEx("zygote start failed:" + pid);
+ return zygoteSendArgsAndGetResult(argsForZygote);
}
-
- return pid;
}
/**
@@ -740,8 +679,13 @@
*
* @return Returns true if the system can run in multiple processes, else
* false if everything is running in a single process.
+ *
+ * @deprecated This method always returns true. Do not use.
*/
- public static final native boolean supportsProcesses();
+ @Deprecated
+ public static final boolean supportsProcesses() {
+ return true;
+ }
/**
* Set the out-of-memory badness adjustment for a process.
@@ -859,4 +803,21 @@
* @hide
*/
public static final native long getPss(int pid);
+
+ /**
+ * Specifies the outcome of having started a process.
+ * @hide
+ */
+ public static final class ProcessStartResult {
+ /**
+ * The PID of the newly started process.
+ * Always >= 0. (If the start failed, an exception will have been thrown instead.)
+ */
+ public int pid;
+
+ /**
+ * True if the process was started with a wrapper attached.
+ */
+ public boolean usingWrapper;
+ }
}
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index b721665..1af24f4a 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -114,7 +114,7 @@
* @hide
*/
public static void initServiceCache(Map<String, IBinder> cache) {
- if (sCache.size() != 0 && Process.supportsProcesses()) {
+ if (sCache.size() != 0) {
throw new IllegalStateException("setServiceCache may only be called once");
}
sCache.putAll(cache);
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 60900e1..2c4b8631 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -172,7 +172,10 @@
@Override
public String toString() {
- return mPath;
+ return "StorageVolume [mAllowMassStorage=" + mAllowMassStorage + ", mDescription="
+ + mDescription + ", mEmulated=" + mEmulated + ", mMaxFileSize=" + mMaxFileSize
+ + ", mMtpReserveSpace=" + mMtpReserveSpace + ", mPath=" + mPath + ", mRemovable="
+ + mRemovable + ", mStorageId=" + mStorageId + "]";
}
public static final Parcelable.Creator<StorageVolume> CREATOR =
diff --git a/core/java/android/pim/ContactsAsyncHelper.java b/core/java/android/pim/ContactsAsyncHelper.java
index 7c78a81..21fc594 100644
--- a/core/java/android/pim/ContactsAsyncHelper.java
+++ b/core/java/android/pim/ContactsAsyncHelper.java
@@ -186,7 +186,7 @@
InputStream inputStream = null;
try {
inputStream = Contacts.openContactPhotoInputStream(
- args.context.getContentResolver(), args.uri);
+ args.context.getContentResolver(), args.uri, true);
} catch (Exception e) {
Log.e(LOG_TAG, "Error opening photo input stream", e);
}
diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java
index b8919c2..7133d3a 100644
--- a/core/java/android/preference/SeekBarPreference.java
+++ b/core/java/android/preference/SeekBarPreference.java
@@ -77,6 +77,11 @@
}
@Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return a.getInt(index, 0);
+ }
+
+ @Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_UP) {
if (keyCode == KeyEvent.KEYCODE_PLUS
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 61deea4..76f198c 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -17,6 +17,7 @@
package android.provider;
import android.accounts.Account;
+import android.app.Activity;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
@@ -27,6 +28,7 @@
import android.content.Entity;
import android.content.EntityIterator;
import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils;
@@ -39,6 +41,7 @@
import android.view.View;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -135,14 +138,6 @@
public static final String ALLOW_PROFILE = "allow_profile";
/**
- * A query parameter key used to specify the package that is requesting a query.
- * This is used for restricting data based on package name.
- *
- * @hide
- */
- public static final String REQUESTING_PACKAGE_PARAM_KEY = "requesting_package";
-
- /**
* Query parameter that should be used by the client to access a specific
* {@link Directory}. The parameter value should be the _ID of the corresponding
* directory, e.g.
@@ -271,8 +266,6 @@
* <li>The URI authority is replaced with the corresponding {@link #DIRECTORY_AUTHORITY}.</li>
* <li>The {@code accountName=} and {@code accountType=} parameters are added or
* replaced using the corresponding {@link #ACCOUNT_TYPE} and {@link #ACCOUNT_NAME} values.</li>
- * <li>If the URI is missing a ContactsContract.REQUESTING_PACKAGE_PARAM_KEY
- * parameter, this parameter is added.</li>
* </ul>
* </p>
* <p>
@@ -759,11 +752,25 @@
public static final String PHOTO_ID = "photo_id";
/**
+ * Photo file ID of the full-size photo. If present, this will be used to populate
+ * {@link #PHOTO_URI}. The ID can also be used with
+ * {@link ContactsContract.DisplayPhoto#CONTENT_URI} to create a URI to the photo.
+ * If this is present, {@link #PHOTO_ID} is also guaranteed to be populated.
+ *
+ * <P>Type: INTEGER</P>
+ */
+ public static final String PHOTO_FILE_ID = "photo_file_id";
+
+ /**
* A URI that can be used to retrieve the contact's full-size photo.
+ * If PHOTO_FILE_ID is not null, this will be populated with a URI based off
+ * {@link ContactsContract.DisplayPhoto#CONTENT_URI}. Otherwise, this will
+ * be populated with the same value as {@link #PHOTO_THUMBNAIL_URI}.
* A photo can be referred to either by a URI (this field) or by ID
- * (see {@link #PHOTO_ID}). If PHOTO_ID is not null, PHOTO_URI and
- * PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa).
- * Thus using PHOTO_URI is a more robust method of retrieving contact photos.
+ * (see {@link #PHOTO_ID}). If either PHOTO_FILE_ID or PHOTO_ID is not null,
+ * PHOTO_URI and PHOTO_THUMBNAIL_URI shall not be null (but not necessarily
+ * vice versa). Thus using PHOTO_URI is a more robust method of retrieving
+ * contact photos.
*
* <P>Type: TEXT</P>
*/
@@ -776,7 +783,7 @@
* PHOTO_THUMBNAIL_URI shall not be null (but not necessarily vice versa).
* If the content provider does not differentiate between full-size photos
* and thumbnail photos, PHOTO_THUMBNAIL_URI and {@link #PHOTO_URI} can contain
- * the same value, but either both shell be null or both not null.
+ * the same value, but either both shall be null or both not null.
*
* <P>Type: TEXT</P>
*/
@@ -1700,10 +1707,15 @@
/**
* A <i>read-only</i> sub-directory of a single contact that contains
- * the contact's primary photo.
+ * the contact's primary photo. The photo may be stored in up to two ways -
+ * the default "photo" is a thumbnail-sized image stored directly in the data
+ * row, while the "display photo", if present, is a larger version stored as
+ * a file.
* <p>
* Usage example:
- *
+ * <dl>
+ * <dt>Retrieving the thumbnail-sized photo</dt>
+ * <dd>
* <pre>
* public InputStream openPhoto(long contactId) {
* Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
@@ -1726,10 +1738,29 @@
* return null;
* }
* </pre>
+ * </dd>
+ * <dt>Retrieving the larger photo version</dt>
+ * <dd>
+ * <pre>
+ * public InputStream openDisplayPhoto(long contactId) {
+ * Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ * Uri displayPhotoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.DISPLAY_PHOTO);
+ * try {
+ * AssetFileDescriptor fd =
+ * getContentResolver().openAssetFile(displayPhotoUri, "r");
+ * return fd.createInputStream();
+ * } catch (FileNotFoundException e) {
+ * return null;
+ * }
+ * }
+ * </pre>
+ * </dd>
+ * </dl>
*
* </p>
- * <p>You should also consider using the convenience method
- * {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri)}
+ * <p>You may also consider using the convenience method
+ * {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri, boolean)}
+ * to retrieve the raw photo contents of either the thumbnail-sized or the full-sized photo.
* </p>
* <p>
* This directory can be used either with a {@link #CONTENT_URI} or
@@ -1748,6 +1779,19 @@
public static final String CONTENT_DIRECTORY = "photo";
/**
+ * The directory twig for retrieving the full-size display photo.
+ */
+ public static final String DISPLAY_PHOTO = "display_photo";
+
+ /**
+ * Full-size photo file ID of the raw contact.
+ * See {@link ContactsContract.DisplayPhoto}.
+ * <p>
+ * Type: NUMBER
+ */
+ public static final String PHOTO_FILE_ID = DATA14;
+
+ /**
* Thumbnail photo of the raw contact. This is the raw bytes of an image
* that could be inflated using {@link android.graphics.BitmapFactory}.
* <p>
@@ -1757,22 +1801,37 @@
}
/**
- * Opens an InputStream for the contacts's default photo and returns the
- * photo as a byte stream. If there is not photo null will be returned.
- *
+ * Opens an InputStream for the contacts's photo and returns the
+ * photo as a byte stream.
+ * @param cr The content resolver to use for querying
* @param contactUri the contact whose photo should be used. This can be used with
* either a {@link #CONTENT_URI} or a {@link #CONTENT_LOOKUP_URI} URI.
- * </p>
-
+ * @param preferHighres If this is true and the contact has a higher resolution photo
+ * available, it is returned. If false, this function always tries to get the thumbnail
* @return an InputStream of the photo, or null if no photo is present
*/
- public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+ public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri,
+ boolean preferHighres) {
+ if (preferHighres) {
+ final Uri displayPhotoUri = Uri.withAppendedPath(contactUri,
+ Contacts.Photo.DISPLAY_PHOTO);
+ InputStream inputStream;
+ try {
+ AssetFileDescriptor fd = cr.openAssetFileDescriptor(displayPhotoUri, "r");
+ return fd.createInputStream();
+ } catch (IOException e) {
+ // fallback to the thumbnail code
+ }
+ }
+
Uri photoUri = Uri.withAppendedPath(contactUri, Photo.CONTENT_DIRECTORY);
if (photoUri == null) {
return null;
}
Cursor cursor = cr.query(photoUri,
- new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, null, null, null);
+ new String[] {
+ ContactsContract.CommonDataKinds.Photo.PHOTO
+ }, null, null, null);
try {
if (cursor == null || !cursor.moveToNext()) {
return null;
@@ -1788,6 +1847,20 @@
}
}
}
+
+ /**
+ * Opens an InputStream for the contacts's thumbnail photo and returns the
+ * photo as a byte stream.
+ * @param cr The content resolver to use for querying
+ * @param contactUri the contact whose photo should be used. This can be used with
+ * either a {@link #CONTENT_URI} or a {@link #CONTENT_LOOKUP_URI} URI.
+ * @return an InputStream of the photo, or null if no photo is present
+ * @see #openContactPhotoInputStream(ContentResolver, Uri, boolean), if instead
+ * of the thumbnail the high-res picture is preferred
+ */
+ public static InputStream openContactPhotoInputStream(ContentResolver cr, Uri contactUri) {
+ return openContactPhotoInputStream(cr, contactUri, false);
+ }
}
/**
@@ -1881,13 +1954,16 @@
public static final String CONTACT_ID = "contact_id";
/**
- * Flag indicating that this {@link RawContacts} entry and its children have
- * been restricted to specific platform apps.
- * <P>Type: INTEGER (boolean)</P>
+ * The data set within the account that this row belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' data.
*
- * @hide until finalized in future platform release
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct data for
+ * the same account type and account name.
+ * <P>Type: TEXT</P>
*/
- public static final String IS_RESTRICTED = "is_restricted";
+ public static final String DATA_SET = "data_set";
/**
* The aggregation mode for this contact.
@@ -2211,8 +2287,8 @@
* <td>The name of the account instance to which this row belongs, which when paired with
* {@link #ACCOUNT_TYPE} identifies a specific account.
* For example, this will be the Gmail address if it is a Google account.
- * It should be set at the time
- * the raw contact is inserted and never changed afterwards.</td>
+ * It should be set at the time the raw contact is inserted and never
+ * changed afterwards.</td>
* </tr>
* <tr>
* <td>String</td>
@@ -2222,8 +2298,8 @@
* <p>
* The type of account to which this row belongs, which when paired with
* {@link #ACCOUNT_NAME} identifies a specific account.
- * It should be set at the time
- * the raw contact is inserted and never changed afterwards.
+ * It should be set at the time the raw contact is inserted and never
+ * changed afterwards.
* </p>
* <p>
* To ensure uniqueness, new account types should be chosen according to the
@@ -2233,15 +2309,38 @@
* </tr>
* <tr>
* <td>String</td>
+ * <td>{@link #DATA_SET}</td>
+ * <td>read/write-once</td>
+ * <td>
+ * <p>
+ * The data set within the account that this row belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' data. The combination of {@link #ACCOUNT_TYPE},
+ * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
+ * that is associated with a single sync adapter.
+ * </p>
+ * <p>
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct data for
+ * the same account type and account name.
+ * </p>
+ * <p>
+ * It should be set at the time the raw contact is inserted and never
+ * changed afterwards.
+ * </p>
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>String</td>
* <td>{@link #SOURCE_ID}</td>
* <td>read/write</td>
* <td>String that uniquely identifies this row to its source account.
* Typically it is set at the time the raw contact is inserted and never
* changed afterwards. The one notable exception is a new raw contact: it
- * will have an account name and type, but no source id. This
- * indicates to the sync adapter that a new contact needs to be created
- * server-side and its ID stored in the corresponding SOURCE_ID field on
- * the phone.
+ * will have an account name and type (and possibly a data set), but no
+ * source id. This indicates to the sync adapter that a new contact needs
+ * to be created server-side and its ID stored in the corresponding
+ * SOURCE_ID field on the phone.
* </td>
* </tr>
* <tr>
@@ -2482,6 +2581,56 @@
}
/**
+ * <p>
+ * A sub-directory of a single raw contact that represents its primary
+ * display photo. To access this directory append
+ * {@link RawContacts.DisplayPhoto#CONTENT_DIRECTORY} to the raw contact URI.
+ * The resulting URI represents an image file, and should be interacted with
+ * using ContentProvider.openAssetFile.
+ * <p>
+ * <p>
+ * Note that this sub-directory also supports opening the photo as an asset file
+ * in write mode. Callers can create or replace the primary photo associated
+ * with this raw contact by opening the asset file and writing the full-size
+ * photo contents into it. When the file is closed, the image will be parsed,
+ * sized down if necessary for the full-size display photo and thumbnail
+ * dimensions, and stored.
+ * </p>
+ * <p>
+ * Usage example:
+ * <pre>
+ * public void writeDisplayPhoto(long rawContactId, byte[] photo) {
+ * Uri rawContactPhotoUri = Uri.withAppendedPath(
+ * ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
+ * RawContacts.DisplayPhoto.CONTENT_DIRECTORY);
+ * try {
+ * AssetFileDescriptor fd =
+ * getContentResolver().openAssetFile(rawContactPhotoUri, "rw");
+ * OutputStream os = fd.createOutputStream();
+ * os.write(photo);
+ * os.close();
+ * fd.close();
+ * } catch (IOException e) {
+ * // Handle error cases.
+ * }
+ * }
+ * </pre>
+ * </p>
+ */
+ public static final class DisplayPhoto {
+ /**
+ * No public constructor since this is a utility class
+ */
+ private DisplayPhoto() {
+ }
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "display_photo";
+ }
+
+ /**
* TODO: javadoc
* @param cursor
* @return
@@ -2537,7 +2686,6 @@
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, DELETED);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, CONTACT_ID);
DatabaseUtils.cursorLongToContentValuesIfPresent(cursor, cv, STARRED);
- DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, IS_RESTRICTED);
DatabaseUtils.cursorIntToContentValuesIfPresent(cursor, cv, NAME_VERIFIED);
android.content.Entity contact = new android.content.Entity(cv);
@@ -3177,6 +3325,50 @@
}
/**
+ * <p>
+ * Constants for the photo files table, which tracks metadata for hi-res photos
+ * stored in the file system.
+ * </p>
+ *
+ * @hide
+ */
+ public static final class PhotoFiles implements BaseColumns, PhotoFilesColumns {
+ /**
+ * No public constructor since this is a utility class
+ */
+ private PhotoFiles() {
+ }
+ }
+
+ /**
+ * Columns in the PhotoFiles table.
+ *
+ * @see ContactsContract.PhotoFiles
+ *
+ * @hide
+ */
+ protected interface PhotoFilesColumns {
+
+ /**
+ * The height, in pixels, of the photo this entry is associated with.
+ * <P>Type: NUMBER</P>
+ */
+ public static final String HEIGHT = "height";
+
+ /**
+ * The width, in pixels, of the photo this entry is associated with.
+ * <P>Type: NUMBER</P>
+ */
+ public static final String WIDTH = "width";
+
+ /**
+ * The size, in bytes, of the photo stored on disk.
+ * <P>Type: NUMBER</P>
+ */
+ public static final String FILESIZE = "filesize";
+ }
+
+ /**
* Columns in the Data table.
*
* @see ContactsContract.Data
@@ -3814,27 +4006,6 @@
/**
* <p>
- * If {@link #FOR_EXPORT_ONLY} is explicitly set to "1", returned Cursor toward
- * Data.CONTENT_URI contains only exportable data.
- * </p>
- * <p>
- * This flag is useful (currently) only for vCard exporter in Contacts app, which
- * needs to exclude "un-exportable" data from available data to export, while
- * Contacts app itself has priviledge to access all data including "un-exportable"
- * ones and providers return all of them regardless of the callers' intention.
- * </p>
- * <p>
- * Type: INTEGER
- * </p>
- *
- * @hide Maybe available only in Eclair and not really ready for public use.
- * TODO: remove, or implement this feature completely. As of now (Eclair),
- * we only use this flag in queryEntities(), not query().
- */
- public static final String FOR_EXPORT_ONLY = "for_export_only";
-
- /**
- * <p>
* Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}
* style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts}
* entry of the given {@link ContactsContract.Data} entry.
@@ -5897,7 +6068,7 @@
/**
* <p>
- * A data kind representing an photo for the contact.
+ * A data kind representing a photo for the contact.
* </p>
* <p>
* Some sync adapters will choose to download photos in a separate
@@ -5917,10 +6088,17 @@
* <th>Alias</th><th colspan='2'>Data column</th>
* </tr>
* <tr>
+ * <td>NUMBER</td>
+ * <td>{@link #PHOTO_FILE_ID}</td>
+ * <td>{@link #DATA14}</td>
+ * <td>ID of the hi-res photo file.</td>
+ * </tr>
+ * <tr>
* <td>BLOB</td>
* <td>{@link #PHOTO}</td>
* <td>{@link #DATA15}</td>
- * <td>By convention, binary data is stored in DATA15.</td>
+ * <td>By convention, binary data is stored in DATA15. The thumbnail of the
+ * photo is stored in this column.</td>
* </tr>
* </table>
*/
@@ -5934,6 +6112,14 @@
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
/**
+ * Photo file ID for the display photo of the raw contact.
+ * See {@link ContactsContract.DisplayPhoto}.
+ * <p>
+ * Type: NUMBER
+ */
+ public static final String PHOTO_FILE_ID = DATA14;
+
+ /**
* Thumbnail photo of the raw contact. This is the raw bytes of an image
* that could be inflated using {@link android.graphics.BitmapFactory}.
* <p>
@@ -6213,6 +6399,18 @@
*/
protected interface GroupsColumns {
/**
+ * The data set within the account that this group belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' group data.
+ *
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct group data
+ * for the same account type and account name.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DATA_SET = "data_set";
+
+ /**
* The display title of this group.
* <p>
* Type: TEXT
@@ -6245,6 +6443,28 @@
public static final String NOTES = "notes";
/**
+ * The Activity action to open the group in the source app (e.g.
+ * {@link Intent#ACTION_VIEW}). Can be NULL if the group does not have a dedicated viewer.
+ * This is used in conjunction with {@link #ACTION_URI}: In order to show an "Open in
+ * (sourceapp)"-button, both of these fields must be set
+ * <p>
+ * Type: TEXT
+ */
+ public static final String ACTION = "action";
+
+
+ /**
+ * Uri to open the group in the source app.
+ * Can be NULL if the group does not have a dedicated viewer.
+ * This is used in conjunction with {@link #ACTION}: In order to show an "Open in
+ * (sourceapp)"-button, both of these fields must be set
+ * <p>
+ * Type: TEXT
+ */
+ public static final String ACTION_URI = "action_uri";
+
+
+ /**
* The ID of this group if it is a System Group, i.e. a group that has a special meaning
* to the sync adapter, null otherwise.
* <P>Type: TEXT</P>
@@ -6338,6 +6558,29 @@
* In other words, it would be a really bad idea to delete and reinsert a
* group. A sync adapter should always do an update instead.</td>
* </tr>
+ # <tr>
+ * <td>String</td>
+ * <td>{@link #DATA_SET}</td>
+ * <td>read/write-once</td>
+ * <td>
+ * <p>
+ * The data set within the account that this group belongs to. This allows
+ * multiple sync adapters for the same account type to distinguish between
+ * each others' group data. The combination of {@link #ACCOUNT_TYPE},
+ * {@link #ACCOUNT_NAME}, and {@link #DATA_SET} identifies a set of data
+ * that is associated with a single sync adapter.
+ * </p>
+ * <p>
+ * This is empty by default, and is completely optional. It only needs to
+ * be populated if multiple sync adapters are entering distinct data for
+ * the same account type and account name.
+ * </p>
+ * <p>
+ * It should be set at the time the group is inserted and never changed
+ * afterwards.
+ * </p>
+ * </td>
+ * </tr>
* <tr>
* <td>String</td>
* <td>{@link #TITLE}</td>
@@ -7018,6 +7261,66 @@
}
/**
+ * Helper class for accessing full-size photos by photo file ID.
+ * <p>
+ * Usage example:
+ * <dl>
+ * <dt>Retrieving a full-size photo by photo file ID (see
+ * {@link ContactsContract.ContactsColumns#PHOTO_FILE_ID})
+ * </dt>
+ * <dd>
+ * <pre>
+ * public InputStream openDisplayPhoto(long photoFileId) {
+ * Uri displayPhotoUri = ContentUris.withAppendedId(DisplayPhoto.CONTENT_URI, photoKey);
+ * try {
+ * AssetFileDescriptor fd = getContentResolver().openAssetFile(displayPhotoUri, "r");
+ * return fd.createInputStream();
+ * } catch (FileNotFoundException e) {
+ * return null;
+ * }
+ * }
+ * </pre>
+ * </dd>
+ * </dl>
+ * </p>
+ */
+ public static final class DisplayPhoto {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private DisplayPhoto() {}
+
+ /**
+ * The content:// style URI for this class, which allows access to full-size photos,
+ * given a key.
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "display_photo");
+
+ /**
+ * This URI allows the caller to query for the maximum dimensions of a display photo
+ * or thumbnail. Requests to this URI can be performed on the UI thread because
+ * they are always unblocking.
+ */
+ public static final Uri CONTENT_MAX_DIMENSIONS_URI =
+ Uri.withAppendedPath(AUTHORITY_URI, "photo_dimensions");
+
+ /**
+ * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
+ * contain this column, populated with the maximum height and width (in pixels)
+ * that will be stored for a display photo. Larger photos will be down-sized to
+ * fit within a square of this many pixels.
+ */
+ public static final String DISPLAY_MAX_DIM = "display_max_dim";
+
+ /**
+ * Queries to {@link ContactsContract.DisplayPhoto#CONTENT_MAX_DIMENSIONS_URI} will
+ * contain this column, populated with the height and width (in pixels) for photo
+ * thumbnails.
+ */
+ public static final String THUMBNAIL_MAX_DIM = "thumbnail_max_dim";
+ }
+
+ /**
* Contains helper classes used to create or manage {@link android.content.Intent Intents}
* that involve contacts.
*/
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f799af3..f3bcedb 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -283,6 +283,13 @@
*/
public static final String IS_DRM = "is_drm";
+ /**
+ * Used by the media scanner to suppress files from being processed as media files.
+ *
+ * <P>Type: INTEGER (boolean)</P>
+ * @hide
+ */
+ public static final String NO_MEDIA = "no_media";
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 23b53ae..34699e2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2683,6 +2683,13 @@
public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
/**
+ * If touch exploration is requested. Touch exploration is enabled if it is
+ * requested by this setting, accessibility is enabled and there is at least
+ * one enabled accessibility serivce that provides spoken feedback.
+ */
+ public static final String TOUCH_EXPLORATION_REQUESTED = "touch_exploration_requested";
+
+ /**
* List of the enabled accessibility providers.
*/
public static final String ENABLED_ACCESSIBILITY_SERVICES =
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 63c420a..f345a6a 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -660,7 +660,6 @@
case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
- case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
if (mBluetoothService.attemptAutoPair(address)) return;
}
diff --git a/core/java/android/server/BluetoothHealthProfileHandler.java b/core/java/android/server/BluetoothHealthProfileHandler.java
index 7f862e0..105ff332 100644
--- a/core/java/android/server/BluetoothHealthProfileHandler.java
+++ b/core/java/android/server/BluetoothHealthProfileHandler.java
@@ -20,15 +20,12 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHealth;
import android.bluetooth.BluetoothHealthAppConfiguration;
-import android.bluetooth.BluetoothHealth;
-import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.IBluetoothHealthCallback;
import android.content.Context;
-import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.provider.Settings;
import android.util.Log;
import java.util.ArrayList;
@@ -36,10 +33,6 @@
import java.util.List;
import java.util.Map.Entry;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-
/**
* This handles all the operations on the Bluetooth Health profile.
* All functions are called by BluetoothService, as Bluetooth Service
@@ -58,6 +51,7 @@
private ArrayList<HealthChannel> mHealthChannels;
private HashMap <BluetoothHealthAppConfiguration, String> mHealthAppConfigs;
private HashMap <BluetoothDevice, Integer> mHealthDevices;
+ private HashMap <BluetoothHealthAppConfiguration, IBluetoothHealthCallback> mCallbacks;
private static final int MESSAGE_REGISTER_APPLICATION = 0;
private static final int MESSAGE_UNREGISTER_APPLICATION = 1;
@@ -103,6 +97,7 @@
}
if (path == null) {
+ mCallbacks.remove(registerApp);
callHealthApplicationStatusCallback(registerApp,
BluetoothHealth.APPLICATION_REGISTRATION_FAILURE);
} else {
@@ -118,6 +113,7 @@
boolean result = mBluetoothService.unregisterHealthApplicationNative(
mHealthAppConfigs.get(unregisterApp));
if (result) {
+ mCallbacks.remove(unregisterApp);
callHealthApplicationStatusCallback(unregisterApp,
BluetoothHealth.APPLICATION_UNREGISTRATION_SUCCESS);
} else {
@@ -149,6 +145,7 @@
mHealthAppConfigs = new HashMap<BluetoothHealthAppConfiguration, String>();
mHealthChannels = new ArrayList<HealthChannel>();
mHealthDevices = new HashMap<BluetoothDevice, Integer>();
+ mCallbacks = new HashMap<BluetoothHealthAppConfiguration, IBluetoothHealthCallback>();
}
static synchronized BluetoothHealthProfileHandler getInstance(Context context,
@@ -157,10 +154,12 @@
return sInstance;
}
- boolean registerAppConfiguration(BluetoothHealthAppConfiguration config) {
+ boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
+ IBluetoothHealthCallback callback) {
Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_APPLICATION);
msg.obj = config;
mHandler.sendMessage(msg);
+ mCallbacks.put(config, callback);
return true;
}
@@ -442,11 +441,11 @@
debugLog("Health Device Callback: " + device + " State Change: "
+ prevState + "->" + state);
- try {
- config.getCallback().onHealthChannelStateChange(config, device, prevState,
- state, fd);
- } catch (RemoteException e) {
- errorLog("Error while making health channel state change callback: " + e);
+ IBluetoothHealthCallback callback = mCallbacks.get(config);
+ if (callback != null) {
+ try {
+ callback.onHealthChannelStateChange(config, device, prevState, state, fd);
+ } catch (RemoteException e) {}
}
}
@@ -454,10 +453,11 @@
BluetoothHealthAppConfiguration config, int status) {
debugLog("Health Device Application: " + config + " State Change: status:"
+ status);
- try {
- config.getCallback().onHealthAppConfigurationStatusChange(config, status);
- } catch (RemoteException e) {
- errorLog("Error while making health app registration state change callback: " + e);
+ IBluetoothHealthCallback callback = mCallbacks.get(config);
+ if (callback != null) {
+ try {
+ callback.onHealthAppConfigurationStatusChange(config, status);
+ } catch (RemoteException e) {}
}
}
@@ -526,19 +526,19 @@
List<HealthChannel> chan;
switch (currDeviceState) {
case BluetoothHealth.STATE_DISCONNECTED:
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
break;
case BluetoothHealth.STATE_CONNECTING:
// Channel got connected.
if (newDeviceState == BluetoothHealth.STATE_CONNECTED) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
} else {
// Channel got disconnected
chan = findChannelByStates(device, new int [] {
BluetoothHealth.STATE_CHANNEL_CONNECTING,
BluetoothHealth.STATE_CHANNEL_DISCONNECTING});
if (chan.isEmpty()) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
}
}
break;
@@ -548,22 +548,23 @@
BluetoothHealth.STATE_CHANNEL_CONNECTING,
BluetoothHealth.STATE_CHANNEL_CONNECTED});
if (chan.isEmpty()) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
}
+ break;
case BluetoothHealth.STATE_DISCONNECTING:
// Channel got disconnected.
chan = findChannelByStates(device, new int [] {
BluetoothHealth.STATE_CHANNEL_CONNECTING,
BluetoothHealth.STATE_CHANNEL_DISCONNECTING});
if (chan.isEmpty()) {
- updateAndsendIntent(device, currDeviceState, newDeviceState);
+ updateAndSendIntent(device, currDeviceState, newDeviceState);
}
break;
}
}
}
- private void updateAndsendIntent(BluetoothDevice device, int prevDeviceState,
+ private void updateAndSendIntent(BluetoothDevice device, int prevDeviceState,
int newDeviceState) {
mHealthDevices.put(device, newDeviceState);
mBluetoothService.sendConnectionStateChange(device, prevDeviceState, newDeviceState);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
old mode 100644
new mode 100755
index 9839f76..ff16c18
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -24,8 +24,6 @@
package android.server;
-import com.android.internal.app.IBatteryStats;
-
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
@@ -40,6 +38,7 @@
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothHealthCallback;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -58,6 +57,8 @@
import android.util.Log;
import android.util.Pair;
+import com.android.internal.app.IBatteryStats;
+
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -2111,11 +2112,12 @@
/**** Handlers for Health Device Profile ****/
// TODO: All these need to be converted to a state machine.
- public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config) {
+ public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
+ IBluetoothHealthCallback callback) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
"Need BLUETOOTH permission");
synchronized (mBluetoothHealthProfileHandler) {
- return mBluetoothHealthProfileHandler.registerAppConfiguration(config);
+ return mBluetoothHealthProfileHandler.registerAppConfiguration(config, callback);
}
}
@@ -2401,6 +2403,7 @@
convertToAdapterState(state));
intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
convertToAdapterState(prevState));
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
+ prevState + " -> " + state);
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index 8ef4295..96864c4 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -17,6 +17,7 @@
import android.media.AudioFormat;
import android.media.AudioTrack;
+import android.text.TextUtils;
import android.util.Log;
import java.util.Iterator;
@@ -25,14 +26,14 @@
class AudioPlaybackHandler {
private static final String TAG = "TTS.AudioPlaybackHandler";
+ private static final boolean DBG_THREADING = false;
private static final boolean DBG = false;
private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
private static final int SYNTHESIS_START = 1;
private static final int SYNTHESIS_DATA_AVAILABLE = 2;
- private static final int SYNTHESIS_COMPLETE_DATA_AVAILABLE = 3;
- private static final int SYNTHESIS_DONE = 4;
+ private static final int SYNTHESIS_DONE = 3;
private static final int PLAY_AUDIO = 5;
private static final int PLAY_SILENCE = 6;
@@ -65,74 +66,105 @@
* Stops all synthesis for a given {@code token}. If the current token
* is currently being processed, an effort will be made to stop it but
* that is not guaranteed.
+ *
+ * NOTE: This assumes that all other messages in the queue with {@code token}
+ * have been removed already.
+ *
+ * NOTE: Must be called synchronized on {@code AudioPlaybackHandler.this}.
*/
- synchronized public void stop(MessageParams token) {
+ private void stop(MessageParams token) {
if (token == null) {
return;
}
- removeMessages(token);
+ if (DBG) Log.d(TAG, "Stopping token : " + token);
if (token.getType() == MessageParams.TYPE_SYNTHESIS) {
AudioTrack current = ((SynthesisMessageParams) token).getAudioTrack();
if (current != null) {
// Stop the current audio track if it's still playing.
- // The audio track is thread safe in this regard.
+ // The audio track is thread safe in this regard. The current
+ // handleSynthesisDataAvailable call will return soon after this
+ // call.
current.stop();
}
+ // This is safe because PlaybackSynthesisCallback#stop would have
+ // been called before this method, and will no longer enqueue any
+ // audio for this token.
+ //
+ // (Even if it did, all it would result in is a warning message).
mQueue.add(new ListEntry(SYNTHESIS_DONE, token, HIGH_PRIORITY));
- } else {
- final MessageParams current = getCurrentParams();
-
- if (current != null) {
- if (token.getType() == MessageParams.TYPE_AUDIO) {
- ((AudioMessageParams) current).getPlayer().stop();
- } else if (token.getType() == MessageParams.TYPE_SILENCE) {
- ((SilenceMessageParams) current).getConditionVariable().open();
- }
- }
+ } else if (token.getType() == MessageParams.TYPE_AUDIO) {
+ ((AudioMessageParams) token).getPlayer().stop();
+ // No cleanup required for audio messages.
+ } else if (token.getType() == MessageParams.TYPE_SILENCE) {
+ ((SilenceMessageParams) token).getConditionVariable().open();
+ // No cleanup required for silence messages.
}
}
+ // -----------------------------------------------------
+ // Methods that add and remove elements from the queue. These do not
+ // need to be synchronized strictly speaking, but they make the behaviour
+ // a lot more predictable. (though it would still be correct without
+ // synchronization).
+ // -----------------------------------------------------
+
synchronized public void removePlaybackItems(String callingApp) {
+ if (DBG_THREADING) Log.d(TAG, "Removing all callback items for : " + callingApp);
removeMessages(callingApp);
- stop(getCurrentParams());
+
+ final MessageParams current = getCurrentParams();
+ if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
+ stop(current);
+ }
}
synchronized public void removeAllItems() {
+ if (DBG_THREADING) Log.d(TAG, "Removing all items");
removeAllMessages();
stop(getCurrentParams());
}
/**
+ * @return false iff the queue is empty and no queue item is currently
+ * being handled, true otherwise.
+ */
+ public boolean isSpeaking() {
+ return (mQueue.peek() != null) || (mCurrentParams != null);
+ }
+
+ /**
* Shut down the audio playback thread.
*/
synchronized public void quit() {
+ removeAllMessages();
stop(getCurrentParams());
mQueue.add(new ListEntry(SHUTDOWN, null, HIGH_PRIORITY));
}
- void enqueueSynthesisStart(SynthesisMessageParams token) {
+ synchronized void enqueueSynthesisStart(SynthesisMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis start : " + token);
mQueue.add(new ListEntry(SYNTHESIS_START, token));
}
- void enqueueSynthesisDataAvailable(SynthesisMessageParams token) {
+ synchronized void enqueueSynthesisDataAvailable(SynthesisMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis data available : " + token);
mQueue.add(new ListEntry(SYNTHESIS_DATA_AVAILABLE, token));
}
- void enqueueSynthesisCompleteDataAvailable(SynthesisMessageParams token) {
- mQueue.add(new ListEntry(SYNTHESIS_COMPLETE_DATA_AVAILABLE, token));
- }
-
- void enqueueSynthesisDone(SynthesisMessageParams token) {
+ synchronized void enqueueSynthesisDone(SynthesisMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing synthesis done : " + token);
mQueue.add(new ListEntry(SYNTHESIS_DONE, token));
}
- void enqueueAudio(AudioMessageParams token) {
+ synchronized void enqueueAudio(AudioMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing audio : " + token);
mQueue.add(new ListEntry(PLAY_AUDIO, token));
}
- void enqueueSilence(SilenceMessageParams token) {
+ synchronized void enqueueSilence(SilenceMessageParams token) {
+ if (DBG_THREADING) Log.d(TAG, "Enqueuing silence : " + token);
mQueue.add(new ListEntry(PLAY_SILENCE, token));
}
@@ -177,26 +209,6 @@
}
/*
- * Remove all messages from the queue that contain the supplied token.
- * Note that the Iterator is thread safe, and other methods can safely
- * continue adding to the queue at this point.
- */
- synchronized private void removeMessages(MessageParams token) {
- if (token == null) {
- return;
- }
-
- Iterator<ListEntry> it = mQueue.iterator();
-
- while (it.hasNext()) {
- final ListEntry current = it.next();
- if (current.mMessage == token) {
- it.remove();
- }
- }
- }
-
- /*
* Atomically clear the queue of all messages.
*/
synchronized private void removeAllMessages() {
@@ -260,6 +272,13 @@
}
private void setCurrentParams(MessageParams p) {
+ if (DBG_THREADING) {
+ if (p != null) {
+ Log.d(TAG, "Started handling :" + p);
+ } else {
+ Log.d(TAG, "End handling : " + mCurrentParams);
+ }
+ }
mCurrentParams = p;
}
@@ -280,8 +299,6 @@
handleSynthesisDataAvailable(msg);
} else if (entry.mWhat == SYNTHESIS_DONE) {
handleSynthesisDone(msg);
- } else if (entry.mWhat == SYNTHESIS_COMPLETE_DATA_AVAILABLE) {
- handleSynthesisCompleteDataAvailable(msg);
} else if (entry.mWhat == PLAY_AUDIO) {
handleAudio(msg);
} else if (entry.mWhat == PLAY_SILENCE) {
@@ -352,7 +369,7 @@
private void handleSynthesisDataAvailable(MessageParams msg) {
final SynthesisMessageParams param = (SynthesisMessageParams) msg;
if (param.getAudioTrack() == null) {
- Log.w(TAG, "Error : null audio track in handleDataAvailable.");
+ Log.w(TAG, "Error : null audio track in handleDataAvailable : " + param);
return;
}
@@ -384,7 +401,7 @@
}
count += written;
}
-
+ param.mBytesWritten += count;
param.mLogger.onPlaybackStart();
}
@@ -396,14 +413,16 @@
params.mLogger.onWriteData();
}
- // Flush all remaining data to the audio track, stop it and release
- // all it's resources.
+ // Wait for the audio track to stop playing, and then release it's resources.
private void handleSynthesisDone(SynthesisMessageParams params) {
if (DBG) Log.d(TAG, "handleSynthesisDone()");
final AudioTrack audioTrack = params.getAudioTrack();
try {
if (audioTrack != null) {
+ if (DBG) Log.d(TAG, "Waiting for audio track to complete : " +
+ audioTrack.hashCode());
+ blockUntilDone(params);
if (DBG) Log.d(TAG, "Releasing audio track [" + audioTrack.hashCode() + "]");
// The last call to AudioTrack.write( ) will return only after
// all data from the audioTrack has been sent to the mixer, so
@@ -417,51 +436,25 @@
}
}
- private void handleSynthesisCompleteDataAvailable(MessageParams msg) {
- final SynthesisMessageParams params = (SynthesisMessageParams) msg;
- if (DBG) Log.d(TAG, "completeAudioAvailable(" + params + ")");
-
- params.mLogger.onPlaybackStart();
-
- // Channel config and bytes per frame are checked before
- // this message is sent.
- int channelConfig = AudioPlaybackHandler.getChannelConfig(params.mChannelCount);
- int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(params.mAudioFormat);
-
- SynthesisMessageParams.ListEntry entry = params.getNextBuffer();
-
- if (entry == null) {
- Log.w(TAG, "completeDataAvailable : No buffers available to play.");
+ private static void blockUntilDone(SynthesisMessageParams params) {
+ if (params.mAudioTrack == null || params.mBytesWritten <= 0) {
return;
}
- final AudioTrack audioTrack = new AudioTrack(params.mStreamType, params.mSampleRateInHz,
- channelConfig, params.mAudioFormat, entry.mLength, AudioTrack.MODE_STATIC);
+ final AudioTrack audioTrack = params.mAudioTrack;
+ final int bytesPerFrame = getBytesPerFrame(params.mAudioFormat);
+ final int lengthInBytes = params.mBytesWritten;
+ final int lengthInFrames = lengthInBytes / bytesPerFrame;
- // So that handleDone can access this correctly.
- params.mAudioTrack = audioTrack;
-
- try {
- audioTrack.write(entry.mBytes, entry.mOffset, entry.mLength);
- setupVolume(audioTrack, params.mVolume, params.mPan);
- audioTrack.play();
- blockUntilDone(audioTrack, bytesPerFrame, entry.mLength);
- if (DBG) Log.d(TAG, "Wrote data to audio track successfully : " + entry.mLength);
- } catch (IllegalStateException ex) {
- Log.e(TAG, "Playback error", ex);
- } finally {
- handleSynthesisDone(msg);
- }
- }
-
-
- private static void blockUntilDone(AudioTrack audioTrack, int bytesPerFrame, int length) {
- int lengthInFrames = length / bytesPerFrame;
int currentPosition = 0;
while ((currentPosition = audioTrack.getPlaybackHeadPosition()) < lengthInFrames) {
+ if (audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
+ break;
+ }
+
long estimatedTimeMs = ((lengthInFrames - currentPosition) * 1000) /
audioTrack.getSampleRate();
- audioTrack.getPlayState();
+
if (DBG) Log.d(TAG, "About to sleep for : " + estimatedTimeMs + " ms," +
" Playback position : " + currentPosition);
try {
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 4f4b3fb..5808919 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -187,37 +187,6 @@
}
}
- @Override
- public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
- byte[] buffer, int offset, int length) {
- synchronized (mStateLock) {
- if (mStopped) {
- if (DBG) Log.d(TAG, "Request has been aborted.");
- return TextToSpeech.ERROR;
- }
- }
- FileOutputStream out = null;
- try {
- out = new FileOutputStream(mFileName);
- out.write(makeWavHeader(sampleRateInHz, audioFormat, channelCount, length));
- out.write(buffer, offset, length);
- mDone = true;
- return TextToSpeech.SUCCESS;
- } catch (IOException ex) {
- Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
- mFileName.delete();
- return TextToSpeech.ERROR;
- } finally {
- try {
- if (out != null) {
- out.close();
- }
- } catch (IOException ex) {
- Log.e(TAG, "Failed to close " + mFileName + ": " + ex);
- }
- }
- }
-
private byte[] makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
int dataLength) {
// TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
index 4c1b6d2..e7d6da3 100644
--- a/core/java/android/speech/tts/MessageParams.java
+++ b/core/java/android/speech/tts/MessageParams.java
@@ -38,5 +38,10 @@
return mCallingApp;
}
+ @Override
+ public String toString() {
+ return "MessageParams[" + hashCode() + "]";
+ }
+
abstract int getType();
}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 38030a6..7dbf1ac 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -53,8 +53,7 @@
// Handler associated with a thread that plays back audio requests.
private final AudioPlaybackHandler mAudioTrackHandler;
- // A request "token", which will be non null after start() or
- // completeAudioAvailable() have been called.
+ // A request "token", which will be non null after start() has been called.
private SynthesisMessageParams mToken = null;
// Whether this request has been stopped. This is useful for keeping
// track whether stop() has been called before start(). In all other cases,
@@ -91,12 +90,10 @@
Log.w(TAG, "stop() called twice");
return;
}
+
// mToken will be null if the engine encounters
// an error before it called start().
- if (mToken != null) {
- mAudioTrackHandler.stop(mToken);
- mToken = null;
- } else {
+ if (mToken == null) {
// In all other cases, mAudioTrackHandler.stop() will
// result in onComplete being called.
mLogger.onWriteData();
@@ -159,7 +156,7 @@
}
synchronized (mStateLock) {
- if (mToken == null) {
+ if (mToken == null || mStopped) {
return TextToSpeech.ERROR;
}
@@ -206,35 +203,4 @@
stop();
}
- @Override
- public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
- byte[] buffer, int offset, int length) {
- int channelConfig = AudioPlaybackHandler.getChannelConfig(channelCount);
- if (channelConfig == 0) {
- Log.e(TAG, "Unsupported number of channels :" + channelCount);
- return TextToSpeech.ERROR;
- }
-
- int bytesPerFrame = AudioPlaybackHandler.getBytesPerFrame(audioFormat);
- if (bytesPerFrame < 0) {
- Log.e(TAG, "Unsupported audio format :" + audioFormat);
- return TextToSpeech.ERROR;
- }
-
- synchronized (mStateLock) {
- if (mStopped) {
- return TextToSpeech.ERROR;
- }
- SynthesisMessageParams params = new SynthesisMessageParams(
- mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan,
- mDispatcher, mCallingApp, mLogger);
- params.addBuffer(buffer, offset, length);
-
- mAudioTrackHandler.enqueueSynthesisCompleteDataAvailable(params);
- mToken = params;
- }
-
- return TextToSpeech.SUCCESS;
- }
-
}
diff --git a/core/java/android/speech/tts/SynthesisCallback.java b/core/java/android/speech/tts/SynthesisCallback.java
index 1b80e40..d70c371d 100644
--- a/core/java/android/speech/tts/SynthesisCallback.java
+++ b/core/java/android/speech/tts/SynthesisCallback.java
@@ -22,19 +22,16 @@
* {@link #start}, then {@link #audioAvailable} until all audio has been provided, then finally
* {@link #done}.
*
- * Alternatively, the engine can provide all the audio at once, by using
- * {@link #completeAudioAvailable}.
*
* {@link #error} can be called at any stage in the synthesis process to
- * indicate that an error has occured, but if the call is made after a call
- * to {@link #done} or {@link #completeAudioAvailable} it might be discarded.
+ * indicate that an error has occurred, but if the call is made after a call
+ * to {@link #done}, it might be discarded.
*/
public interface SynthesisCallback {
/**
* @return the maximum number of bytes that the TTS engine can pass in a single call of
- * {@link #audioAvailable}. This does not apply to {@link #completeAudioAvailable}.
- * Calls to {@link #audioAvailable} with data lengths larger than this
- * value will not succeed.
+ * {@link #audioAvailable}. Calls to {@link #audioAvailable} with data lengths
+ * larger than this value will not succeed.
*/
public int getMaxBufferSize();
@@ -69,23 +66,6 @@
public int audioAvailable(byte[] buffer, int offset, int length);
/**
- * The service can call this method instead of using {@link #start}, {@link #audioAvailable}
- * and {@link #done} if all the audio data is available in a single buffer.
- *
- * @param sampleRateInHz Sample rate in HZ of the generated audio.
- * @param audioFormat Audio format of the generated audio. Must be one of
- * the ENCODING_ constants defined in {@link android.media.AudioFormat}.
- * @param channelCount The number of channels. Must be {@code 1} or {@code 2}.
- * @param buffer The generated audio data. This method will not hold on to {@code buffer},
- * so the caller is free to modify it after this method returns.
- * @param offset The offset into {@code buffer} where the audio data starts.
- * @param length The number of bytes of audio data in {@code buffer}.
- * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
- */
- public int completeAudioAvailable(int sampleRateInHz, int audioFormat,
- int channelCount, byte[] buffer, int offset, int length);
-
- /**
* The service should call this method when all the synthesized audio for a request has
* been passed to {@link #audioAvailable}.
*
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index caf02ef..ffe70e2 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -32,7 +32,9 @@
final float mPan;
final EventLogger mLogger;
- public volatile AudioTrack mAudioTrack;
+ volatile AudioTrack mAudioTrack;
+ // Not volatile, accessed only from the synthesis thread.
+ int mBytesWritten;
private final LinkedList<ListEntry> mDataBufferList = new LinkedList<ListEntry>();
@@ -52,6 +54,7 @@
// initially null.
mAudioTrack = null;
+ mBytesWritten = 0;
}
@Override
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 8e4725f..5126e48 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -109,6 +109,11 @@
/**
* Broadcast Action: The TextToSpeech synthesizer has completed processing
* of all the text in the speech queue.
+ *
+ * Note that this notifies callers when the <b>engine</b> has finished has
+ * processing text data. Audio playback might not have completed (or even started)
+ * at this point. If you wish to be notified when this happens, see
+ * {@link OnUtteranceCompletedListener}.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
@@ -181,7 +186,7 @@
*
* @hide
* @deprecated No longer in use, the default engine is determined by
- * the sort order defined in {@link EngineInfoComparator}. Note that
+ * the sort order defined in {@link TtsEngines}. Note that
* this doesn't "break" anything because there is no guarantee that
* the engine specified below is installed on a given build, let
* alone be the default.
@@ -504,36 +509,39 @@
}
private int initTts() {
- String defaultEngine = getDefaultEngine();
- String engine = defaultEngine;
- if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
- engine = mRequestedEngine;
+ // Step 1: Try connecting to the engine that was requested.
+ if (mRequestedEngine != null && mEnginesHelper.isEngineInstalled(mRequestedEngine)) {
+ if (connectToEngine(mRequestedEngine)) {
+ mCurrentEngine = mRequestedEngine;
+ return SUCCESS;
+ }
}
- // Try requested engine
- if (connectToEngine(engine)) {
- mCurrentEngine = engine;
- return SUCCESS;
- }
-
- // Fall back to user's default engine if different from the already tested one
- if (!engine.equals(defaultEngine)) {
+ // Step 2: Try connecting to the user's default engine.
+ final String defaultEngine = getDefaultEngine();
+ if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) {
if (connectToEngine(defaultEngine)) {
- mCurrentEngine = engine;
+ mCurrentEngine = defaultEngine;
return SUCCESS;
}
}
+ // Step 3: Try connecting to the highest ranked engine in the
+ // system.
final String highestRanked = mEnginesHelper.getHighestRankedEngineName();
- // Fall back to the hardcoded default if different from the two above
- if (!defaultEngine.equals(highestRanked)
- && !engine.equals(highestRanked)) {
+ if (highestRanked != null && !highestRanked.equals(mRequestedEngine) &&
+ !highestRanked.equals(defaultEngine)) {
if (connectToEngine(highestRanked)) {
- mCurrentEngine = engine;
+ mCurrentEngine = highestRanked;
return SUCCESS;
}
}
+ // NOTE: The API currently does not allow the caller to query whether
+ // they are actually connected to any engine. This might fail for various
+ // reasons like if the user disables all her TTS engines.
+
+ mCurrentEngine = null;
dispatchOnInit(ERROR);
return ERROR;
}
@@ -573,6 +581,14 @@
service.setCallback(getPackageName(), null);
service.stop(getPackageName());
mServiceConnection.disconnect();
+ // Context#unbindService does not result in a call to
+ // ServiceConnection#onServiceDisconnected. As a result, the
+ // service ends up being destroyed (if there are no other open
+ // connections to it) but the process lives on and the
+ // ServiceConnection continues to refer to the destroyed service.
+ //
+ // This leads to tons of log spam about SynthThread being dead.
+ mServiceConnection = null;
mCurrentEngine = null;
return null;
}
@@ -793,7 +809,10 @@
}
/**
- * Checks whether the TTS engine is busy speaking.
+ * Checks whether the TTS engine is busy speaking. Note that a speech item is
+ * considered complete once it's audio data has been sent to the audio mixer, or
+ * written to a file. There might be a finite lag between this point, and when
+ * the audio hardware completes playback.
*
* @return {@code true} if the TTS engine is speaking.
*/
@@ -963,7 +982,7 @@
/**
* Synthesizes the given text to a file using the specified parameters.
*
- * @param text Thetext that should be synthesized
+ * @param text The text that should be synthesized
* @param params Parameters for the request. Can be null.
* Supported parameter names:
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
@@ -1073,7 +1092,9 @@
*
* @deprecated This doesn't inform callers when the TTS engine has been
* initialized. {@link #TextToSpeech(Context, OnInitListener, String)}
- * can be used with the appropriate engine name.
+ * can be used with the appropriate engine name. Also, there is no
+ * guarantee that the engine specified will be loaded. If it isn't
+ * installed or disabled, the user / system wide defaults will apply.
*
* @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
*
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 010c155..1926c92 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -282,6 +282,8 @@
if (current != null) {
current.stop();
}
+
+ // The AudioPlaybackHandler will be destroyed by the caller.
}
/**
@@ -337,6 +339,8 @@
}
removeCallbacksAndMessages(callingApp);
+ // This stops writing data to the file / or publishing
+ // items to the audio playback handler.
SpeechItem current = setCurrentSpeechItem(null);
if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
current.stop();
@@ -628,9 +632,7 @@
@Override
protected void stopImpl() {
- if (mToken != null) {
- mAudioPlaybackHandler.stop(mToken);
- }
+ // Do nothing.
}
}
@@ -657,9 +659,7 @@
@Override
protected void stopImpl() {
- if (mToken != null) {
- mAudioPlaybackHandler.stop(mToken);
- }
+ // Do nothing.
}
}
@@ -719,7 +719,7 @@
}
public boolean isSpeaking() {
- return mSynthHandler.isSpeaking();
+ return mSynthHandler.isSpeaking() || mAudioPlaybackHandler.isSpeaking();
}
public int stop(String callingApp) {
@@ -767,10 +767,6 @@
mCallbacks.setCallback(packageName, cb);
}
- private boolean isDefault(String lang, String country, String variant) {
- return Locale.getDefault().equals(new Locale(lang, country, variant));
- }
-
private String intern(String in) {
// The input parameter will be non null.
return in.intern();
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index 757a8c3..5a244f1 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -226,7 +226,17 @@
*/
public static Metrics isBoring(CharSequence text,
TextPaint paint) {
- return isBoring(text, paint, null);
+ return isBoring(text, paint, TextDirectionHeuristics.FIRSTSTRONG_LTR, null);
+ }
+
+ /**
+ * Returns null if not boring; the width, ascent, and descent if boring.
+ * @hide
+ */
+ public static Metrics isBoring(CharSequence text,
+ TextPaint paint,
+ TextDirectionHeuristic textDir) {
+ return isBoring(text, paint, textDir, null);
}
/**
@@ -235,6 +245,17 @@
* if boring.
*/
public static Metrics isBoring(CharSequence text, TextPaint paint, Metrics metrics) {
+ return isBoring(text, paint, TextDirectionHeuristics.FIRSTSTRONG_LTR, metrics);
+ }
+
+ /**
+ * Returns null if not boring; the width, ascent, and descent in the
+ * provided Metrics object (or a new one if the provided one was null)
+ * if boring.
+ * @hide
+ */
+ public static Metrics isBoring(CharSequence text, TextPaint paint,
+ TextDirectionHeuristic textDir, Metrics metrics) {
char[] temp = TextUtils.obtain(500);
int length = text.length();
boolean boring = true;
@@ -258,6 +279,11 @@
break outer;
}
}
+
+ if (textDir.isRtl(temp, 0, n)) {
+ boring = false;
+ break outer;
+ }
}
TextUtils.recycle(temp);
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index f196b34..cb96969 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -75,12 +75,31 @@
float spacingmult, float spacingadd,
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
- super((ellipsize == null)
- ? display
- : (display instanceof Spanned)
- ? new SpannedEllipsizer(display)
+ this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+ spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+ }
+
+ /**
+ * Make a layout for the transformed text (password transformation
+ * being the primary example of a transformation)
+ * that will be updated as the base text is changed.
+ * If ellipsize is non-null, the Layout will ellipsize the text
+ * down to ellipsizedWidth.
+ * *
+ * *@hide
+ */
+ public DynamicLayout(CharSequence base, CharSequence display,
+ TextPaint paint,
+ int width, Alignment align, TextDirectionHeuristic textDir,
+ float spacingmult, float spacingadd,
+ boolean includepad,
+ TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
+ super((ellipsize == null)
+ ? display
+ : (display instanceof Spanned)
+ ? new SpannedEllipsizer(display)
: new Ellipsizer(display),
- paint, width, align, spacingmult, spacingadd);
+ paint, width, align, textDir, spacingmult, spacingadd);
mBase = base;
mDisplay = display;
@@ -259,7 +278,7 @@
reflowed = new StaticLayout(true);
reflowed.generate(text, where, where + after,
- getPaint(), getWidth(), getAlignment(),
+ getPaint(), getWidth(), getAlignment(), getTextDirectionHeuristic(),
getSpacingMultiplier(), getSpacingAdd(),
false, true, mEllipsizedWidth, mEllipsizeAt);
int n = reflowed.getLineCount();
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index aae9ccf..eabeef0 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,8 +16,6 @@
package android.text;
-import com.android.internal.util.ArrayUtils;
-
import android.emoji.EmojiFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -32,6 +30,8 @@
import android.text.style.ReplacementSpan;
import android.text.style.TabStopSpan;
+import com.android.internal.util.ArrayUtils;
+
import java.util.Arrays;
/**
@@ -113,6 +113,29 @@
protected Layout(CharSequence text, TextPaint paint,
int width, Alignment align,
float spacingMult, float spacingAdd) {
+ this(text, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
+ spacingMult, spacingAdd);
+ }
+
+ /**
+ * Subclasses of Layout use this constructor to set the display text,
+ * width, and other standard properties.
+ * @param text the text to render
+ * @param paint the default paint for the layout. Styles can override
+ * various attributes of the paint.
+ * @param width the wrapping width for the text.
+ * @param align whether to left, right, or center the text. Styles can
+ * override the alignment.
+ * @param spacingMult factor by which to scale the font size to get the
+ * default line spacing
+ * @param spacingAdd amount to add to the default line spacing
+ *
+ * @hide
+ */
+ protected Layout(CharSequence text, TextPaint paint,
+ int width, Alignment align, TextDirectionHeuristic textDir,
+ float spacingMult, float spacingAdd) {
+
if (width < 0)
throw new IllegalArgumentException("Layout: " + width + " < 0");
@@ -133,6 +156,7 @@
mSpacingMult = spacingMult;
mSpacingAdd = spacingAdd;
mSpannedText = text instanceof Spanned;
+ mTextDir = textDir;
}
/**
@@ -531,6 +555,14 @@
}
/**
+ * Return the heuristic used to determine paragraph text direction.
+ * @hide
+ */
+ public final TextDirectionHeuristic getTextDirectionHeuristic() {
+ return mTextDir;
+ }
+
+ /**
* Return the number of lines of text in this layout.
*/
public abstract int getLineCount();
@@ -1419,7 +1451,7 @@
MeasuredText mt = MeasuredText.obtain();
TextLine tl = TextLine.obtain();
try {
- mt.setPara(text, start, end, DIR_REQUEST_LTR);
+ mt.setPara(text, start, end, TextDirectionHeuristics.LTR);
Directions directions;
int dir;
if (mt.mEasy) {
@@ -1769,6 +1801,7 @@
private float mSpacingAdd;
private static final Rect sTempRect = new Rect();
private boolean mSpannedText;
+ private TextDirectionHeuristic mTextDir;
public static final int DIR_LEFT_TO_RIGHT = 1;
public static final int DIR_RIGHT_TO_LEFT = -1;
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index a81be09..2920ac5 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -85,7 +85,7 @@
* Analyzes text for bidirectional runs. Allocates working buffers.
*/
/* package */
- void setPara(CharSequence text, int start, int end, int bidiRequest) {
+ void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
mText = text;
mTextStart = start;
@@ -115,13 +115,29 @@
}
}
- if (TextUtils.doesNotNeedBidi(mChars, 0, len)) {
+ if ((textDir == TextDirectionHeuristics.LTR ||
+ textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR ||
+ textDir == TextDirectionHeuristics.ANYRTL_LTR) &&
+ TextUtils.doesNotNeedBidi(mChars, 0, len)) {
mDir = Layout.DIR_LEFT_TO_RIGHT;
mEasy = true;
} else {
if (mLevels == null || mLevels.length < len) {
mLevels = new byte[ArrayUtils.idealByteArraySize(len)];
}
+ int bidiRequest;
+ if (textDir == TextDirectionHeuristics.LTR) {
+ bidiRequest = Layout.DIR_REQUEST_LTR;
+ } else if (textDir == TextDirectionHeuristics.RTL) {
+ bidiRequest = Layout.DIR_REQUEST_RTL;
+ } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR) {
+ bidiRequest = Layout.DIR_REQUEST_DEFAULT_LTR;
+ } else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
+ bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
+ } else {
+ boolean isRtl = textDir.isRtl(mChars, 0, len);
+ bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
+ }
mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels, len, false);
mEasy = false;
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 9e48eff..f7b9502 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -16,8 +16,6 @@
package android.text;
-import com.android.internal.util.ArrayUtils;
-
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.text.style.LeadingMarginSpan;
@@ -26,6 +24,8 @@
import android.text.style.MetricAffectingSpan;
import android.text.style.TabStopSpan;
+import com.android.internal.util.ArrayUtils;
+
/**
* StaticLayout is a Layout for text that will not be edited after it
* is laid out. Use {@link DynamicLayout} for text that may change.
@@ -46,6 +46,17 @@
spacingmult, spacingadd, includepad);
}
+ /**
+ * @hide
+ */
+ public StaticLayout(CharSequence source, TextPaint paint,
+ int width, Alignment align, TextDirectionHeuristic textDir,
+ float spacingmult, float spacingadd,
+ boolean includepad) {
+ this(source, 0, source.length(), paint, width, align, textDir,
+ spacingmult, spacingadd, includepad);
+ }
+
public StaticLayout(CharSequence source, int bufstart, int bufend,
TextPaint paint, int outerwidth,
Alignment align,
@@ -55,9 +66,35 @@
spacingmult, spacingadd, includepad, null, 0);
}
+ /**
+ * @hide
+ */
+ public StaticLayout(CharSequence source, int bufstart, int bufend,
+ TextPaint paint, int outerwidth,
+ Alignment align, TextDirectionHeuristic textDir,
+ float spacingmult, float spacingadd,
+ boolean includepad) {
+ this(source, bufstart, bufend, paint, outerwidth, align, textDir,
+ spacingmult, spacingadd, includepad, null, 0);
+}
+
+ public StaticLayout(CharSequence source, int bufstart, int bufend,
+ TextPaint paint, int outerwidth,
+ Alignment align,
+ float spacingmult, float spacingadd,
+ boolean includepad,
+ TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
+ this(source, bufstart, bufend, paint, outerwidth, align,
+ TextDirectionHeuristics.FIRSTSTRONG_LTR,
+ spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+ }
+
+ /**
+ * @hide
+ */
public StaticLayout(CharSequence source, int bufstart, int bufend,
TextPaint paint, int outerwidth,
- Alignment align,
+ Alignment align, TextDirectionHeuristic textDir,
float spacingmult, float spacingadd,
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
@@ -66,7 +103,7 @@
: (source instanceof Spanned)
? new SpannedEllipsizer(source)
: new Ellipsizer(source),
- paint, outerwidth, align, spacingmult, spacingadd);
+ paint, outerwidth, align, textDir, spacingmult, spacingadd);
/*
* This is annoying, but we can't refer to the layout until
@@ -96,7 +133,7 @@
mMeasured = MeasuredText.obtain();
- generate(source, bufstart, bufend, paint, outerwidth, align,
+ generate(source, bufstart, bufend, paint, outerwidth, align, textDir,
spacingmult, spacingadd, includepad, includepad,
ellipsizedWidth, ellipsize);
@@ -116,7 +153,7 @@
/* package */ void generate(CharSequence source, int bufStart, int bufEnd,
TextPaint paint, int outerWidth,
- Alignment align,
+ Alignment align, TextDirectionHeuristic textDir,
float spacingmult, float spacingadd,
boolean includepad, boolean trackpad,
float ellipsizedWidth, TextUtils.TruncateAt ellipsize) {
@@ -157,7 +194,7 @@
LeadingMarginSpan lms = sp[i];
firstWidth -= sp[i].getLeadingMargin(true);
restWidth -= sp[i].getLeadingMargin(false);
-
+
// LeadingMarginSpan2 is odd. The count affects all
// leading margin spans, not just this particular one,
// and start from the top of the span, not the top of the
@@ -195,7 +232,7 @@
}
}
- measured.setPara(source, paraStart, paraEnd, DIR_REQUEST_DEFAULT_LTR);
+ measured.setPara(source, paraStart, paraEnd, textDir);
char[] chs = measured.mChars;
float[] widths = measured.mWidths;
byte[] chdirs = measured.mLevels;
diff --git a/core/java/android/text/TextDirectionHeuristic.java b/core/java/android/text/TextDirectionHeuristic.java
new file mode 100644
index 0000000..130f879
--- /dev/null
+++ b/core/java/android/text/TextDirectionHeuristic.java
@@ -0,0 +1,13 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package android.text;
+
+/**
+ * Interface for objects that guess at the paragraph direction by examining text.
+ *
+ * @hide
+ */
+public interface TextDirectionHeuristic {
+ /** @hide */ boolean isRtl(CharSequence text, int start, int end);
+ /** @hide */ boolean isRtl(char[] text, int start, int count);
+}
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
new file mode 100644
index 0000000..5f9ffc5
--- /dev/null
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -0,0 +1,310 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package android.text;
+
+
+/**
+ * Some objects that implement TextDirectionHeuristic.
+ * @hide
+ */
+public class TextDirectionHeuristics {
+
+ /** Always decides that the direction is left to right. */
+ public static final TextDirectionHeuristic LTR =
+ new TextDirectionHeuristicInternal(null /* no algorithm */, false);
+
+ /** Always decides that the direction is right to left. */
+ public static final TextDirectionHeuristic RTL =
+ new TextDirectionHeuristicInternal(null /* no algorithm */, true);
+
+ /**
+ * Determines the direction based on the first strong directional character,
+ * including bidi format chars, falling back to left to right if it
+ * finds none. This is the default behavior of the Unicode Bidirectional
+ * Algorithm.
+ */
+ public static final TextDirectionHeuristic FIRSTSTRONG_LTR =
+ new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, false);
+
+ /**
+ * Determines the direction based on the first strong directional character,
+ * including bidi format chars, falling back to right to left if it
+ * finds none. This is similar to the default behavior of the Unicode
+ * Bidirectional Algorithm, just with different fallback behavior.
+ */
+ public static final TextDirectionHeuristic FIRSTSTRONG_RTL =
+ new TextDirectionHeuristicInternal(FirstStrong.INSTANCE, true);
+
+ /**
+ * If the text contains any strong right to left non-format character, determines
+ * that the direction is right to left, falling back to left to right if it
+ * finds none.
+ */
+ public static final TextDirectionHeuristic ANYRTL_LTR =
+ new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_RTL, false);
+
+ /**
+ * If the text contains any strong left to right non-format character, determines
+ * that the direction is left to right, falling back to right to left if it
+ * finds none.
+ */
+ public static final TextDirectionHeuristic ANYLTR_RTL =
+ new TextDirectionHeuristicInternal(AnyStrong.INSTANCE_LTR, true);
+
+ /**
+ * Examines only the strong directional non-format characters, and if either
+ * left to right or right to left characters are 60% or more of this total,
+ * determines that the direction follows the majority of characters. Falls
+ * back to left to right if neither direction meets this threshold.
+ */
+ public static final TextDirectionHeuristic CHARCOUNT_LTR =
+ new TextDirectionHeuristicInternal(CharCount.INSTANCE_DEFAULT, false);
+
+ /**
+ * Examines only the strong directional non-format characters, and if either
+ * left to right or right to left characters are 60% or more of this total,
+ * determines that the direction follows the majority of characters. Falls
+ * back to right to left if neither direction meets this threshold.
+ */
+ public static final TextDirectionHeuristic CHARCOUNT_RTL =
+ new TextDirectionHeuristicInternal(CharCount.INSTANCE_DEFAULT, true);
+
+ private static enum TriState {
+ TRUE, FALSE, UNKNOWN;
+ }
+
+ /**
+ * Computes the text direction based on an algorithm. Subclasses implement
+ * {@link #defaultIsRtl} to handle cases where the algorithm cannot determine the
+ * direction from the text alone.
+ * @hide
+ */
+ public static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic {
+ private final TextDirectionAlgorithm mAlgorithm;
+
+ public TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) {
+ mAlgorithm = algorithm;
+ }
+
+ /**
+ * Return true if the default text direction is rtl.
+ */
+ abstract protected boolean defaultIsRtl();
+
+ @Override
+ public boolean isRtl(CharSequence text, int start, int end) {
+ if (text == null || start < 0 || end < start || text.length() < end) {
+ throw new IllegalArgumentException();
+ }
+ if (mAlgorithm == null) {
+ return defaultIsRtl();
+ }
+ text = text.subSequence(start, end);
+ char[] chars = text.toString().toCharArray();
+ return doCheck(chars, 0, chars.length);
+ }
+
+ @Override
+ public boolean isRtl(char[] chars, int start, int count) {
+ if (chars == null || start < 0 || count < 0 || chars.length - count < start) {
+ throw new IllegalArgumentException();
+ }
+ if (mAlgorithm == null) {
+ return defaultIsRtl();
+ }
+ return doCheck(chars, start, count);
+ }
+
+ private boolean doCheck(char[] chars, int start, int count) {
+ switch(mAlgorithm.checkRtl(chars, start, count)) {
+ case TRUE:
+ return true;
+ case FALSE:
+ return false;
+ default:
+ return defaultIsRtl();
+ }
+ }
+ }
+
+ private static class TextDirectionHeuristicInternal extends TextDirectionHeuristicImpl {
+ private final boolean mDefaultIsRtl;
+
+ private TextDirectionHeuristicInternal(TextDirectionAlgorithm algorithm,
+ boolean defaultIsRtl) {
+ super(algorithm);
+ mDefaultIsRtl = defaultIsRtl;
+ }
+
+ @Override
+ protected boolean defaultIsRtl() {
+ return mDefaultIsRtl;
+ }
+ }
+
+ private static TriState isRtlText(int directionality) {
+ switch (directionality) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ return TriState.FALSE;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ return TriState.TRUE;
+ default:
+ return TriState.UNKNOWN;
+ }
+ }
+
+ private static TriState isRtlTextOrFormat(int directionality) {
+ switch (directionality) {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ return TriState.FALSE;
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+ return TriState.TRUE;
+ default:
+ return TriState.UNKNOWN;
+ }
+ }
+
+ /**
+ * Interface for an algorithm to guess the direction of a paragraph of text.
+ *
+ * @hide
+ */
+ public static interface TextDirectionAlgorithm {
+ /**
+ * Returns whether the range of text is RTL according to the algorithm.
+ *
+ * @hide
+ */
+ TriState checkRtl(char[] text, int start, int count);
+ }
+
+ /**
+ * Algorithm that uses the first strong directional character to determine
+ * the paragraph direction. This is the standard Unicode Bidirectional
+ * algorithm.
+ *
+ * @hide
+ */
+ public static class FirstStrong implements TextDirectionAlgorithm {
+ @Override
+ public TriState checkRtl(char[] text, int start, int count) {
+ TriState result = TriState.UNKNOWN;
+ for (int i = start, e = start + count; i < e && result == TriState.UNKNOWN; ++i) {
+ result = isRtlTextOrFormat(Character.getDirectionality(text[i]));
+ }
+ return result;
+ }
+
+ private FirstStrong() {
+ }
+
+ public static final FirstStrong INSTANCE = new FirstStrong();
+ }
+
+ /**
+ * Algorithm that uses the presence of any strong directional non-format
+ * character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
+ * direction of text.
+ *
+ * @hide
+ */
+ public static class AnyStrong implements TextDirectionAlgorithm {
+ private final boolean mLookForRtl;
+
+ @Override
+ public TriState checkRtl(char[] text, int start, int count) {
+ boolean haveUnlookedFor = false;
+ for (int i = start, e = start + count; i < e; ++i) {
+ switch (isRtlText(Character.getDirectionality(text[i]))) {
+ case TRUE:
+ if (mLookForRtl) {
+ return TriState.TRUE;
+ }
+ haveUnlookedFor = true;
+ break;
+ case FALSE:
+ if (!mLookForRtl) {
+ return TriState.FALSE;
+ }
+ haveUnlookedFor = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (haveUnlookedFor) {
+ return mLookForRtl ? TriState.FALSE : TriState.TRUE;
+ }
+ return TriState.UNKNOWN;
+ }
+
+ private AnyStrong(boolean lookForRtl) {
+ this.mLookForRtl = lookForRtl;
+ }
+
+ public static final AnyStrong INSTANCE_RTL = new AnyStrong(true);
+ public static final AnyStrong INSTANCE_LTR = new AnyStrong(false);
+ }
+
+ /**
+ * Algorithm that uses the relative proportion of strong directional
+ * characters (excluding LRE, LRO, RLE, RLO) to determine the direction
+ * of the paragraph, if the proportion exceeds a given threshold.
+ *
+ * @hide
+ */
+ public static class CharCount implements TextDirectionAlgorithm {
+ private final float mThreshold;
+
+ @Override
+ public TriState checkRtl(char[] text, int start, int count) {
+ int countLtr = 0;
+ int countRtl = 0;
+ for(int i = start, e = start + count; i < e; ++i) {
+ switch (isRtlText(Character.getDirectionality(text[i]))) {
+ case TRUE:
+ ++countLtr;
+ break;
+ case FALSE:
+ ++countRtl;
+ break;
+ default:
+ break;
+ }
+ }
+ int limit = (int)((countLtr + countRtl) * mThreshold);
+ if (limit > 0) {
+ if (countLtr > limit) {
+ return TriState.FALSE;
+ }
+ if (countRtl > limit) {
+ return TriState.TRUE;
+ }
+ }
+ return TriState.UNKNOWN;
+ }
+
+ private CharCount(float threshold) {
+ mThreshold = threshold;
+ }
+
+ public static CharCount withThreshold(float threshold) {
+ if (threshold < 0 || threshold > 1) {
+ throw new IllegalArgumentException();
+ }
+ if (threshold == DEFAULT_THRESHOLD) {
+ return INSTANCE_DEFAULT;
+ }
+ return new CharCount(threshold);
+ }
+
+ public static final float DEFAULT_THRESHOLD = 0.6f;
+ public static final CharCount INSTANCE_DEFAULT = new CharCount(DEFAULT_THRESHOLD);
+ }
+}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 6741059..29c9853 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -16,9 +16,6 @@
package android.text;
-import com.android.internal.R;
-import com.android.internal.util.ArrayUtils;
-
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
@@ -45,6 +42,9 @@
import android.text.style.UnderlineSpan;
import android.util.Printer;
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.regex.Pattern;
@@ -1001,13 +1001,37 @@
* will be padded with zero-width spaces to preserve the original
* length and offsets instead of truncating.
* If <code>callback</code> is non-null, it will be called to
- * report the start and end of the ellipsized range.
+ * report the start and end of the ellipsized range. TextDirection
+ * is determined by the first strong directional character.
*/
public static CharSequence ellipsize(CharSequence text,
TextPaint paint,
float avail, TruncateAt where,
boolean preserveLength,
EllipsizeCallback callback) {
+ return ellipsize(text, paint, avail, where, preserveLength, callback,
+ TextDirectionHeuristics.FIRSTSTRONG_LTR);
+ }
+
+ /**
+ * Returns the original text if it fits in the specified width
+ * given the properties of the specified Paint,
+ * or, if it does not fit, a copy with ellipsis character added
+ * at the specified edge or center.
+ * If <code>preserveLength</code> is specified, the returned copy
+ * will be padded with zero-width spaces to preserve the original
+ * length and offsets instead of truncating.
+ * If <code>callback</code> is non-null, it will be called to
+ * report the start and end of the ellipsized range.
+ *
+ * @hide
+ */
+ public static CharSequence ellipsize(CharSequence text,
+ TextPaint paint,
+ float avail, TruncateAt where,
+ boolean preserveLength,
+ EllipsizeCallback callback,
+ TextDirectionHeuristic textDir) {
if (sEllipsis == null) {
Resources r = Resources.getSystem();
sEllipsis = r.getString(R.string.ellipsis);
@@ -1017,8 +1041,7 @@
MeasuredText mt = MeasuredText.obtain();
try {
- float width = setPara(mt, paint, text, 0, text.length(),
- Layout.DIR_REQUEST_DEFAULT_LTR);
+ float width = setPara(mt, paint, text, 0, text.length(), textDir);
if (width <= avail) {
if (callback != null) {
@@ -1108,11 +1131,20 @@
TextPaint p, float avail,
String oneMore,
String more) {
+ return commaEllipsize(text, p, avail, oneMore, more,
+ TextDirectionHeuristics.FIRSTSTRONG_LTR);
+ }
+
+ /**
+ * @hide
+ */
+ public static CharSequence commaEllipsize(CharSequence text, TextPaint p,
+ float avail, String oneMore, String more, TextDirectionHeuristic textDir) {
MeasuredText mt = MeasuredText.obtain();
try {
int len = text.length();
- float width = setPara(mt, p, text, 0, len, Layout.DIR_REQUEST_DEFAULT_LTR);
+ float width = setPara(mt, p, text, 0, len, textDir);
if (width <= avail) {
return text;
}
@@ -1135,9 +1167,6 @@
int count = 0;
float[] widths = mt.mWidths;
- int request = mt.mDir == 1 ? Layout.DIR_REQUEST_LTR :
- Layout.DIR_REQUEST_RTL;
-
MeasuredText tempMt = MeasuredText.obtain();
for (int i = 0; i < len; i++) {
w += widths[i];
@@ -1155,7 +1184,7 @@
}
// XXX this is probably ok, but need to look at it more
- tempMt.setPara(format, 0, format.length(), request);
+ tempMt.setPara(format, 0, format.length(), textDir);
float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);
if (w + moreWid <= avail) {
@@ -1175,9 +1204,9 @@
}
private static float setPara(MeasuredText mt, TextPaint paint,
- CharSequence text, int start, int end, int bidiRequest) {
+ CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
- mt.setPara(text, start, end, bidiRequest);
+ mt.setPara(text, start, end, textDir);
float width;
Spanned sp = text instanceof Spanned ? (Spanned) text : null;
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index 132b595..09ce8e4 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -196,6 +196,12 @@
private int pos = 0;
private int limit = 0;
+ /*
+ * The offset of the first character in the buffer.
+ */
+ private int bufferStartLine = 1;
+ private int bufferStartColumn = 1;
+
private final List<JsonScope> stack = new ArrayList<JsonScope>();
{
push(JsonScope.EMPTY_DOCUMENT);
@@ -711,6 +717,16 @@
* false.
*/
private boolean fillBuffer(int minimum) throws IOException {
+ // Before clobbering the old characters, update where buffer starts
+ for (int i = 0; i < pos; i++) {
+ if (buffer[i] == '\n') {
+ bufferStartLine++;
+ bufferStartColumn = 1;
+ } else {
+ bufferStartColumn++;
+ }
+ }
+
if (limit != pos) {
limit -= pos;
System.arraycopy(buffer, pos, buffer, 0, limit);
@@ -729,6 +745,28 @@
return false;
}
+ private int getLineNumber() {
+ int result = bufferStartLine;
+ for (int i = 0; i < pos; i++) {
+ if (buffer[i] == '\n') {
+ result++;
+ }
+ }
+ return result;
+ }
+
+ private int getColumnNumber() {
+ int result = bufferStartColumn;
+ for (int i = 0; i < pos; i++) {
+ if (buffer[i] == '\n') {
+ result = 1;
+ } else {
+ result++;
+ }
+ }
+ return result;
+ }
+
private int nextNonWhitespace() throws IOException {
while (pos < limit || fillBuffer(1)) {
int c = buffer[pos++];
@@ -1107,7 +1145,8 @@
* with this reader's content.
*/
private IOException syntaxError(String message) throws IOException {
- throw new MalformedJsonException(message + " near " + getSnippet());
+ throw new MalformedJsonException(message
+ + " at line " + getLineNumber() + " column " + getColumnNumber());
}
private CharSequence getSnippet() {
diff --git a/core/java/android/util/JsonWriter.java b/core/java/android/util/JsonWriter.java
index 47e84c5..c1e6e40 100644
--- a/core/java/android/util/JsonWriter.java
+++ b/core/java/android/util/JsonWriter.java
@@ -407,6 +407,11 @@
* quotation marks except for the characters that must be escaped:
* quotation mark, reverse solidus, and the control characters
* (U+0000 through U+001F)."
+ *
+ * We also escape '\u2028' and '\u2029', which JavaScript interprets
+ * as newline characters. This prevents eval() from failing with a
+ * syntax error.
+ * http://code.google.com/p/google-gson/issues/detail?id=341
*/
switch (c) {
case '"':
@@ -435,6 +440,11 @@
out.write("\\f");
break;
+ case '\u2028':
+ case '\u2029':
+ out.write(String.format("\\u%04x", (int) c));
+ break;
+
default:
if (c <= 0x1F) {
out.write(String.format("\\u%04x", (int) c));
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 7fc43b9..7cf4579 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -23,10 +23,14 @@
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Integers to Objects.
*/
-public class SparseArray<E> {
+public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
+ private int[] mKeys;
+ private Object[] mValues;
+ private int mSize;
+
/**
* Creates a new SparseArray containing no mappings.
*/
@@ -47,6 +51,20 @@
mSize = 0;
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public SparseArray<E> clone() {
+ SparseArray<E> clone = null;
+ try {
+ clone = (SparseArray<E>) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
+ }
+ return clone;
+ }
+
/**
* Gets the Object mapped from the specified key, or <code>null</code>
* if no such mapping has been made.
@@ -59,6 +77,7 @@
* Gets the Object mapped from the specified key, or the specified Object
* if no such mapping has been made.
*/
+ @SuppressWarnings("unchecked")
public E get(int key, E valueIfKeyNotFound) {
int i = binarySearch(mKeys, 0, mSize, key);
@@ -209,6 +228,7 @@
* the value from the <code>index</code>th key-value mapping that this
* SparseArray stores.
*/
+ @SuppressWarnings("unchecked")
public E valueAt(int index) {
if (mGarbage) {
gc();
@@ -331,20 +351,4 @@
else
return ~high;
}
-
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
- private int[] mKeys;
- private Object[] mValues;
- private int mSize;
}
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index f7799de..76c47c6 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -24,7 +24,7 @@
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Integers to Booleans.
*/
-public class SparseBooleanArray {
+public class SparseBooleanArray implements Cloneable {
/**
* Creates a new SparseBooleanArray containing no mappings.
*/
@@ -45,6 +45,19 @@
mSize = 0;
}
+ @Override
+ public SparseBooleanArray clone() {
+ SparseBooleanArray clone = null;
+ try {
+ clone = (SparseBooleanArray) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
+ }
+ return clone;
+ }
+
/**
* Gets the boolean mapped from the specified key, or <code>false</code>
* if no such mapping has been made.
@@ -227,18 +240,6 @@
return ~high;
}
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
private int[] mKeys;
private boolean[] mValues;
private int mSize;
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index 9ab3b53..8d11177 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -23,7 +23,12 @@
* there can be gaps in the indices. It is intended to be more efficient
* than using a HashMap to map Integers to Integers.
*/
-public class SparseIntArray {
+public class SparseIntArray implements Cloneable {
+
+ private int[] mKeys;
+ private int[] mValues;
+ private int mSize;
+
/**
* Creates a new SparseIntArray containing no mappings.
*/
@@ -44,6 +49,19 @@
mSize = 0;
}
+ @Override
+ public SparseIntArray clone() {
+ SparseIntArray clone = null;
+ try {
+ clone = (SparseIntArray) super.clone();
+ clone.mKeys = mKeys.clone();
+ clone.mValues = mValues.clone();
+ } catch (CloneNotSupportedException cnse) {
+ /* ignore */
+ }
+ return clone;
+ }
+
/**
* Gets the int mapped from the specified key, or <code>0</code>
* if no such mapping has been made.
@@ -232,20 +250,4 @@
else
return ~high;
}
-
- private void checkIntegrity() {
- for (int i = 1; i < mSize; i++) {
- if (mKeys[i] <= mKeys[i - 1]) {
- for (int j = 0; j < mSize; j++) {
- Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]);
- }
-
- throw new RuntimeException();
- }
- }
- }
-
- private int[] mKeys;
- private int[] mValues;
- private int mSize;
}
diff --git a/core/java/android/view/ActionProvider.java b/core/java/android/view/ActionProvider.java
index 6491da0..5601dc5 100644
--- a/core/java/android/view/ActionProvider.java
+++ b/core/java/android/view/ActionProvider.java
@@ -28,7 +28,9 @@
* {@link android.app.ActionBar} as a substitute for the menu item when the item is
* displayed as an action item. Also the provider is responsible for performing a
* default action if a menu item placed on the overflow menu of the ActionBar is
- * selected and none of the menu item callbacks has handled the selection.
+ * selected and none of the menu item callbacks has handled the selection. For this
+ * case the provider can also optionally provide a sub-menu for accomplishing the
+ * task at hand.
* </p>
* <p>
* There are two ways for using an action provider for creating and handling of action views:
@@ -76,7 +78,7 @@
* Performs an optional default action.
* <p>
* For the case of an action provider placed in a menu item not shown as an action this
- * method is invoked if none of the callbacks for processing menu selection has handled
+ * method is invoked if previous callbacks for processing menu selection has handled
* the event.
* </p>
* <p>
@@ -104,11 +106,36 @@
* </ul>
* </p>
* <p>
- * The default implementation does not perform any action.
+ * The default implementation does not perform any action and returns false.
* </p>
- *
- * @param actionView A view created by {@link #onCreateActionView()}.
*/
- public void onPerformDefaultAction(View actionView) {
+ public boolean onPerformDefaultAction() {
+ return false;
+ }
+
+ /**
+ * Determines if this ActionProvider has a submenu associated with it.
+ *
+ * <p>Associated submenus will be shown when an action view is not. This
+ * provider instance will receive a call to {@link #onPrepareSubMenu(SubMenu)}
+ * after the call to {@link #onPerformDefaultAction()} and before a submenu is
+ * displayed to the user.
+ *
+ * @return true if the item backed by this provider should have an associated submenu
+ */
+ public boolean hasSubMenu() {
+ return false;
+ }
+
+ /**
+ * Called to prepare an associated submenu for the menu item backed by this ActionProvider.
+ *
+ * <p>if {@link #hasSubMenu()} returns true, this method will be called when the
+ * menu item is selected to prepare the submenu for presentation to the user. Apps
+ * may use this to create or alter submenu content right before display.
+ *
+ * @param subMenu Submenu that will be displayed
+ */
+ public void onPrepareSubMenu(SubMenu subMenu) {
}
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 1638c74..011e44c 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -128,10 +128,19 @@
abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
/**
- * Invoked whenever the size of the target surface changes. This will
- * not be invoked when the surface is first created.
+ * This method should be invoked whenever the current hardware renderer
+ * context should be reset.
*/
- abstract void preapareSurfaceForResize();
+ abstract void invalidate();
+
+ /**
+ * This method should be invoked to ensure the hardware renderer is in
+ * valid state (for instance, to ensure the correct EGL context is bound
+ * to the current thread.)
+ *
+ * @return true if the renderer is now valid, false otherwise
+ */
+ abstract boolean validate();
/**
* Setup the hardware renderer for drawing. This is called whenever the
@@ -629,11 +638,16 @@
}
@Override
- void preapareSurfaceForResize() {
+ void invalidate() {
// Cancels any existing buffer to ensure we'll get a buffer
// of the right size before we call eglSwapBuffers
sEgl.eglMakeCurrent(sEglDisplay, EGL10.EGL_NO_SURFACE,
- EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ }
+
+ @Override
+ boolean validate() {
+ return checkCurrent() != SURFACE_STATE_ERROR;
}
@Override
@@ -662,7 +676,7 @@
attachInfo.mDrawingTime = SystemClock.uptimeMillis();
view.mPrivateFlags |= View.DRAWN;
-
+
final int surfaceState = checkCurrent();
if (surfaceState != SURFACE_STATE_ERROR) {
// We had to change the current surface and/or context, redraw everything
@@ -723,10 +737,21 @@
}
}
}
-
+
+ /**
+ * Ensures the currnet EGL context is the one we expect.
+ *
+ * @return {@link #SURFACE_STATE_ERROR} if the correct EGL context cannot be made current,
+ * {@link #SURFACE_STATE_UPDATED} if the EGL context was changed or
+ * {@link #SURFACE_STATE_SUCCESS} if the EGL context was the correct one
+ */
private int checkCurrent() {
- // TODO: Don't check the current context when we have one per UI thread
- // TODO: Use a threadlocal flag to know whether the surface has changed
+ if (sEglThread != Thread.currentThread()) {
+ throw new IllegalStateException("Hardware acceleration can only be used with a " +
+ "single UI thread.\nOriginal thread: " + sEglThread + "\n" +
+ "Current thread: " + Thread.currentThread());
+ }
+
if (!sEglContext.equals(sEgl.eglGetCurrentContext()) ||
!mEglSurface.equals(sEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
if (!sEgl.eglMakeCurrent(sEglDisplay, mEglSurface, mEglSurface, sEglContext)) {
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index a7f0cba..c46e43a 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -166,7 +166,12 @@
// Add the item if it hasn't been added (if the item was
// a submenu, it would have been added already)
if (!menuState.hasAddedItem()) {
- menuState.addItem();
+ if (menuState.itemActionProvider != null &&
+ menuState.itemActionProvider.hasSubMenu()) {
+ menuState.addSubMenuItem();
+ } else {
+ menuState.addItem();
+ }
}
} else if (tagName.equals(XML_MENU)) {
reachedEndOfMenu = true;
@@ -270,6 +275,8 @@
private String itemListenerMethodName;
+ private ActionProvider itemActionProvider;
+
private static final int defaultGroupId = NO_ID;
private static final int defaultItemId = NO_ID;
private static final int defaultItemCategory = 0;
@@ -347,6 +354,19 @@
itemActionViewClassName = a.getString(com.android.internal.R.styleable.MenuItem_actionViewClass);
itemActionProviderClassName = a.getString(com.android.internal.R.styleable.MenuItem_actionProviderClass);
+ final boolean hasActionProvider = itemActionProviderClassName != null;
+ if (hasActionProvider && itemActionViewLayout == 0 && itemActionViewClassName == null) {
+ itemActionProvider = newInstance(itemActionProviderClassName,
+ ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE,
+ mActionProviderConstructorArguments);
+ } else {
+ if (hasActionProvider) {
+ Log.w(LOG_TAG, "Ignoring attribute 'actionProviderClass'."
+ + " Action view already specified.");
+ }
+ itemActionProvider = null;
+ }
+
a.recycle();
itemAdded = false;
@@ -406,16 +426,8 @@
+ " Action view already specified.");
}
}
- if (itemActionProviderClassName != null) {
- if (!actionViewSpecified) {
- ActionProvider actionProvider = newInstance(itemActionProviderClassName,
- ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE,
- mActionProviderConstructorArguments);
- item.setActionProvider(actionProvider);
- } else {
- Log.w(LOG_TAG, "Ignoring attribute 'itemActionProviderClass'."
- + " Action view already specified.");
- }
+ if (itemActionProvider != null) {
+ item.setActionProvider(itemActionProvider);
}
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index d656f31..96d6f09 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -20,6 +20,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.util.AttributeSet;
import android.util.Log;
@@ -107,6 +108,14 @@
private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
+ private Canvas mCanvas;
+ private int mSaveCount;
+
+ private final Object[] mNativeWindowLock = new Object[0];
+ // Used from native code, do not write!
+ @SuppressWarnings({"UnusedDeclaration"})
+ private int mNativeWindow;
+
/**
* Creates a new TextureView.
*
@@ -190,7 +199,11 @@
mListener.onSurfaceTextureDestroyed(mSurface);
}
- mLayer.destroy();
+ synchronized (mNativeWindowLock) {
+ nDestroyNativeWindow();
+ }
+
+ mLayer.destroy();
mSurface = null;
mLayer = null;
}
@@ -274,6 +287,7 @@
mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ nCreateNativeWindow(mSurface);
mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
@Override
@@ -431,6 +445,79 @@
}
/**
+ * <p>Start editing the pixels in the surface. The returned Canvas can be used
+ * to draw into the surface's bitmap. A null is returned if the surface has
+ * not been created or otherwise cannot be edited. You will usually need
+ * to implement
+ * {@link SurfaceTextureListener#onSurfaceTextureAvailable(android.graphics.SurfaceTexture, int, int)}
+ * to find out when the Surface is available for use.</p>
+ *
+ * <p>The content of the Surface is never preserved between unlockCanvas()
+ * and lockCanvas(), for this reason, every pixel within the Surface area
+ * must be written. The only exception to this rule is when a dirty
+ * rectangle is specified, in which case, non-dirty pixels will be
+ * preserved.</p>
+ *
+ * @return A Canvas used to draw into the surface.
+ *
+ * @see #lockCanvas(android.graphics.Rect)
+ * @see #unlockCanvasAndPost(android.graphics.Canvas)
+ */
+ public Canvas lockCanvas() {
+ return lockCanvas(null);
+ }
+
+ /**
+ * Just like {@link #lockCanvas()} but allows specification of a dirty
+ * rectangle. Every pixel within that rectangle must be written; however
+ * pixels outside the dirty rectangle will be preserved by the next call
+ * to lockCanvas().
+ *
+ * @param dirty Area of the surface that will be modified.
+
+ * @return A Canvas used to draw into the surface.
+ *
+ * @see #lockCanvas()
+ * @see #unlockCanvasAndPost(android.graphics.Canvas)
+ */
+ public Canvas lockCanvas(Rect dirty) {
+ if (!isAvailable()) return null;
+
+ if (mCanvas == null) {
+ mCanvas = new Canvas();
+ }
+
+ synchronized (mNativeWindowLock) {
+ nLockCanvas(mNativeWindow, mCanvas, dirty);
+ }
+ mSaveCount = mCanvas.save();
+
+ return mCanvas;
+ }
+
+ /**
+ * Finish editing pixels in the surface. After this call, the surface's
+ * current pixels will be shown on the screen, but its content is lost,
+ * in particular there is no guarantee that the content of the Surface
+ * will remain unchanged when lockCanvas() is called again.
+ *
+ * @param canvas The Canvas previously returned by lockCanvas()
+ *
+ * @see #lockCanvas()
+ * @see #lockCanvas(android.graphics.Rect)
+ */
+ public void unlockCanvasAndPost(Canvas canvas) {
+ if (mCanvas != null && canvas == mCanvas) {
+ canvas.restoreToCount(mSaveCount);
+ mSaveCount = 0;
+
+ synchronized (mNativeWindowLock) {
+ nUnlockCanvasAndPost(mNativeWindow, mCanvas);
+ }
+ }
+ }
+
+ /**
* Returns the {@link SurfaceTexture} used by this view. This method
* may return null if the view is not attached to a window or if the surface
* texture has not been initialized yet.
@@ -506,6 +593,12 @@
public void onSurfaceTextureUpdated(SurfaceTexture surface);
}
+ private native void nCreateNativeWindow(SurfaceTexture surface);
+ private native void nDestroyNativeWindow();
+
private static native void nSetDefaultBufferSize(SurfaceTexture surfaceTexture,
int width, int height);
+
+ private static native void nLockCanvas(int nativeWindow, Canvas canvas, Rect dirty);
+ private static native void nUnlockCanvasAndPost(int nativeWindow, Canvas canvas);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 74dc100..4385c2f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,13 +16,6 @@
package android.view;
-import android.util.FloatProperty;
-import android.util.LocaleUtil;
-import android.util.Property;
-import com.android.internal.R;
-import com.android.internal.util.Predicate;
-import com.android.internal.view.menu.MenuBuilder;
-
import android.content.ClipData;
import android.content.Context;
import android.content.res.Configuration;
@@ -53,11 +46,14 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.LocaleUtil;
import android.util.Log;
import android.util.Pool;
import android.util.Poolable;
import android.util.PoolableManager;
import android.util.Pools;
+import android.util.Property;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ContextMenu.ContextMenuInfo;
@@ -72,6 +68,10 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.ScrollBarDrawable;
+import com.android.internal.R;
+import com.android.internal.util.Predicate;
+import com.android.internal.view.menu.MenuBuilder;
+
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -2167,21 +2167,27 @@
/**
* Cache the paddingRight set by the user to append to the scrollbar's size.
+ *
+ * @hide
*/
@ViewDebug.ExportedProperty(category = "padding")
- int mUserPaddingRight;
+ protected int mUserPaddingRight;
/**
* Cache the paddingBottom set by the user to append to the scrollbar's size.
+ *
+ * @hide
*/
@ViewDebug.ExportedProperty(category = "padding")
- int mUserPaddingBottom;
+ protected int mUserPaddingBottom;
/**
* Cache the paddingLeft set by the user to append to the scrollbar's size.
+ *
+ * @hide
*/
@ViewDebug.ExportedProperty(category = "padding")
- int mUserPaddingLeft;
+ protected int mUserPaddingLeft;
/**
* Cache if the user padding is relative.
@@ -2493,12 +2499,6 @@
private boolean mSendingHoverAccessibilityEvents;
/**
- * Undefined text direction (used by resolution algorithm).
- * @hide
- */
- public static final int TEXT_DIRECTION_UNDEFINED = -1;
-
- /**
* Text direction is inherited thru {@link ViewGroup}
* @hide
*/
@@ -2507,7 +2507,7 @@
/**
* Text direction is using "first strong algorithm". The first strong directional character
* determines the paragraph direction. If there is no strong directional character, the
- * paragraph direction is the view’s resolved ayout direction.
+ * paragraph direction is the view's resolved ayout direction.
*
* @hide
*/
@@ -2516,7 +2516,7 @@
/**
* Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains
* any strong RTL character, otherwise it is LTR if it contains any strong LTR characters.
- * If there are neither, the paragraph direction is the view’s resolved layout direction.
+ * If there are neither, the paragraph direction is the view's resolved layout direction.
*
* @hide
*/
@@ -2560,7 +2560,6 @@
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
- @ViewDebug.IntToString(from = TEXT_DIRECTION_UNDEFINED, to = "UNDEFINED"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
@@ -2568,21 +2567,25 @@
@ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL")
})
- protected int mTextDirection = DEFAULT_TEXT_DIRECTION;
+ private int mTextDirection = DEFAULT_TEXT_DIRECTION;
/**
- * The resolved text direction. If resolution has not yet been done or has been reset, it will
- * be equal to {@link #TEXT_DIRECTION_UNDEFINED}. Otherwise it will be either {@link #TEXT_DIRECTION_LTR}
- * or {@link #TEXT_DIRECTION_RTL}.
+ * The resolved text direction. This needs resolution if the value is
+ * TEXT_DIRECTION_INHERIT. The resolution matches mTextDirection if that is
+ * not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds up the parent
+ * chain of the view.
*
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
- @ViewDebug.IntToString(from = TEXT_DIRECTION_UNDEFINED, to = "UNDEFINED"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
+ @ViewDebug.IntToString(from = TEXT_DIRECTION_CHAR_COUNT, to = "CHAR_COUNT"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
@ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL")
})
- protected int mResolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ private int mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
/**
* Consistency verifier for debugging purposes.
@@ -9066,11 +9069,20 @@
// Set resolved depending on layout direction
switch (getLayoutDirection()) {
case LAYOUT_DIRECTION_INHERIT:
+ // We cannot do the resolution if there is no parent
+ if (mParent == null) return;
+
// If this is root view, no need to look at parent's layout dir.
- if (mParent != null &&
- mParent instanceof ViewGroup &&
- ((ViewGroup) mParent).getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
- mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+ if (mParent instanceof ViewGroup) {
+ ViewGroup viewGroup = ((ViewGroup) mParent);
+
+ // Check if the parent view group can resolve
+ if (! viewGroup.canResolveLayoutDirection()) {
+ return;
+ }
+ if (viewGroup.getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+ mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+ }
}
break;
case LAYOUT_DIRECTION_RTL:
@@ -9115,12 +9127,12 @@
// Start user padding override Left user padding. Otherwise, if Left user
// padding is not defined, use the default left padding. If Left user padding
// is defined, just use it.
- if (mUserPaddingStart > 0) {
+ if (mUserPaddingStart >= 0) {
mUserPaddingLeft = mUserPaddingStart;
} else if (mUserPaddingLeft < 0) {
mUserPaddingLeft = mPaddingLeft;
}
- if (mUserPaddingEnd > 0) {
+ if (mUserPaddingEnd >= 0) {
mUserPaddingRight = mUserPaddingEnd;
} else if (mUserPaddingRight < 0) {
mUserPaddingRight = mPaddingRight;
@@ -9132,6 +9144,15 @@
recomputePadding();
}
+ protected boolean canResolveLayoutDirection() {
+ switch (getLayoutDirection()) {
+ case LAYOUT_DIRECTION_INHERIT:
+ return (mParent != null);
+ default:
+ return true;
+ }
+ }
+
/**
* Reset the resolved layout direction.
*
@@ -11101,6 +11122,10 @@
* background
*/
public void setBackgroundDrawable(Drawable d) {
+ if (d == mBGDrawable) {
+ return;
+ }
+
boolean requestLayout = false;
mBackgroundResource = 0;
@@ -13048,43 +13073,41 @@
*
* @return the resolved text direction. Return one of:
*
+ * {@link #TEXT_DIRECTION_FIRST_STRONG}
+ * {@link #TEXT_DIRECTION_ANY_RTL},
+ * {@link #TEXT_DIRECTION_CHAR_COUNT},
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
*
* @hide
*/
public int getResolvedTextDirection() {
- if (!isResolvedTextDirection()) {
+ if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) {
resolveTextDirection();
}
return mResolvedTextDirection;
}
/**
- * Resolve the text direction. Classes that extend View and want to do a specific text direction
- * resolution will need to implement this method and set the mResolvedTextDirection to
- * either TEXT_DIRECTION_LTR if direction is LTR or TEXT_DIRECTION_RTL if
- * direction is RTL.
+ * Resolve the text direction.
*/
protected void resolveTextDirection() {
+ if (mTextDirection != TEXT_DIRECTION_INHERIT) {
+ mResolvedTextDirection = mTextDirection;
+ return;
+ }
+ if (mParent != null && mParent instanceof ViewGroup) {
+ mResolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
+ return;
+ }
+ mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
}
/**
- * Return if the text direction has been resolved or not.
- *
- * @return true, if resolved and false if not resolved
- *
- * @hide
- */
- public boolean isResolvedTextDirection() {
- return (mResolvedTextDirection != TEXT_DIRECTION_UNDEFINED);
- }
-
- /**
- * Reset resolved text direction. Will be resolved during a call to getResolvedLayoutDirection().
+ * Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection().
*/
protected void resetResolvedTextDirection() {
- mResolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
+ mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
}
//
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index c0619a5..ac73611 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -901,6 +901,7 @@
!mAttachInfo.mTurnOffWindowResizeAnim &&
mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled() &&
+ mAttachInfo.mHardwareRenderer.validate() &&
lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
disposeResizeBuffer();
@@ -1314,10 +1315,10 @@
if (hwInitialized || ((windowShouldResize || params != null) &&
mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled())) {
- if (!hwInitialized) {
- mAttachInfo.mHardwareRenderer.preapareSurfaceForResize();
- }
mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
+ if (!hwInitialized) {
+ mAttachInfo.mHardwareRenderer.invalidate();
+ }
}
if (!mStopped) {
@@ -2208,6 +2209,62 @@
public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT = 1023;
@Override
+ public String getMessageName(Message message) {
+ switch (message.what) {
+ case DO_TRAVERSAL:
+ return "DO_TRAVERSAL";
+ case DIE:
+ return "DIE";
+ case RESIZED:
+ return "RESIZED";
+ case RESIZED_REPORT:
+ return "RESIZED_REPORT";
+ case WINDOW_FOCUS_CHANGED:
+ return "WINDOW_FOCUS_CHANGED";
+ case DISPATCH_KEY:
+ return "DISPATCH_KEY";
+ case DISPATCH_POINTER:
+ return "DISPATCH_POINTER";
+ case DISPATCH_TRACKBALL:
+ return "DISPATCH_TRACKBALL";
+ case DISPATCH_APP_VISIBILITY:
+ return "DISPATCH_APP_VISIBILITY";
+ case DISPATCH_GET_NEW_SURFACE:
+ return "DISPATCH_GET_NEW_SURFACE";
+ case FINISHED_EVENT:
+ return "FINISHED_EVENT";
+ case DISPATCH_KEY_FROM_IME:
+ return "DISPATCH_KEY_FROM_IME";
+ case FINISH_INPUT_CONNECTION:
+ return "FINISH_INPUT_CONNECTION";
+ case CHECK_FOCUS:
+ return "CHECK_FOCUS";
+ case CLOSE_SYSTEM_DIALOGS:
+ return "CLOSE_SYSTEM_DIALOGS";
+ case DISPATCH_DRAG_EVENT:
+ return "DISPATCH_DRAG_EVENT";
+ case DISPATCH_DRAG_LOCATION_EVENT:
+ return "DISPATCH_DRAG_LOCATION_EVENT";
+ case DISPATCH_SYSTEM_UI_VISIBILITY:
+ return "DISPATCH_SYSTEM_UI_VISIBILITY";
+ case DISPATCH_GENERIC_MOTION:
+ return "DISPATCH_GENERIC_MOTION";
+ case UPDATE_CONFIGURATION:
+ return "UPDATE_CONFIGURATION";
+ case DO_PERFORM_ACCESSIBILITY_ACTION:
+ return "DO_PERFORM_ACCESSIBILITY_ACTION";
+ case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
+ return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
+ case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
+ return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
+ case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT:
+ return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_TEXT";
+
+ }
+ return super.getMessageName(message);
+ }
+
+ @Override
public void handleMessage(Message msg) {
switch (msg.what) {
case View.AttachInfo.INVALIDATE_MSG:
@@ -2633,8 +2690,9 @@
mInputEventDeliverTimeNanos = System.nanoTime();
}
+ final boolean isTouchEvent = event.isTouchEvent();
if (mInputEventConsistencyVerifier != null) {
- if (event.isTouchEvent()) {
+ if (isTouchEvent) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
} else {
mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
@@ -2652,9 +2710,9 @@
mTranslator.translateEventInScreenToAppWindow(event);
}
- // Enter touch mode on the down.
- boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN;
- if (isDown) {
+ // Enter touch mode on down or scroll.
+ final int action = event.getAction();
+ if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
ensureTouchMode(true);
}
@@ -2667,8 +2725,10 @@
}
// Remember the touch position for possible drag-initiation.
- mLastTouchPoint.x = event.getRawX();
- mLastTouchPoint.y = event.getRawY();
+ if (isTouchEvent) {
+ mLastTouchPoint.x = event.getRawX();
+ mLastTouchPoint.y = event.getRawY();
+ }
// Dispatch touch to view hierarchy.
boolean handled = mView.dispatchPointerEvent(event);
@@ -2680,51 +2740,6 @@
return;
}
- // Apply edge slop and try again, if appropriate.
- final int edgeFlags = event.getEdgeFlags();
- if (edgeFlags != 0 && mView instanceof ViewGroup) {
- final int edgeSlop = mViewConfiguration.getScaledEdgeSlop();
- int direction = View.FOCUS_UP;
- int x = (int)event.getX();
- int y = (int)event.getY();
- final int[] deltas = new int[2];
-
- if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) {
- direction = View.FOCUS_DOWN;
- if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
- deltas[0] = edgeSlop;
- x += edgeSlop;
- } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
- deltas[0] = -edgeSlop;
- x -= edgeSlop;
- }
- } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) {
- direction = View.FOCUS_UP;
- if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
- deltas[0] = edgeSlop;
- x += edgeSlop;
- } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
- deltas[0] = -edgeSlop;
- x -= edgeSlop;
- }
- } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) {
- direction = View.FOCUS_RIGHT;
- } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) {
- direction = View.FOCUS_LEFT;
- }
-
- View nearest = FocusFinder.getInstance().findNearestTouchable(
- ((ViewGroup) mView), x, y, direction, deltas);
- if (nearest != null) {
- event.offsetLocation(deltas[0], deltas[1]);
- event.setEdgeFlags(0);
- if (mView.dispatchPointerEvent(event)) {
- finishMotionEvent(event, sendDone, true);
- return;
- }
- }
- }
-
// Pointer event was unhandled.
finishMotionEvent(event, sendDone, false);
}
@@ -3848,10 +3863,6 @@
}
private static int checkCallingPermission(String permission) {
- if (!Process.supportsProcesses()) {
- return PackageManager.PERMISSION_GRANTED;
- }
-
try {
return ActivityManagerNative.getDefault().checkPermission(
permission, Binder.getCallingPid(), Binder.getCallingUid());
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index f014070..f7f5a21 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -16,41 +16,45 @@
package android.view;
-import android.util.Log;
-import android.util.DisplayMetrics;
-import android.content.res.Resources;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
-import android.os.Environment;
import android.os.Debug;
+import android.os.Environment;
+import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Printer;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
+import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.FileOutputStream;
-import java.io.DataOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.BufferedOutputStream;
import java.io.OutputStream;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.lang.annotation.Target;
+import java.io.OutputStreamWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.annotation.Target;
import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Various debugging/tracing tools related to {@link View} and the view hierarchy.
@@ -106,13 +110,6 @@
public static final boolean DEBUG_PROFILE_LAYOUT = false;
/**
- * Profiles real fps (times between draws) and displays the result.
- *
- * @hide
- */
- public static final boolean DEBUG_SHOW_FPS = false;
-
- /**
* Enables detailed logging of drag/drop operations.
* @hide
*/
@@ -396,6 +393,9 @@
private static List<RecyclerTrace> sRecyclerTraces;
private static String sRecyclerTracePrefix;
+ private static final ThreadLocal<LooperProfiler> sLooperProfilerStorage =
+ new ThreadLocal<LooperProfiler>();
+
/**
* Returns the number of instanciated Views.
*
@@ -419,6 +419,124 @@
}
/**
+ * Starts profiling the looper associated with the current thread.
+ * You must call {@link #stopLooperProfiling} to end profiling
+ * and obtain the traces. Both methods must be invoked on the
+ * same thread.
+ *
+ * @param traceFile The path where to write the looper traces
+ *
+ * @see #stopLooperProfiling()
+ */
+ public static void startLooperProfiling(File traceFile) {
+ if (sLooperProfilerStorage.get() == null) {
+ LooperProfiler profiler = new LooperProfiler(traceFile);
+ sLooperProfilerStorage.set(profiler);
+ Looper.myLooper().setMessageLogging(profiler);
+ }
+ }
+
+ /**
+ * Stops profiling the looper associated with the current thread.
+ *
+ * @see #startLooperProfiling(java.io.File)
+ */
+ public static void stopLooperProfiling() {
+ LooperProfiler profiler = sLooperProfilerStorage.get();
+ if (profiler != null) {
+ sLooperProfilerStorage.remove();
+ Looper.myLooper().setMessageLogging(null);
+ profiler.save();
+ }
+ }
+
+ private static class LooperProfiler implements Looper.Profiler, Printer {
+ private static final int LOOPER_PROFILER_VERSION = 1;
+
+ private static final String LOG_TAG = "LooperProfiler";
+
+ private final ArrayList<Entry> mTraces = new ArrayList<Entry>(512);
+ private final File mTraceFile;
+
+ public LooperProfiler(File traceFile) {
+ mTraceFile = traceFile;
+ }
+
+ @Override
+ public void println(String x) {
+ // Ignore messages
+ }
+
+ @Override
+ public void profile(Message message, long wallStart, long wallTime, long threadTime) {
+ Entry entry = new Entry();
+ entry.messageId = message.what;
+ entry.name = message.getTarget().getMessageName(message);
+ entry.wallStart = wallStart;
+ entry.wallTime = wallTime;
+ entry.threadTime = threadTime;
+
+ mTraces.add(entry);
+ }
+
+ void save() {
+ // Don't block the UI thread
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ saveTraces();
+ }
+ }, "LooperProfiler[" + mTraceFile + "]").start();
+ }
+
+ private void saveTraces() {
+ FileOutputStream fos;
+ try {
+ fos = new FileOutputStream(mTraceFile);
+ } catch (FileNotFoundException e) {
+ Log.e(LOG_TAG, "Could not open trace file: " + mTraceFile);
+ return;
+ }
+
+ DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
+
+ try {
+ out.writeInt(LOOPER_PROFILER_VERSION);
+ out.writeInt(mTraces.size());
+ for (Entry entry : mTraces) {
+ saveTrace(entry, out);
+ }
+
+ Log.d(LOG_TAG, "Looper traces ready: " + mTraceFile);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Could not write trace file: ", e);
+ } finally {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private void saveTrace(Entry entry, DataOutputStream out) throws IOException {
+ out.writeInt(entry.messageId);
+ out.writeUTF(entry.name);
+ out.writeLong(entry.wallStart);
+ out.writeLong(entry.wallTime);
+ out.writeLong(entry.threadTime);
+ }
+
+ static class Entry {
+ int messageId;
+ String name;
+ long wallStart;
+ long wallTime;
+ long threadTime;
+ }
+ }
+
+ /**
* Outputs a trace to the currently opened recycler traces. The trace records the type of
* recycler action performed on the supplied view as well as a number of parameters.
*
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 752fd5a..cb3e9c6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -41,6 +41,7 @@
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.view.animation.Transformation;
+
import com.android.internal.R;
import com.android.internal.util.Predicate;
@@ -5012,37 +5013,6 @@
}
}
- /**
- * This method will be called during text direction resolution (text direction resolution
- * inheritance)
- */
- @Override
- protected void resolveTextDirection() {
- int resolvedTextDirection;
- switch(mTextDirection) {
- default:
- case TEXT_DIRECTION_INHERIT:
- // Try to the text direction from the parent layout
- if (mParent != null && mParent instanceof ViewGroup) {
- resolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
- } else {
- // We reached the top of the View hierarchy, so set the text direction
- // heuristic to "first strong"
- resolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
- }
- break;
- // Pass down the hierarchy the following text direction values
- case TEXT_DIRECTION_FIRST_STRONG:
- case TEXT_DIRECTION_ANY_RTL:
- case TEXT_DIRECTION_CHAR_COUNT:
- case TEXT_DIRECTION_LTR:
- case TEXT_DIRECTION_RTL:
- resolvedTextDirection = mTextDirection;
- break;
- }
- mResolvedTextDirection = resolvedTextDirection;
- }
-
@Override
protected void resetResolvedTextDirection() {
super.resetResolvedTextDirection();
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index ac86769..9be2a67 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -552,7 +552,8 @@
/**
* Returns a cached instance if such is available or a new one is
- * initialized with from the given <code>event</code>.
+ * created. The returned instance is initialized from the given
+ * <code>event</code>.
*
* @param event The other event.
* @return An instance.
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 314b7ca..83c73cb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -71,7 +71,9 @@
private static AccessibilityManager sInstance;
- private static final int DO_SET_ENABLED = 10;
+ private static final int DO_SET_ACCESSIBILITY_ENABLED = 10;
+
+ private static final int DO_SET_TOUCH_EXPLORATION_ENABLED = 20;
final IAccessibilityManager mService;
@@ -79,6 +81,8 @@
boolean mIsEnabled;
+ boolean mIsTouchExplorationEnabled;
+
final CopyOnWriteArrayList<AccessibilityStateChangeListener> mAccessibilityStateChangeListeners =
new CopyOnWriteArrayList<AccessibilityStateChangeListener>();
@@ -97,7 +101,12 @@
final IAccessibilityManagerClient.Stub mClient = new IAccessibilityManagerClient.Stub() {
public void setEnabled(boolean enabled) {
- mHandler.obtainMessage(DO_SET_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
+ mHandler.obtainMessage(DO_SET_ACCESSIBILITY_ENABLED, enabled ? 1 : 0, 0).sendToTarget();
+ }
+
+ public void setTouchExplorationEnabled(boolean enabled) {
+ mHandler.obtainMessage(DO_SET_TOUCH_EXPLORATION_ENABLED,
+ enabled ? 1 : 0, 0).sendToTarget();
}
};
@@ -110,9 +119,14 @@
@Override
public void handleMessage(Message message) {
switch (message.what) {
- case DO_SET_ENABLED :
- final boolean isEnabled = (message.arg1 == 1);
- setAccessibilityState(isEnabled);
+ case DO_SET_ACCESSIBILITY_ENABLED :
+ final boolean isAccessibilityEnabled = (message.arg1 == 1);
+ setAccessibilityState(isAccessibilityEnabled);
+ return;
+ case DO_SET_TOUCH_EXPLORATION_ENABLED :
+ synchronized (mHandler) {
+ mIsTouchExplorationEnabled = (message.arg1 == 1);
+ }
return;
default :
Log.w(LOG_TAG, "Unknown message type: " + message.what);
@@ -168,6 +182,17 @@
}
/**
+ * Returns if the touch exploration in the system is enabled.
+ *
+ * @return True if touch exploration is enabled, false otherwise.
+ */
+ public boolean isTouchExplorationEnabled() {
+ synchronized (mHandler) {
+ return mIsTouchExplorationEnabled;
+ }
+ }
+
+ /**
* Returns the client interface this instance registers in
* the centralized accessibility manager service.
*
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 031c6ae..0e04471 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -120,7 +120,7 @@
private CharSequence mText;
private CharSequence mContentDescription;
- private final SparseIntArray mChildAccessibilityIds = new SparseIntArray();
+ private SparseIntArray mChildAccessibilityIds = new SparseIntArray();
private int mActions;
private IAccessibilityServiceConnection mConnection;
@@ -873,6 +873,20 @@
}
/**
+ * Returns a cached instance if such is available or a new one is
+ * create. The returned instance is initialized from the given
+ * <code>info</code>.
+ *
+ * @param info The other info.
+ * @return An instance.
+ */
+ public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
+ AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
+ infoClone.init(info);
+ return infoClone;
+ }
+
+ /**
* Return an instance back to be reused.
* <p>
* <strong>Note:</strong> You must not touch the object after calling this function.
@@ -945,6 +959,28 @@
}
/**
+ * Initializes this instance from another one.
+ *
+ * @param other The other instance.
+ */
+ private void init(AccessibilityNodeInfo other) {
+ mSealed = other.mSealed;
+ mConnection = other.mConnection;
+ mAccessibilityViewId = other.mAccessibilityViewId;
+ mParentAccessibilityViewId = other.mParentAccessibilityViewId;
+ mAccessibilityWindowId = other.mAccessibilityWindowId;
+ mBoundsInParent.set(other.mBoundsInParent);
+ mBoundsInScreen.set(other.mBoundsInScreen);
+ mPackageName = other.mPackageName;
+ mClassName = other.mClassName;
+ mText = other.mText;
+ mContentDescription = other.mContentDescription;
+ mActions= other.mActions;
+ mBooleanProperties = other.mBooleanProperties;
+ mChildAccessibilityIds = other.mChildAccessibilityIds.clone();
+ }
+
+ /**
* Creates a new instance from a {@link Parcel}.
*
* @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
@@ -994,6 +1030,7 @@
mConnection = null;
mAccessibilityViewId = View.NO_ID;
mParentAccessibilityViewId = View.NO_ID;
+ mAccessibilityWindowId = View.NO_ID;
mChildAccessibilityIds.clear();
mBoundsInParent.set(0, 0, 0, 0);
mBoundsInScreen.set(0, 0, 0, 0);
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index f4d5e89..210106f 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -50,7 +50,7 @@
*/
public class AccessibilityRecord {
- private static final int INVALID_POSITION = -1;
+ private static final int UNDEFINED = -1;
private static final int PROPERTY_CHECKED = 0x00000001;
private static final int PROPERTY_ENABLED = 0x00000002;
@@ -68,15 +68,15 @@
boolean mSealed;
int mBooleanProperties;
- int mCurrentItemIndex;
- int mItemCount;
- int mFromIndex;
- int mToIndex;
- int mScrollX;
- int mScrollY;
+ int mCurrentItemIndex = UNDEFINED;
+ int mItemCount = UNDEFINED;
+ int mFromIndex = UNDEFINED;
+ int mToIndex = UNDEFINED;
+ int mScrollX = UNDEFINED;
+ int mScrollY = UNDEFINED;
- int mAddedCount;
- int mRemovedCount;
+ int mAddedCount= UNDEFINED;
+ int mRemovedCount = UNDEFINED;
int mSourceViewId = View.NO_ID;
int mSourceWindowId = View.NO_ID;
@@ -681,14 +681,14 @@
void clear() {
mSealed = false;
mBooleanProperties = 0;
- mCurrentItemIndex = INVALID_POSITION;
- mItemCount = 0;
- mFromIndex = 0;
- mToIndex = 0;
- mScrollX = 0;
- mScrollY = 0;
- mAddedCount = 0;
- mRemovedCount = 0;
+ mCurrentItemIndex = UNDEFINED;
+ mItemCount = UNDEFINED;
+ mFromIndex = UNDEFINED;
+ mToIndex = UNDEFINED;
+ mScrollX = UNDEFINED;
+ mScrollY = UNDEFINED;
+ mAddedCount = UNDEFINED;
+ mRemovedCount = UNDEFINED;
mClassName = null;
mContentDescription = null;
mBeforeText = null;
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 1eb60fc..4e69692 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -26,4 +26,5 @@
void setEnabled(boolean enabled);
+ void setTouchExplorationEnabled(boolean enabled);
}
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 0294e3f..88583df 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -120,6 +120,7 @@
private static final int AUTO_LOGIN = 140;
private static final int CLIENT_CERT_REQUEST = 141;
private static final int SEARCHBOX_IS_SUPPORTED_CALLBACK = 142;
+ private static final int SEARCHBOX_DISPATCH_COMPLETE_CALLBACK= 143;
// Message triggered by the client to resume execution
private static final int NOTIFY = 200;
@@ -821,6 +822,13 @@
searchBox.handleIsSupportedCallback(supported);
break;
}
+ case SEARCHBOX_DISPATCH_COMPLETE_CALLBACK: {
+ SearchBoxImpl searchBox = (SearchBoxImpl) mWebView.getSearchBox();
+ Boolean success = (Boolean) msg.obj;
+ searchBox.handleDispatchCompleteCallback(msg.getData().getString("function"),
+ msg.getData().getInt("id"), success);
+ break;
+ }
}
}
@@ -1641,4 +1649,13 @@
msg.obj = new Boolean(isSupported);
sendMessage(msg);
}
+
+ void onSearchboxDispatchCompleteCallback(String function, int id, boolean success) {
+ Message msg = obtainMessage(SEARCHBOX_DISPATCH_COMPLETE_CALLBACK);
+ msg.obj = Boolean.valueOf(success);
+ msg.getData().putString("function", function);
+ msg.getData().putInt("id", id);
+
+ sendMessage(msg);
+ }
}
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index f9d0067d..a1c6a53 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -75,7 +75,18 @@
com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE
com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE
com.android.internal.R.string.autofill_phone_suffix_separator_re, // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
- com.android.internal.R.string.credit_card_number_preview_format // IDS_CREDIT_CARD_NUMBER_PREVIEW_FORMAT
+ com.android.internal.R.string.autofill_province, // IDS_AUTOFILL_DIALOG_PROVINCE
+ com.android.internal.R.string.autofill_postal_code, // IDS_AUTOFILL_DIALOG_POSTAL_CODE
+ com.android.internal.R.string.autofill_state, // IDS_AUTOFILL_DIALOG_STATE
+ com.android.internal.R.string.autofill_zip_code, // IDS_AUTOFILL_DIALOG_ZIP_CODE
+ com.android.internal.R.string.autofill_county, // IDS_AUTOFILL_DIALOG_COUNTY
+ com.android.internal.R.string.autofill_island, // IDS_AUTOFILL_DIALOG_ISLAND
+ com.android.internal.R.string.autofill_district, // IDS_AUTOFILL_DIALOG_DISTRICT
+ com.android.internal.R.string.autofill_department, // IDS_AUTOFILL_DIALOG_DEPARTMENT
+ com.android.internal.R.string.autofill_prefecture, // IDS_AUTOFILL_DIALOG_PREFECTURE
+ com.android.internal.R.string.autofill_parish, // IDS_AUTOFILL_DIALOG_PARISH
+ com.android.internal.R.string.autofill_area, // IDS_AUTOFILL_DIALOG_AREA
+ com.android.internal.R.string.autofill_emirate // IDS_AUTOFILL_DIALOG_EMIRATE
};
private static Context mApplicationContext;
diff --git a/core/java/android/webkit/SearchBox.java b/core/java/android/webkit/SearchBox.java
index 5075302..6512c4b 100644
--- a/core/java/android/webkit/SearchBox.java
+++ b/core/java/android/webkit/SearchBox.java
@@ -68,11 +68,15 @@
* Notify the search page of any changes to the searchbox. Such as
* a change in the typed query (onchange), the user commiting a given query
* (onsubmit), or a change in size of a suggestions dropdown (onresize).
+ *
+ * @param listener an optional listener to notify of the success of the operation,
+ * indicating if the javascript function existed and could be called or not.
+ * It will be called on the UI thread.
*/
- void onchange();
- void onsubmit();
- void onresize();
- void oncancel();
+ void onchange(SearchBoxListener listener);
+ void onsubmit(SearchBoxListener listener);
+ void onresize(SearchBoxListener listener);
+ void oncancel(SearchBoxListener listener);
/**
* Add and remove listeners to the given Searchbox. Listeners are notified
@@ -91,8 +95,12 @@
* Listeners (if any) will be called on the thread that created the
* webview.
*/
- interface SearchBoxListener {
- void onSuggestionsReceived(String query, List<String> suggestions);
+ public abstract class SearchBoxListener {
+ public void onSuggestionsReceived(String query, List<String> suggestions) {}
+ public void onChangeComplete(boolean called) {}
+ public void onSubmitComplete(boolean called) {}
+ public void onResizeComplete(boolean called) {}
+ public void onCancelComplete(boolean called) {}
}
interface IsSupportedCallback {
diff --git a/core/java/android/webkit/SearchBoxImpl.java b/core/java/android/webkit/SearchBoxImpl.java
index 61fb2ce..9942d25 100644
--- a/core/java/android/webkit/SearchBoxImpl.java
+++ b/core/java/android/webkit/SearchBoxImpl.java
@@ -16,10 +16,12 @@
package android.webkit;
+import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewCore.EventHub;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
@@ -69,7 +71,7 @@
private static final String SET_VERBATIM_SCRIPT
= "if (window.chrome && window.chrome.searchBox) {"
- + " window.chrome.searchBox.verbatim = %s;"
+ + " window.chrome.searchBox.verbatim = %1$s;"
+ "}";
private static final String SET_SELECTION_SCRIPT
@@ -89,13 +91,21 @@
+ "}";
private static final String DISPATCH_EVENT_SCRIPT
- = "if (window.chrome && window.chrome.searchBox &&"
- + " window.chrome.searchBox.on%1$s) { window.chrome.searchBox.on%1$s(); }";
+ = "if (window.chrome && window.chrome.searchBox && window.chrome.searchBox.on%1$s) {"
+ + " window.chrome.searchBox.on%1$s();"
+ + " window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, true);"
+ + "} else {"
+ + " window.searchBoxJavaBridge_.dispatchCompleteCallback('%1$s', %2$d, false);"
+ + "}";
+
+ private static final String EVENT_CHANGE = "change";
+ private static final String EVENT_SUBMIT = "submit";
+ private static final String EVENT_RESIZE = "resize";
+ private static final String EVENT_CANCEL = "cancel";
private static final String IS_SUPPORTED_SCRIPT
= "if (window.searchBoxJavaBridge_) {"
- + " if (window.chrome && window.chrome.searchBox && "
- + " window.chrome.searchBox.onsubmit) {"
+ + " if (window.chrome && window.chrome.sv) {"
+ " window.searchBoxJavaBridge_.isSupportedCallback(true);"
+ " } else {"
+ " window.searchBoxJavaBridge_.isSupportedCallback(false);"
@@ -105,11 +115,14 @@
private final WebViewCore mWebViewCore;
private final CallbackProxy mCallbackProxy;
private IsSupportedCallback mSupportedCallback;
+ private int mNextEventId = 1;
+ private final HashMap<Integer, SearchBoxListener> mEventCallbacks;
SearchBoxImpl(WebViewCore webViewCore, CallbackProxy callbackProxy) {
mListeners = new ArrayList<SearchBoxListener>();
mWebViewCore = webViewCore;
mCallbackProxy = callbackProxy;
+ mEventCallbacks = new HashMap<Integer, SearchBoxListener>();
}
@Override
@@ -141,27 +154,36 @@
}
@Override
- public void onchange() {
- dispatchEvent("change");
+ public void onchange(SearchBoxListener callback) {
+ dispatchEvent(EVENT_CHANGE, callback);
}
@Override
- public void onsubmit() {
- dispatchEvent("submit");
+ public void onsubmit(SearchBoxListener callback) {
+ dispatchEvent(EVENT_SUBMIT, callback);
}
@Override
- public void onresize() {
- dispatchEvent("resize");
+ public void onresize(SearchBoxListener callback) {
+ dispatchEvent(EVENT_RESIZE, callback);
}
@Override
- public void oncancel() {
- dispatchEvent("cancel");
+ public void oncancel(SearchBoxListener callback) {
+ dispatchEvent(EVENT_CANCEL, callback);
}
- private void dispatchEvent(String eventName) {
- final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName);
+ private void dispatchEvent(String eventName, SearchBoxListener callback) {
+ int eventId;
+ if (callback != null) {
+ synchronized(this) {
+ eventId = mNextEventId++;
+ mEventCallbacks.put(eventId, callback);
+ }
+ } else {
+ eventId = 0;
+ }
+ final String js = String.format(DISPATCH_EVENT_SCRIPT, eventName, eventId);
dispatchJs(js);
}
@@ -202,9 +224,35 @@
}
}
+ // Called by Javascript through the Java bridge.
+ public void dispatchCompleteCallback(String function, int id, boolean successful) {
+ mCallbackProxy.onSearchboxDispatchCompleteCallback(function, id, successful);
+ }
+
+ public void handleDispatchCompleteCallback(String function, int id, boolean successful) {
+ if (id != 0) {
+ SearchBoxListener listener;
+ synchronized(this) {
+ listener = mEventCallbacks.get(id);
+ mEventCallbacks.remove(id);
+ }
+ if (listener != null) {
+ if (TextUtils.equals(EVENT_CHANGE, function)) {
+ listener.onChangeComplete(successful);
+ } else if (TextUtils.equals(EVENT_SUBMIT, function)) {
+ listener.onSubmitComplete(successful);
+ } else if (TextUtils.equals(EVENT_RESIZE, function)) {
+ listener.onResizeComplete(successful);
+ } else if (TextUtils.equals(EVENT_CANCEL, function)) {
+ listener.onCancelComplete(successful);
+ }
+ }
+ }
+ }
+
// This is used as a hackish alternative to javascript escaping.
// There appears to be no such functionality in the core framework.
- private String jsonSerialize(String query) {
+ private static String jsonSerialize(String query) {
JSONStringer stringer = new JSONStringer();
try {
stringer.array().value(query).endArray();
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 761007f..d584acd 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1783,6 +1783,20 @@
}
/**
+ * @hide
+ */
+ public void setProperty(String key, String value) {
+ mWebView.nativeSetProperty(key, value);
+ }
+
+ /**
+ * @hide
+ */
+ public String getProperty(String key) {
+ return mWebView.nativeGetProperty(key);
+ }
+
+ /**
* Transfer messages from the queue to the new WebCoreThread. Called from
* WebCore thread.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7ba86a5..b22c57b0 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -9089,6 +9089,52 @@
}
}
+ /**
+ * Begin collecting per-tile profiling data
+ *
+ * @hide only used by profiling tests
+ */
+ public void tileProfilingStart() {
+ nativeTileProfilingStart();
+ }
+ /**
+ * Return per-tile profiling data
+ *
+ * @hide only used by profiling tests
+ */
+ public float tileProfilingStop() {
+ return nativeTileProfilingStop();
+ }
+
+ /** @hide only used by profiling tests */
+ public void tileProfilingClear() {
+ nativeTileProfilingClear();
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingNumFrames() {
+ return nativeTileProfilingNumFrames();
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingNumTilesInFrame(int frame) {
+ return nativeTileProfilingNumTilesInFrame(frame);
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingGetX(int frame, int tile) {
+ return nativeTileProfilingGetX(frame, tile);
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingGetY(int frame, int tile) {
+ return nativeTileProfilingGetY(frame, tile);
+ }
+ /** @hide only used by profiling tests */
+ public boolean tileProfilingGetReady(int frame, int tile) {
+ return nativeTileProfilingGetReady(frame, tile);
+ }
+ /** @hide only used by profiling tests */
+ public int tileProfilingGetLevel(int frame, int tile) {
+ return nativeTileProfilingGetLevel(frame, tile);
+ }
+
private native int nativeCacheHitFramePointer();
private native boolean nativeCacheHitIsPlugin();
private native Rect nativeCacheHitNodeBounds();
@@ -9211,6 +9257,15 @@
private native void nativeStopGL();
private native Rect nativeSubtractLayers(Rect content);
private native int nativeTextGeneration();
+ private native void nativeTileProfilingStart();
+ private native float nativeTileProfilingStop();
+ private native void nativeTileProfilingClear();
+ private native int nativeTileProfilingNumFrames();
+ private native int nativeTileProfilingNumTilesInFrame(int frame);
+ private native int nativeTileProfilingGetX(int frame, int tile);
+ private native int nativeTileProfilingGetY(int frame, int tile);
+ private native boolean nativeTileProfilingGetReady(int frame, int tile);
+ private native int nativeTileProfilingGetLevel(int frame, int tile);
// Never call this version except by updateCachedTextfield(String) -
// we always want to pass in our generation number.
private native void nativeUpdateCachedTextfield(String updatedText,
@@ -9234,4 +9289,6 @@
*/
private native boolean nativeScrollLayer(int layer, int newX, int newY);
private native int nativeGetBackgroundColor();
+ native void nativeSetProperty(String key, String value);
+ native String nativeGetProperty(String key);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c652e55..5414b79 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -248,7 +248,7 @@
/* Get the BrowserFrame component. This is used for subwindow creation and
* is called only from BrowserFrame in the WebCore thread. */
- /* package */ BrowserFrame getBrowserFrame() {
+ /* package */ synchronized BrowserFrame getBrowserFrame() {
return mBrowserFrame;
}
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 7d3f313..49ea944 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -344,6 +344,8 @@
public final void setInitialScaleInPercent(int scaleInPercent) {
mInitialScale = scaleInPercent * 0.01f;
+ mActualScale = mInitialScale > 0 ? mInitialScale : mDefaultScale;
+ mInvActualScale = 1 / mActualScale;
}
public final float computeScaleWithLimits(float scale) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 1449b18..8f8c1d0 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -271,12 +271,6 @@
Drawable mSelector;
/**
- * Set to true if we would like to have the selector showing itself.
- * We still need to draw and position it even if this is false.
- */
- boolean mSelectorShowing;
-
- /**
* The current position of the selector in the list.
*/
int mSelectorPosition = INVALID_POSITION;
@@ -1669,7 +1663,6 @@
setSelectedPositionInt(INVALID_POSITION);
setNextSelectedPositionInt(INVALID_POSITION);
mSelectedTop = 0;
- mSelectorShowing = false;
mSelectorPosition = INVALID_POSITION;
mSelectorRect.setEmpty();
invalidate();
@@ -2025,7 +2018,7 @@
final boolean isChildViewEnabled = mIsChildViewEnabled;
if (sel.isEnabled() != isChildViewEnabled) {
mIsChildViewEnabled = !isChildViewEnabled;
- if (mSelectorShowing) {
+ if (getSelectedItemPosition() != INVALID_POSITION) {
refreshDrawableState();
}
}
@@ -2769,6 +2762,7 @@
// touch mode). Force an initial layout to get rid of the selection.
layoutChildren();
}
+ updateSelectorState();
} else {
int touchMode = mTouchMode;
if (touchMode == TOUCH_MODE_OVERSCROLL || touchMode == TOUCH_MODE_OVERFLING) {
@@ -2847,14 +2841,6 @@
}
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
} else {
- if (ev.getEdgeFlags() != 0 && motionPosition < 0) {
- // If we couldn't find a view to click on, but the down event
- // was touching the edge, we will bail out and try again.
- // This allows the edge correcting code in ViewAncestor to try to
- // find a nearby view to select
- return false;
- }
-
if (mTouchMode == TOUCH_MODE_FLING) {
// Stopped a fling. It is a scroll.
createScrollingCache();
@@ -2888,7 +2874,11 @@
}
case MotionEvent.ACTION_MOVE: {
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == -1) {
+ pointerIndex = 0;
+ mActivePointerId = ev.getPointerId(pointerIndex);
+ }
final int y = (int) ev.getY(pointerIndex);
deltaY = y - mMotionY;
switch (mTouchMode) {
@@ -3464,7 +3454,11 @@
case MotionEvent.ACTION_MOVE: {
switch (mTouchMode) {
case TOUCH_MODE_DOWN:
- final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ if (pointerIndex == -1) {
+ pointerIndex = 0;
+ mActivePointerId = ev.getPointerId(pointerIndex);
+ }
final int y = (int) ev.getY(pointerIndex);
if (startScrollIfNeeded(y - mMotionY)) {
return true;
@@ -4521,7 +4515,6 @@
setSelectedPositionInt(INVALID_POSITION);
setNextSelectedPositionInt(INVALID_POSITION);
mSelectedTop = 0;
- mSelectorShowing = false;
}
}
@@ -4645,6 +4638,9 @@
childrenTop += getVerticalFadingEdgeLength();
}
}
+ // Don't ever focus a disabled item.
+ if (!mAdapter.isEnabled(i)) continue;
+
if (top >= childrenTop) {
// Found a view whose top is fully visisble
selectedPos = firstPosition + i;
diff --git a/core/java/android/widget/ActivityChooserModel.java b/core/java/android/widget/ActivityChooserModel.java
index 83f80ff..d7429b3 100644
--- a/core/java/android/widget/ActivityChooserModel.java
+++ b/core/java/android/widget/ActivityChooserModel.java
@@ -126,7 +126,7 @@
*/
// This cannot be done by a simple comparator since an Activity weight
// is computed from history. Note that Activity implements Comparable.
- public void sort(Intent intent, List<Activity> activities,
+ public void sort(Intent intent, List<ActivityResolveInfo> activities,
List<HistoricalRecord> historicalRecords);
}
@@ -215,7 +215,7 @@
/**
* List of activities that can handle the current intent.
*/
- private final List<Activity> mActivitys = new ArrayList<Activity>();
+ private final List<ActivityResolveInfo> mActivites = new ArrayList<ActivityResolveInfo>();
/**
* List with historical choice records.
@@ -311,9 +311,6 @@
* @return The model.
*/
public static ActivityChooserModel get(Context context, String historyFileName) {
- if (historyFileName == null) {
- return new ActivityChooserModel(context, historyFileName);
- }
synchronized (sRegistryLock) {
ActivityChooserModel dataModel = sDataModelRegistry.get(historyFileName);
if (dataModel == null) {
@@ -380,7 +377,7 @@
*/
public int getActivityCount() {
synchronized (mInstanceLock) {
- return mActivitys.size();
+ return mActivites.size();
}
}
@@ -389,12 +386,12 @@
*
* @return The activity.
*
- * @see Activity
+ * @see ActivityResolveInfo
* @see #setIntent(Intent)
*/
public ResolveInfo getActivity(int index) {
synchronized (mInstanceLock) {
- return mActivitys.get(index).resolveInfo;
+ return mActivites.get(index).resolveInfo;
}
}
@@ -406,10 +403,10 @@
* @return The index if found, -1 otherwise.
*/
public int getActivityIndex(ResolveInfo activity) {
- List<Activity> activities = mActivitys;
+ List<ActivityResolveInfo> activities = mActivites;
final int activityCount = activities.size();
for (int i = 0; i < activityCount; i++) {
- Activity currentActivity = activities.get(i);
+ ActivityResolveInfo currentActivity = activities.get(i);
if (currentActivity.resolveInfo == activity) {
return i;
}
@@ -433,8 +430,7 @@
* @see HistoricalRecord
*/
public Intent chooseActivity(int index) {
- Activity chosenActivity = mActivitys.get(index);
- Activity defaultActivity = mActivitys.get(0);
+ ActivityResolveInfo chosenActivity = mActivites.get(index);
ComponentName chosenName = new ComponentName(
chosenActivity.resolveInfo.activityInfo.packageName,
@@ -460,8 +456,8 @@
*/
public ResolveInfo getDefaultActivity() {
synchronized (mInstanceLock) {
- if (!mActivitys.isEmpty()) {
- return mActivitys.get(0).resolveInfo;
+ if (!mActivites.isEmpty()) {
+ return mActivites.get(0).resolveInfo;
}
}
return null;
@@ -478,8 +474,8 @@
* @param index The index of the activity to set as default.
*/
public void setDefaultActivity(int index) {
- Activity newDefaultActivity = mActivitys.get(index);
- Activity oldDefaultActivity = mActivitys.get(0);
+ ActivityResolveInfo newDefaultActivity = mActivites.get(index);
+ ActivityResolveInfo oldDefaultActivity = mActivites.get(0);
final float weight;
if (oldDefaultActivity != null) {
@@ -572,8 +568,8 @@
*/
private void sortActivities() {
synchronized (mInstanceLock) {
- if (mActivitySorter != null && !mActivitys.isEmpty()) {
- mActivitySorter.sort(mIntent, mActivitys,
+ if (mActivitySorter != null && !mActivites.isEmpty()) {
+ mActivitySorter.sort(mIntent, mActivites,
Collections.unmodifiableList(mHistoricalRecords));
notifyChanged();
}
@@ -661,14 +657,14 @@
* Loads the activities.
*/
private void loadActivitiesLocked() {
- mActivitys.clear();
+ mActivites.clear();
if (mIntent != null) {
List<ResolveInfo> resolveInfos =
mContext.getPackageManager().queryIntentActivities(mIntent, 0);
final int resolveInfoCount = resolveInfos.size();
for (int i = 0; i < resolveInfoCount; i++) {
ResolveInfo resolveInfo = resolveInfos.get(i);
- mActivitys.add(new Activity(resolveInfo));
+ mActivites.add(new ActivityResolveInfo(resolveInfo));
}
sortActivities();
} else {
@@ -797,7 +793,7 @@
/**
* Represents an activity.
*/
- public final class Activity implements Comparable<Activity> {
+ public final class ActivityResolveInfo implements Comparable<ActivityResolveInfo> {
/**
* The {@link ResolveInfo} of the activity.
@@ -814,7 +810,7 @@
*
* @param resolveInfo activity {@link ResolveInfo}.
*/
- public Activity(ResolveInfo resolveInfo) {
+ public ActivityResolveInfo(ResolveInfo resolveInfo) {
this.resolveInfo = resolveInfo;
}
@@ -834,14 +830,14 @@
if (getClass() != obj.getClass()) {
return false;
}
- Activity other = (Activity) obj;
+ ActivityResolveInfo other = (ActivityResolveInfo) obj;
if (Float.floatToIntBits(weight) != Float.floatToIntBits(other.weight)) {
return false;
}
return true;
}
- public int compareTo(Activity another) {
+ public int compareTo(ActivityResolveInfo another) {
return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
}
@@ -862,18 +858,18 @@
private final class DefaultSorter implements ActivitySorter {
private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f;
- private final Map<String, Activity> mPackageNameToActivityMap =
- new HashMap<String, Activity>();
+ private final Map<String, ActivityResolveInfo> mPackageNameToActivityMap =
+ new HashMap<String, ActivityResolveInfo>();
- public void sort(Intent intent, List<Activity> activities,
+ public void sort(Intent intent, List<ActivityResolveInfo> activities,
List<HistoricalRecord> historicalRecords) {
- Map<String, Activity> packageNameToActivityMap =
+ Map<String, ActivityResolveInfo> packageNameToActivityMap =
mPackageNameToActivityMap;
packageNameToActivityMap.clear();
final int activityCount = activities.size();
for (int i = 0; i < activityCount; i++) {
- Activity activity = activities.get(i);
+ ActivityResolveInfo activity = activities.get(i);
activity.weight = 0.0f;
String packageName = activity.resolveInfo.activityInfo.packageName;
packageNameToActivityMap.put(packageName, activity);
@@ -884,9 +880,11 @@
for (int i = lastShareIndex; i >= 0; i--) {
HistoricalRecord historicalRecord = historicalRecords.get(i);
String packageName = historicalRecord.activity.getPackageName();
- Activity activity = packageNameToActivityMap.get(packageName);
- activity.weight += historicalRecord.weight * nextRecordWeight;
- nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT;
+ ActivityResolveInfo activity = packageNameToActivityMap.get(packageName);
+ if (activity != null) {
+ activity.weight += historicalRecord.weight * nextRecordWeight;
+ nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT;
+ }
}
Collections.sort(activities);
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 2fe8162..5b69aa8 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -16,23 +16,29 @@
package android.widget;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.os.Debug;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ActivityChooserModel;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListPopupWindow;
+import android.widget.PopupWindow;
+import android.widget.TextView;
import com.android.internal.R;
@@ -56,11 +62,6 @@
* </li>
* </ul>
* </p>
- * </p>
- * This view is backed by a {@link ActivityChooserModel}. Calling {@link #showPopup()}
- * while this view is attached to the view hierarchy will show a popup with
- * activities while if the view is not attached it will show a dialog.
- * </p>
*
* @hide
*/
@@ -92,29 +93,26 @@
private final ImageButton mDefaultActionButton;
/**
- * The header for handlers list.
+ * The maximal width of the list popup.
*/
- private final View mListHeaderView;
+ private final int mListPopupMaxWidth;
/**
- * The footer for handlers list.
+ * Observer for the model data.
*/
- private final View mListFooterView;
+ private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
- /**
- * The title of the header view.
- */
- private TextView mListHeaderViewTitle;
-
- /**
- * The title for expanding the activities list.
- */
- private final String mListHeaderViewTitleSelectDefault;
-
- /**
- * The title if no activity exist.
- */
- private final String mListHeaderViewTitleNoActivities;
+ @Override
+ public void onChanged() {
+ super.onChanged();
+ mAdapter.notifyDataSetChanged();
+ }
+ @Override
+ public void onInvalidated() {
+ super.onInvalidated();
+ mAdapter.notifyDataSetInvalidated();
+ }
+ };
/**
* Popup window for showing the activity overflow list.
@@ -122,11 +120,6 @@
private ListPopupWindow mListPopupWindow;
/**
- * Alert dialog for showing the activity overflow list.
- */
- private AlertDialog mAlertDialog;
-
- /**
* Listener for the dismissal of the popup/alert.
*/
private PopupWindow.OnDismissListener mOnDismissListener;
@@ -147,16 +140,6 @@
private boolean mIsAttachedToWindow;
/**
- * Flag whether this view is showing an alert dialog.
- */
- private boolean mIsShowingAlertDialog;
-
- /**
- * Flag whether this view is showing a popup window.
- */
- private boolean mIsShowingPopuWindow;
-
- /**
* Create a new instance.
*
* @param context The application environment.
@@ -195,8 +178,7 @@
Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
R.styleable.ActivityChooserView_expandActivityOverflowButtonDrawable);
- LayoutInflater inflater = (LayoutInflater) context.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
+ LayoutInflater inflater = LayoutInflater.from(mContext);
inflater.inflate(R.layout.activity_chooser_view, this, true);
mCallbacks = new Callbacks();
@@ -209,16 +191,7 @@
mExpandActivityOverflowButton = (ImageButton) findViewById(R.id.expand_activities_button);
mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
- mExpandActivityOverflowButton.setBackgroundDrawable(expandActivityOverflowButtonDrawable);
-
- mListHeaderView = inflater.inflate(R.layout.activity_chooser_list_header, null);
- mListFooterView = inflater.inflate(R.layout.activity_chooser_list_footer, null);
-
- mListHeaderViewTitle = (TextView) mListHeaderView.findViewById(R.id.title);
- mListHeaderViewTitleSelectDefault = context.getString(
- R.string.activity_chooser_view_select_default);
- mListHeaderViewTitleNoActivities = context.getString(
- R.string.activity_chooser_view_no_activities);
+ mExpandActivityOverflowButton.setImageDrawable(expandActivityOverflowButtonDrawable);
mAdapter = new ActivityChooserViewAdapter();
mAdapter.registerDataSetObserver(new DataSetObserver() {
@@ -228,6 +201,10 @@
updateButtons();
}
});
+
+ Resources resources = context.getResources();
+ mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
+ resources.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
}
/**
@@ -253,7 +230,7 @@
* @param drawable The drawable.
*/
public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
- mExpandActivityOverflowButton.setBackgroundDrawable(drawable);
+ mExpandActivityOverflowButton.setImageDrawable(drawable);
}
/**
@@ -262,7 +239,7 @@
* @return True if the popup was shown, false if already showing.
*/
public boolean showPopup() {
- if (isShowingPopup()) {
+ if (isShowingPopup() || !mIsAttachedToWindow) {
return false;
}
mIsSelectingDefaultActivity = false;
@@ -276,38 +253,30 @@
* @param maxActivityCount The max number of activities to display.
*/
private void showPopupUnchecked(int maxActivityCount) {
+ if (mAdapter.getDataModel() == null) {
+ throw new IllegalStateException("No data model. Did you call #setDataModel?");
+ }
+
mAdapter.setMaxActivityCount(maxActivityCount);
- if (mIsSelectingDefaultActivity) {
- if (mAdapter.getActivityCount() > 0) {
- mListHeaderViewTitle.setText(mListHeaderViewTitleSelectDefault);
+
+ final int activityCount = mAdapter.getActivityCount();
+ if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED
+ && activityCount > maxActivityCount + 1) {
+ mAdapter.setShowFooterView(true);
+ } else {
+ mAdapter.setShowFooterView(false);
+ }
+
+ ListPopupWindow popupWindow = getListPopupWindow();
+ if (!popupWindow.isShowing()) {
+ if (mIsSelectingDefaultActivity) {
+ mAdapter.setShowDefaultActivity(true);
} else {
- mListHeaderViewTitle.setText(mListHeaderViewTitleNoActivities);
+ mAdapter.setShowDefaultActivity(false);
}
- mAdapter.setHeaderView(mListHeaderView);
- } else {
- mAdapter.setHeaderView(null);
- }
-
- if (mAdapter.getActivityCount() > maxActivityCount + 1) {
- mAdapter.setFooterView(mListFooterView);
- } else {
- mAdapter.setFooterView(null);
- }
-
- if (!mIsAttachedToWindow || mIsShowingAlertDialog) {
- AlertDialog alertDialog = getAlertDilalog();
- if (!alertDialog.isShowing()) {
- alertDialog.setCustomTitle(this);
- alertDialog.show();
- mIsShowingAlertDialog = true;
- }
- } else {
- ListPopupWindow popupWindow = getListPopupWindow();
- if (!popupWindow.isShowing()) {
- popupWindow.setContentWidth(mAdapter.measureContentWidth());
- popupWindow.show();
- mIsShowingPopuWindow = true;
- }
+ final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
+ popupWindow.setContentWidth(contentWidth);
+ popupWindow.show();
}
}
@@ -317,12 +286,7 @@
* @return True if dismissed, false if already dismissed.
*/
public boolean dismissPopup() {
- if (!isShowingPopup()) {
- return false;
- }
- if (mIsShowingAlertDialog) {
- getAlertDilalog().dismiss();
- } else if (mIsShowingPopuWindow) {
+ if (isShowingPopup()) {
getListPopupWindow().dismiss();
}
return true;
@@ -334,12 +298,7 @@
* @return True if the popup is shown.
*/
public boolean isShowingPopup() {
- if (mIsShowingAlertDialog) {
- return getAlertDilalog().isShowing();
- } else if (mIsShowingPopuWindow) {
- return getListPopupWindow().isShowing();
- }
- return false;
+ return getListPopupWindow().isShowing();
}
@Override
@@ -347,6 +306,7 @@
super.onAttachedToWindow();
ActivityChooserModel dataModel = mAdapter.getDataModel();
if (dataModel != null) {
+ dataModel.registerObserver(mModelDataSetOberver);
dataModel.readHistoricalData();
}
mIsAttachedToWindow = true;
@@ -357,6 +317,7 @@
super.onDetachedFromWindow();
ActivityChooserModel dataModel = mAdapter.getDataModel();
if (dataModel != null) {
+ dataModel.unregisterObserver(mModelDataSetOberver);
dataModel.persistHistoricalData();
}
mIsAttachedToWindow = false;
@@ -371,13 +332,11 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- mActivityChooserContent.layout(left, top, right, bottom);
- if (mIsShowingPopuWindow) {
- if (isShown()) {
- showPopupUnchecked(mAdapter.getMaxActivityCount());
- } else {
- dismissPopup();
- }
+ mActivityChooserContent.layout(0, 0, right - left, bottom - top);
+ if (getListPopupWindow().isShowing()) {
+ showPopupUnchecked(mAdapter.getMaxActivityCount());
+ } else {
+ dismissPopup();
}
}
@@ -429,22 +388,6 @@
}
/**
- * Gets the alert dialog which is lazily initialized.
- *
- * @return The popup.
- */
- private AlertDialog getAlertDilalog() {
- if (mAlertDialog == null) {
- Builder builder = new Builder(getContext());
- builder.setAdapter(mAdapter, null);
- mAlertDialog = builder.create();
- mAlertDialog.getListView().setOnItemClickListener(mCallbacks);
- mAlertDialog.setOnDismissListener(mCallbacks);
- }
- return mAlertDialog;
- }
-
- /**
* Updates the buttons state.
*/
private void updateButtons() {
@@ -458,7 +401,7 @@
}
ResolveInfo activity = mAdapter.getDefaultActivity();
PackageManager packageManager = mContext.getPackageManager();
- mDefaultActionButton.setBackgroundDrawable(activity.loadIcon(packageManager));
+ mDefaultActionButton.setImageDrawable(activity.loadIcon(packageManager));
} else {
mDefaultActionButton.setVisibility(View.INVISIBLE);
mExpandActivityOverflowButton.setEnabled(false);
@@ -469,24 +412,23 @@
* Interface implementation to avoid publishing them in the APIs.
*/
private class Callbacks implements AdapterView.OnItemClickListener,
- View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener,
- DialogInterface.OnDismissListener {
+ View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener {
// AdapterView#OnItemClickListener
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter();
final int itemViewType = adapter.getItemViewType(position);
switch (itemViewType) {
- case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_HEADER: {
- /* do nothing */
- } break;
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: {
showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED);
} break;
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: {
dismissPopup();
if (mIsSelectingDefaultActivity) {
- mAdapter.getDataModel().setDefaultActivity(position);
+ // The item at position zero is the default already.
+ if (position > 0) {
+ mAdapter.getDataModel().setDefaultActivity(position);
+ }
} else {
// The first item in the model is default action => adjust index
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position + 1);
@@ -530,16 +472,6 @@
// PopUpWindow.OnDismissListener#onDismiss
public void onDismiss() {
- mIsShowingPopuWindow = false;
- notifyOnDismissListener();
- }
-
- // DialogInterface.OnDismissListener#onDismiss
- @Override
- public void onDismiss(DialogInterface dialog) {
- mIsShowingAlertDialog = false;
- AlertDialog alertDialog = (AlertDialog) dialog;
- alertDialog.setCustomTitle(null);
notifyOnDismissListener();
}
@@ -559,59 +491,35 @@
public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4;
- private static final int ITEM_VIEW_TYPE_HEADER = 0;
+ private static final int ITEM_VIEW_TYPE_ACTIVITY = 0;
- private static final int ITEM_VIEW_TYPE_ACTIVITY = 1;
-
- private static final int ITEM_VIEW_TYPE_FOOTER = 2;
+ private static final int ITEM_VIEW_TYPE_FOOTER = 1;
private static final int ITEM_VIEW_TYPE_COUNT = 3;
- private final DataSetObserver mDataSetOberver = new DataSetObserver() {
-
- @Override
- public void onChanged() {
- super.onChanged();
- notifyDataSetChanged();
- }
- @Override
- public void onInvalidated() {
- super.onInvalidated();
- notifyDataSetInvalidated();
- }
- };
-
private ActivityChooserModel mDataModel;
private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT;
- private ResolveInfo mDefaultActivity;
+ private boolean mShowDefaultActivity;
- private View mHeaderView;
-
- private View mFooterView;
+ private boolean mShowFooterView;
public void setDataModel(ActivityChooserModel dataModel) {
+ ActivityChooserModel oldDataModel = mAdapter.getDataModel();
+ if (oldDataModel != null && isShown()) {
+ oldDataModel.unregisterObserver(mModelDataSetOberver);
+ }
mDataModel = dataModel;
- mDataModel.registerObserver(mDataSetOberver);
+ if (dataModel != null && isShown()) {
+ dataModel.registerObserver(mModelDataSetOberver);
+ }
notifyDataSetChanged();
}
@Override
- public void notifyDataSetChanged() {
- if (mDataModel.getActivityCount() > 0) {
- mDefaultActivity = mDataModel.getDefaultActivity();
- } else {
- mDefaultActivity = null;
- }
- super.notifyDataSetChanged();
- }
-
- @Override
public int getItemViewType(int position) {
- if (mHeaderView != null && position == 0) {
- return ITEM_VIEW_TYPE_HEADER;
- } else if (mFooterView != null && position == getCount() - 1) {
+ if (mShowFooterView && position == getCount() - 1) {
return ITEM_VIEW_TYPE_FOOTER;
} else {
return ITEM_VIEW_TYPE_ACTIVITY;
@@ -626,14 +534,11 @@
public int getCount() {
int count = 0;
int activityCount = mDataModel.getActivityCount();
- if (activityCount > 0) {
+ if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
activityCount--;
}
count = Math.min(activityCount, mMaxActivityCount);
- if (mHeaderView != null) {
- count++;
- }
- if (mFooterView != null) {
+ if (mShowFooterView) {
count++;
}
return count;
@@ -642,16 +547,13 @@
public Object getItem(int position) {
final int itemViewType = getItemViewType(position);
switch (itemViewType) {
- case ITEM_VIEW_TYPE_HEADER:
- return mHeaderView;
case ITEM_VIEW_TYPE_FOOTER:
- return mFooterView;
+ return null;
case ITEM_VIEW_TYPE_ACTIVITY:
- int targetIndex = (mHeaderView == null) ? position : position - 1;
- if (mDefaultActivity != null) {
- targetIndex++;
+ if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
+ position++;
}
- return mDataModel.getActivity(targetIndex);
+ return mDataModel.getActivity(position);
default:
throw new IllegalArgumentException();
}
@@ -661,27 +563,19 @@
return position;
}
- @Override
- public boolean isEnabled(int position) {
- final int itemViewType = getItemViewType(position);
- switch (itemViewType) {
- case ITEM_VIEW_TYPE_HEADER:
- return false;
- case ITEM_VIEW_TYPE_FOOTER:
- case ITEM_VIEW_TYPE_ACTIVITY:
- return true;
- default:
- throw new IllegalArgumentException();
- }
- }
-
public View getView(int position, View convertView, ViewGroup parent) {
final int itemViewType = getItemViewType(position);
switch (itemViewType) {
- case ITEM_VIEW_TYPE_HEADER:
- return mHeaderView;
case ITEM_VIEW_TYPE_FOOTER:
- return mFooterView;
+ if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) {
+ convertView = LayoutInflater.from(getContext()).inflate(
+ R.layout.activity_chooser_view_list_item, parent, false);
+ convertView.setId(ITEM_VIEW_TYPE_FOOTER);
+ TextView titleView = (TextView) convertView.findViewById(R.id.title);
+ titleView.setText(mContext.getString(
+ R.string.activity_chooser_view_see_all));
+ }
+ return convertView;
case ITEM_VIEW_TYPE_ACTIVITY:
if (convertView == null || convertView.getId() != R.id.list_item) {
convertView = LayoutInflater.from(getContext()).inflate(
@@ -691,10 +585,16 @@
// Set the icon
ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
ResolveInfo activity = (ResolveInfo) getItem(position);
- iconView.setBackgroundDrawable(activity.loadIcon(packageManager));
+ iconView.setImageDrawable(activity.loadIcon(packageManager));
// Set the title.
TextView titleView = (TextView) convertView.findViewById(R.id.title);
titleView.setText(activity.loadLabel(packageManager));
+ // Highlight the default.
+ if (mShowDefaultActivity && position == 0) {
+ convertView.setActivated(true);
+ } else {
+ convertView.setActivated(false);
+ }
return convertView;
default:
throw new IllegalArgumentException();
@@ -702,7 +602,7 @@
}
public int measureContentWidth() {
- // The user may have specified some of the target not to be show but we
+ // The user may have specified some of the target not to be shown but we
// want to measure all of them since after expansion they should fit.
final int oldMaxActivityCount = mMaxActivityCount;
mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED;
@@ -733,19 +633,12 @@
}
public ResolveInfo getDefaultActivity() {
- return mDefaultActivity;
+ return mDataModel.getDefaultActivity();
}
- public void setHeaderView(View headerView) {
- if (mHeaderView != headerView) {
- mHeaderView = headerView;
- notifyDataSetChanged();
- }
- }
-
- public void setFooterView(View footerView) {
- if (mFooterView != footerView) {
- mFooterView = footerView;
+ public void setShowFooterView(boolean showFooterView) {
+ if (mShowFooterView != showFooterView) {
+ mShowFooterView = showFooterView;
notifyDataSetChanged();
}
}
@@ -761,5 +654,12 @@
public ActivityChooserModel getDataModel() {
return mDataModel;
}
+
+ public void setShowDefaultActivity(boolean showDefaultActivity) {
+ if (mShowDefaultActivity != showDefaultActivity) {
+ mShowDefaultActivity = showDefaultActivity;
+ notifyDataSetChanged();
+ }
+ }
}
}
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index f8c76f2..1b713c3 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -21,6 +21,7 @@
import android.annotation.Widget;
import android.app.Service;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Canvas;
@@ -239,21 +240,11 @@
private String[] mDayLabels;
/**
- * Temporary instance to avoid multiple instantiations.
- */
- private Calendar mTempDate = Calendar.getInstance();
-
- /**
* The first day of the week.
*/
private int mFirstDayOfWeek;
/**
- * The first day of the focused month.
- */
- private Calendar mFirstDayOfMonth = Calendar.getInstance();
-
- /**
* Which month should be displayed/highlighted [0-11].
*/
private int mCurrentMonthDisplayed;
@@ -289,14 +280,24 @@
private ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable();
/**
+ * Temporary instance to avoid multiple instantiations.
+ */
+ private Calendar mTempDate;
+
+ /**
+ * The first day of the focused month.
+ */
+ private Calendar mFirstDayOfMonth;
+
+ /**
* The start date of the range supported by this picker.
*/
- private Calendar mMinDate = Calendar.getInstance();
+ private Calendar mMinDate;
/**
* The end date of the range supported by this picker.
*/
- private Calendar mMaxDate = Calendar.getInstance();
+ private Calendar mMaxDate;
/**
* Date format for parsing dates.
@@ -304,6 +305,11 @@
private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
/**
+ * The current locale.
+ */
+ private Locale mCurrentLocale;
+
+ /**
* The callback used to indicate the user changes the date.
*/
public interface OnDateChangeListener {
@@ -330,6 +336,9 @@
public CalendarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, 0);
+ // initialization based on locale
+ setCurrentLocale(Locale.getDefault());
+
TypedValue calendarViewStyle = new TypedValue();
context.getTheme().resolveAttribute(R.attr.calendarViewStyle, calendarViewStyle, true);
TypedArray attributesArray = context.obtainStyledAttributes(calendarViewStyle.resourceId,
@@ -366,6 +375,7 @@
com.android.internal.R.styleable.TextAppearance);
mDateTextSize = dateTextAppearance.getDimensionPixelSize(
R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE);
+ dateTextAppearance.recycle();
int weekDayTextAppearanceResId = attributesArray.getResourceId(
R.styleable.CalendarView_weekDayTextAppearance,
@@ -413,6 +423,12 @@
return mListView.isEnabled();
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ setCurrentLocale(newConfig.locale);
+ }
+
/**
* Gets the minimal date supported by this {@link CalendarView} in milliseconds
* since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time
@@ -624,6 +640,41 @@
}
/**
+ * Sets the current locale.
+ *
+ * @param locale The current locale.
+ */
+ private void setCurrentLocale(Locale locale) {
+ if (locale.equals(mCurrentLocale)) {
+ return;
+ }
+
+ mCurrentLocale = locale;
+
+ mTempDate = getCalendarForLocale(mTempDate, locale);
+ mFirstDayOfMonth = getCalendarForLocale(mFirstDayOfMonth, locale);
+ mMinDate = getCalendarForLocale(mMinDate, locale);
+ mMaxDate = getCalendarForLocale(mMaxDate, locale);
+ }
+
+ /**
+ * Gets a calendar for locale bootstrapped with the value of a given calendar.
+ *
+ * @param oldCalendar The old calendar.
+ * @param locale The locale.
+ */
+ private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
+ if (oldCalendar == null) {
+ return Calendar.getInstance(locale);
+ } else {
+ final long currentTimeMillis = oldCalendar.getTimeInMillis();
+ Calendar newCalendar = Calendar.getInstance(locale);
+ newCalendar.setTimeInMillis(currentTimeMillis);
+ return newCalendar;
+ }
+ }
+
+ /**
* @return True if the <code>firstDate</code> is the same as the <code>
* secondDate</code>.
*/
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 8d4aaea..49616cc 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -130,10 +130,10 @@
setMinHeight(d.getIntrinsicHeight());
mCheckMarkWidth = d.getIntrinsicWidth();
- mPaddingRight = mCheckMarkWidth + mBasePaddingRight;
+ mUserPaddingRight = mCheckMarkWidth + mBasePaddingRight;
d.setState(getDrawableState());
} else {
- mPaddingRight = mBasePaddingRight;
+ mUserPaddingRight = mBasePaddingRight;
}
mCheckMarkDrawable = d;
requestLayout();
@@ -142,7 +142,7 @@
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
- mBasePaddingRight = mPaddingRight;
+ mBasePaddingRight = mUserPaddingRight;
}
@Override
@@ -167,9 +167,9 @@
int right = getWidth();
checkMarkDrawable.setBounds(
- right - mCheckMarkWidth - mBasePaddingRight,
+ right - mUserPaddingRight,
y,
- right - mBasePaddingRight,
+ right - mUserPaddingRight + mCheckMarkWidth,
y + height);
checkMarkDrawable.draw(canvas);
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 2410eb2..d3cdad8 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -217,6 +217,7 @@
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
+ info.setCheckable(true);
info.setChecked(mChecked);
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 30fb927..4812283 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -16,10 +16,9 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.Widget;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,6 +32,8 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.NumberPicker.OnValueChangeListener;
+import com.android.internal.R;
+
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@@ -89,23 +90,23 @@
private final CalendarView mCalendarView;
+ private Locale mCurrentLocale;
+
private OnDateChangedListener mOnDateChangedListener;
- private Locale mMonthLocale;
-
- private final Calendar mTempDate = Calendar.getInstance();
-
- private final int mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
-
- private final String[] mShortMonths = new String[mNumberOfMonths];
+ private String[] mShortMonths;
private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
- private final Calendar mMinDate = Calendar.getInstance();
+ private int mNumberOfMonths;
- private final Calendar mMaxDate = Calendar.getInstance();
+ private Calendar mTempDate;
- private final Calendar mCurrentDate = Calendar.getInstance();
+ private Calendar mMinDate;
+
+ private Calendar mMaxDate;
+
+ private Calendar mCurrentDate;
private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
@@ -137,6 +138,9 @@
public DatePicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ // initialization based on locale
+ setCurrentLocale(Locale.getDefault());
+
TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.DatePicker,
defStyle, 0);
boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
@@ -213,7 +217,7 @@
mMonthSpinner = (NumberPicker) findViewById(R.id.month);
mMonthSpinner.setMinValue(0);
mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
- mMonthSpinner.setDisplayedValues(getShortMonths());
+ mMonthSpinner.setDisplayedValues(mShortMonths);
mMonthSpinner.setOnLongPressUpdateInterval(200);
mMonthSpinner.setOnValueChangedListener(onChangeListener);
@@ -363,6 +367,12 @@
event.getText().add(selectedDateUtterance);
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ setCurrentLocale(newConfig.locale);
+ }
+
/**
* Gets whether the {@link CalendarView} is shown.
*
@@ -411,6 +421,48 @@
}
/**
+ * Sets the current locale.
+ *
+ * @param locale The current locale.
+ */
+ private void setCurrentLocale(Locale locale) {
+ if (locale.equals(mCurrentLocale)) {
+ return;
+ }
+
+ mCurrentLocale = locale;
+
+ mTempDate = getCalendarForLocale(mTempDate, locale);
+ mMinDate = getCalendarForLocale(mMinDate, locale);
+ mMaxDate = getCalendarForLocale(mMaxDate, locale);
+ mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
+
+ mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
+ mShortMonths = new String[mNumberOfMonths];
+ for (int i = 0; i < mNumberOfMonths; i++) {
+ mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
+ DateUtils.LENGTH_MEDIUM);
+ }
+ }
+
+ /**
+ * Gets a calendar for locale bootstrapped with the value of a given calendar.
+ *
+ * @param oldCalendar The old calendar.
+ * @param locale The locale.
+ */
+ private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
+ if (oldCalendar == null) {
+ return Calendar.getInstance(locale);
+ } else {
+ final long currentTimeMillis = oldCalendar.getTimeInMillis();
+ Calendar newCalendar = Calendar.getInstance(locale);
+ newCalendar.setTimeInMillis(currentTimeMillis);
+ return newCalendar;
+ }
+ }
+
+ /**
* Reorders the spinners according to the date format that is
* explicitly set by the user and if no such is set fall back
* to the current locale's default format.
@@ -507,23 +559,6 @@
}
}
- /**
- * @return The short month abbreviations.
- */
- private String[] getShortMonths() {
- final Locale currentLocale = Locale.getDefault();
- if (currentLocale.equals(mMonthLocale)) {
- return mShortMonths;
- } else {
- for (int i = 0; i < mNumberOfMonths; i++) {
- mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
- DateUtils.LENGTH_MEDIUM);
- }
- mMonthLocale = currentLocale;
- return mShortMonths;
- }
- }
-
private boolean isNewDate(int year, int month, int dayOfMonth) {
return (mCurrentDate.get(Calendar.YEAR) != year
|| mCurrentDate.get(Calendar.MONTH) != dayOfMonth
@@ -569,7 +604,7 @@
// make sure the month names are a zero based array
// with the months in the month spinner
- String[] displayedValues = Arrays.copyOfRange(getShortMonths(),
+ String[] displayedValues = Arrays.copyOfRange(mShortMonths,
mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
mMonthSpinner.setDisplayedValues(displayedValues);
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index c2759e5..f82c61a 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -28,7 +28,7 @@
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
-import com.android.internal.R.styleable;
+import com.android.internal.R;
import java.lang.reflect.Array;
import java.util.ArrayList;
@@ -53,12 +53,12 @@
* container and grid index {@code N} is fixed to its trailing edge
* (after padding is taken into account).
*
- * <h4>Row and Column Groups</h4>
+ * <h4>Row and Column Specs</h4>
*
* Children occupy one or more contiguous cells, as defined
- * by their {@link GridLayout.LayoutParams#rowGroup rowGroup} and
- * {@link GridLayout.LayoutParams#columnGroup columnGroup} layout parameters.
- * Each group specifies the set of rows or columns that are to be
+ * by their {@link GridLayout.LayoutParams#rowSpec rowSpec} and
+ * {@link GridLayout.LayoutParams#columnSpec columnSpec} layout parameters.
+ * Each spec defines the set of rows or columns that are to be
* occupied; and how children should be aligned within the resulting group of cells.
* Although cells do not normally overlap in a GridLayout, GridLayout does
* not prevent children being defined to occupy the same cell or group of cells.
@@ -92,7 +92,7 @@
*
* <h4>Excess Space Distribution</h4>
*
- * A child's ability to stretch is controlled using the {@link Group#flexibility flexibility}
+ * A child's ability to stretch is controlled using the flexibility
* properties of its row and column groups.
* <p>
* <p>
@@ -167,8 +167,7 @@
// Misc constants
private static final String TAG = GridLayout.class.getName();
- private static final boolean DEBUG = false;
- private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;
+ static boolean DEBUG = false;
private static final int PRF = 1;
// Defaults
@@ -178,19 +177,18 @@
private static final boolean DEFAULT_USE_DEFAULT_MARGINS = false;
private static final boolean DEFAULT_ORDER_PRESERVED = false;
private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
- // todo remove this
- private static final int DEFAULT_CONTAINER_MARGIN = 20;
+ private static final int DEFAULT_CONTAINER_MARGIN = 0;
private static final int MAX_SIZE = 100000;
// TypedArray indices
- private static final int ORIENTATION = styleable.GridLayout_orientation;
- private static final int ROW_COUNT = styleable.GridLayout_rowCount;
- private static final int COLUMN_COUNT = styleable.GridLayout_columnCount;
- private static final int USE_DEFAULT_MARGINS = styleable.GridLayout_useDefaultMargins;
- private static final int ALIGNMENT_MODE = styleable.GridLayout_alignmentMode;
- private static final int ROW_ORDER_PRESERVED = styleable.GridLayout_rowOrderPreserved;
- private static final int COLUMN_ORDER_PRESERVED = styleable.GridLayout_columnOrderPreserved;
+ private static final int ORIENTATION = R.styleable.GridLayout_orientation;
+ private static final int ROW_COUNT = R.styleable.GridLayout_rowCount;
+ private static final int COLUMN_COUNT = R.styleable.GridLayout_columnCount;
+ private static final int USE_DEFAULT_MARGINS = R.styleable.GridLayout_useDefaultMargins;
+ private static final int ALIGNMENT_MODE = R.styleable.GridLayout_alignmentMode;
+ private static final int ROW_ORDER_PRESERVED = R.styleable.GridLayout_rowOrderPreserved;
+ private static final int COLUMN_ORDER_PRESERVED = R.styleable.GridLayout_columnOrderPreserved;
// Instance variables
@@ -201,6 +199,7 @@
private boolean mUseDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
private int mDefaultGravity = Gravity.NO_GRAVITY;
+ private int mDefaultGap;
// Constructors
@@ -212,7 +211,8 @@
if (DEBUG) {
setWillNotDraw(false);
}
- TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout);
+ mDefaultGap = context.getResources().getDimensionPixelOffset(R.dimen.default_gap);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
setColumnCount(a.getInt(COLUMN_COUNT, DEFAULT_COUNT));
@@ -278,12 +278,12 @@
/**
* Returns the current number of rows. This is either the last value that was set
* with {@link #setRowCount(int)} or, if no such value was set, the maximum
- * value of each the upper bounds defined in {@link LayoutParams#rowGroup}.
+ * value of each the upper bounds defined in {@link LayoutParams#rowSpec}.
*
* @return the current number of rows
*
* @see #setRowCount(int)
- * @see LayoutParams#rowGroup
+ * @see LayoutParams#rowSpec
*
* @attr ref android.R.styleable#GridLayout_rowCount
*/
@@ -299,7 +299,7 @@
* @param rowCount the number of rows
*
* @see #getRowCount()
- * @see LayoutParams#rowGroup
+ * @see LayoutParams#rowSpec
*
* @attr ref android.R.styleable#GridLayout_rowCount
*/
@@ -310,12 +310,12 @@
/**
* Returns the current number of columns. This is either the last value that was set
* with {@link #setColumnCount(int)} or, if no such value was set, the maximum
- * value of each the upper bounds defined in {@link LayoutParams#columnGroup}.
+ * value of each the upper bounds defined in {@link LayoutParams#columnSpec}.
*
* @return the current number of columns
*
* @see #setColumnCount(int)
- * @see LayoutParams#columnGroup
+ * @see LayoutParams#columnSpec
*
* @attr ref android.R.styleable#GridLayout_columnCount
*/
@@ -331,7 +331,7 @@
* @param columnCount the number of columns.
*
* @see #getColumnCount()
- * @see LayoutParams#columnGroup
+ * @see LayoutParams#columnSpec
*
* @attr ref android.R.styleable#GridLayout_columnCount
*/
@@ -381,6 +381,10 @@
*/
public void setUseDefaultMargins(boolean useDefaultMargins) {
mUseDefaultMargins = useDefaultMargins;
+ if (useDefaultMargins) {
+ int padding = mDefaultGap;
+ setPadding(padding, padding, padding, padding);
+ }
requestLayout();
}
@@ -518,6 +522,14 @@
return result;
}
+ private static int sum(int[] a) {
+ int result = 0;
+ for (int i = 0, N = a.length; i < N; i++) {
+ result += a[i];
+ }
+ return result;
+ }
+
private static <T> T[] append(T[] a, T[] b) {
T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
System.arraycopy(a, 0, result, 0, a.length);
@@ -526,16 +538,10 @@
}
private int getDefaultMargin(View c, boolean horizontal, boolean leading) {
- // In the absence of any other information, calculate a default gap such
- // that, in a grid of identical components, the heights and the vertical
- // gaps are in the proportion of the golden ratio.
- // To effect this with equal margins at each edge, set each of the
- // four margin values to half this amount.
- return (int) (c.getMeasuredHeight() / GOLDEN_RATIO / 2);
+ return mDefaultGap / 2;
}
private int getDefaultMargin(View c, boolean isAtEdge, boolean horizontal, boolean leading) {
- // todo remove DEFAULT_CONTAINER_MARGIN. Use padding? Seek advice on Themes/Styles, etc.
return isAtEdge ? DEFAULT_CONTAINER_MARGIN : getDefaultMargin(c, horizontal, leading);
}
@@ -543,9 +549,9 @@
if (!mUseDefaultMargins) {
return 0;
}
- Group group = horizontal ? p.columnGroup : p.rowGroup;
+ Spec spec = horizontal ? p.columnSpec : p.rowSpec;
Axis axis = horizontal ? mHorizontalAxis : mVerticalAxis;
- Interval span = group.span;
+ Interval span = spec.span;
boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
return getDefaultMargin(c, isAtEdge, horizontal, leading);
@@ -593,12 +599,12 @@
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams1(c);
- final Group colGroup = lp.columnGroup;
- final Interval cols = colGroup.span;
+ final Spec colSpec = lp.columnSpec;
+ final Interval cols = colSpec.span;
final int colSpan = cols.size();
- final Group rowGroup = lp.rowGroup;
- final Interval rows = rowGroup.span;
+ final Spec rowSpec = lp.rowSpec;
+ final Interval rows = rowSpec.span;
final int rowSpan = rows.size();
if (horizontal) {
@@ -623,8 +629,8 @@
maxSize = max(maxSize, colSpan);
}
- lp.setColumnGroupSpan(new Interval(col, col + colSpan));
- lp.setRowGroupSpan(new Interval(row, row + rowSpan));
+ lp.setColumnSpecSpan(new Interval(col, col + colSpan));
+ lp.setRowSpecSpan(new Interval(row, row + rowSpan));
if (horizontal) {
col = col + colSpan;
@@ -737,7 +743,7 @@
}
// Draw margins
- paint.setColor(Color.YELLOW);
+ paint.setColor(Color.MAGENTA);
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
drawRectangle(canvas,
@@ -781,6 +787,12 @@
invalidateStructure();
}
+ @Override
+ public void removeAllViews() {
+ super.removeAllViews();
+ invalidateStructure();
+ }
+
// Measurement
private boolean isGone(View c) {
@@ -872,11 +884,11 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group columnGroup = lp.columnGroup;
- Group rowGroup = lp.rowGroup;
+ Spec columnSpec = lp.columnSpec;
+ Spec rowSpec = lp.rowSpec;
- Interval colSpan = columnGroup.span;
- Interval rowSpan = rowGroup.span;
+ Interval colSpan = columnSpec.span;
+ Interval rowSpan = rowSpec.span;
int x1 = mHorizontalAxis.getLocationIncludingMargin(true, colSpan.min);
int y1 = mVerticalAxis.getLocationIncludingMargin(true, rowSpan.min);
@@ -890,8 +902,8 @@
int pWidth = getMeasurement(c, true);
int pHeight = getMeasurement(c, false);
- Alignment hAlign = columnGroup.alignment;
- Alignment vAlign = rowGroup.alignment;
+ Alignment hAlign = columnSpec.alignment;
+ Alignment vAlign = rowSpec.alignment;
int dx, dy;
@@ -961,7 +973,7 @@
public boolean countValid = false;
public boolean countWasExplicitySet = false;
- PackedMap<Group, Bounds> groupBounds;
+ PackedMap<Spec, Bounds> groupBounds;
public boolean groupBoundsValid = false;
PackedMap<Interval, MutableInt> forwardLinks;
@@ -998,9 +1010,9 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams params = getLayoutParams(c);
- Group g = horizontal ? params.columnGroup : params.rowGroup;
- count = max(count, g.span.min);
- count = max(count, g.span.max);
+ Spec spec = horizontal ? params.columnSpec : params.rowSpec;
+ count = max(count, spec.span.min);
+ count = max(count, spec.span.max);
}
return count == -1 ? UNDEFINED : count;
}
@@ -1027,17 +1039,17 @@
invalidateStructure();
}
- private PackedMap<Group, Bounds> createGroupBounds() {
- Assoc<Group, Bounds> assoc = Assoc.of(Group.class, Bounds.class);
+ private PackedMap<Spec, Bounds> createGroupBounds() {
+ Assoc<Spec, Bounds> assoc = Assoc.of(Spec.class, Bounds.class);
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
if (isGone(c)) {
- assoc.put(Group.GONE, Bounds.GONE);
+ assoc.put(Spec.GONE, Bounds.GONE);
} else {
LayoutParams lp = getLayoutParams(c);
- Group group = horizontal ? lp.columnGroup : lp.rowGroup;
- Bounds bounds = group.alignment.getBounds();
- assoc.put(group, bounds);
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ Bounds bounds = spec.alignment.getBounds();
+ assoc.put(spec, bounds);
}
}
return assoc.pack();
@@ -1052,12 +1064,12 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- groupBounds.getValue(i).include(c, g, GridLayout.this, this);
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
}
}
- private PackedMap<Group, Bounds> getGroupBounds() {
+ private PackedMap<Spec, Bounds> getGroupBounds() {
if (groupBounds == null) {
groupBounds = createGroupBounds();
}
@@ -1071,7 +1083,7 @@
// Add values computed by alignment - taking the max of all alignments in each span
private PackedMap<Interval, MutableInt> createLinks(boolean min) {
Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
- Group[] keys = getGroupBounds().keys;
+ Spec[] keys = getGroupBounds().keys;
for (int i = 0, N = keys.length; i < N; i++) {
Interval span = min ? keys[i].span : keys[i].span.inverse();
result.put(span, new MutableInt());
@@ -1092,8 +1104,7 @@
MutableInt valueHolder = links.getValue(i);
if (min) {
valueHolder.value = max(valueHolder.value, size);
- }
- else {
+ } else {
valueHolder.value = -max(-valueHolder.value, size);
}
}
@@ -1236,8 +1247,8 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- Interval span = g.span;
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ Interval span = spec.span;
leadingEdgeCount[span.min]++;
trailingEdgeCount[span.max]++;
}
@@ -1436,8 +1447,8 @@
View c = getChildAt(i);
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- Interval span = g.span;
+ Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
+ Interval span = spec.span;
int index = leading ? span.min : span.max;
margins[index] = max(margins[index], getMargin(c, horizontal, leading));
}
@@ -1514,6 +1525,12 @@
}
private void setParentConstraints(int min, int max) {
+ if (mAlignmentMode != ALIGN_MARGINS) {
+ int margins = sum(getLeadingMargins()) + sum(getTrailingMargins());
+ min -= margins;
+ max -= margins;
+ }
+
parentMin.value = min;
parentMax.value = -max;
locationsValid = false;
@@ -1529,7 +1546,7 @@
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED: {
- return getMeasure(0, MAX_SIZE);
+ return getMeasure(0, MAX_SIZE);
}
case MeasureSpec.EXACTLY: {
return getMeasure(size, size);
@@ -1584,14 +1601,14 @@
* GridLayout supports both row and column spanning and arbitrary forms of alignment within
* each cell group. The fundamental parameters associated with each cell group are
* gathered into their vertical and horizontal components and stored
- * in the {@link #rowGroup} and {@link #columnGroup} layout parameters.
- * {@link Group Groups} are immutable structures and may be shared between the layout
- * parameters of different children.
+ * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
+ * {@link android.widget.GridLayout.Spec Specs} are immutable structures
+ * and may be shared between the layout parameters of different children.
* <p>
- * The row and column groups contain the leading and trailing indices along each axis
+ * The row and column specs contain the leading and trailing indices along each axis
* and together specify the four grid indices that delimit the cells of this cell group.
* <p>
- * The {@link Group#alignment alignment} fields of the row and column groups together specify
+ * The alignment properties of the row and column specs together specify
* both aspects of alignment within the cell group. It is also possible to specify a child's
* alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
* method.
@@ -1620,10 +1637,10 @@
* {@link GridLayout#setUseDefaultMargins(boolean) useDefaultMargins} is
* {@code false}; otherwise {@link #UNDEFINED}, to
* indicate that a default value should be computed on demand. </li>
- * <li>{@link #rowGroup}{@code .span} = {@code [0, 1]} </li>
- * <li>{@link #rowGroup}{@code .alignment} = {@link #BASELINE} </li>
- * <li>{@link #columnGroup}{@code .span} = {@code [0, 1]} </li>
- * <li>{@link #columnGroup}{@code .alignment} = {@link #LEFT} </li>
+ * <li>{@link #rowSpec}{@code .span} = {@code [0, 1]} </li>
+ * <li>{@link #rowSpec}{@code .alignment} = {@link #BASELINE} </li>
+ * <li>{@link #columnSpec}{@code .span} = {@code [0, 1]} </li>
+ * <li>{@link #columnSpec}{@code .alignment} = {@link #LEFT} </li>
* </ul>
*
* @attr ref android.R.styleable#GridLayout_Layout_layout_row
@@ -1656,70 +1673,71 @@
// TypedArray indices
- private static final int MARGIN = styleable.ViewGroup_MarginLayout_layout_margin;
- private static final int LEFT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginLeft;
- private static final int TOP_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginTop;
- private static final int RIGHT_MARGIN = styleable.ViewGroup_MarginLayout_layout_marginRight;
+ private static final int MARGIN = R.styleable.ViewGroup_MarginLayout_layout_margin;
+ private static final int LEFT_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginLeft;
+ private static final int TOP_MARGIN = R.styleable.ViewGroup_MarginLayout_layout_marginTop;
+ private static final int RIGHT_MARGIN =
+ R.styleable.ViewGroup_MarginLayout_layout_marginRight;
private static final int BOTTOM_MARGIN =
- styleable.ViewGroup_MarginLayout_layout_marginBottom;
+ R.styleable.ViewGroup_MarginLayout_layout_marginBottom;
- private static final int COLUMN = styleable.GridLayout_Layout_layout_column;
- private static final int COLUMN_SPAN = styleable.GridLayout_Layout_layout_columnSpan;
+ private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
+ private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
private static final int COLUMN_FLEXIBILITY =
- styleable.GridLayout_Layout_layout_columnFlexibility;
+ R.styleable.GridLayout_Layout_layout_columnFlexibility;
- private static final int ROW = styleable.GridLayout_Layout_layout_row;
- private static final int ROW_SPAN = styleable.GridLayout_Layout_layout_rowSpan;
+ private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
+ private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
private static final int ROW_FLEXIBILITY =
- styleable.GridLayout_Layout_layout_rowFlexibility;
+ R.styleable.GridLayout_Layout_layout_rowFlexibility;
- private static final int GRAVITY = styleable.GridLayout_Layout_layout_gravity;
+ private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
// Instance variables
/**
- * The group that specifies the vertical characteristics of the cell group
+ * The spec that specifies the vertical characteristics of the cell group
* described by these layout parameters.
*/
- public Group rowGroup;
+ public Spec rowSpec;
/**
- * The group that specifies the horizontal characteristics of the cell group
+ * The spec that specifies the horizontal characteristics of the cell group
* described by these layout parameters.
*/
- public Group columnGroup;
+ public Spec columnSpec;
// Constructors
private LayoutParams(
int width, int height,
int left, int top, int right, int bottom,
- Group rowGroup, Group columnGroup) {
+ Spec rowSpec, Spec columnSpec) {
super(width, height);
setMargins(left, top, right, bottom);
- this.rowGroup = rowGroup;
- this.columnGroup = columnGroup;
+ this.rowSpec = rowSpec;
+ this.columnSpec = columnSpec;
}
/**
- * Constructs a new LayoutParams instance for this <code>rowGroup</code>
- * and <code>columnGroup</code>. All other fields are initialized with
+ * Constructs a new LayoutParams instance for this <code>rowSpec</code>
+ * and <code>columnSpec</code>. All other fields are initialized with
* default values as defined in {@link LayoutParams}.
*
- * @param rowGroup the rowGroup
- * @param columnGroup the columnGroup
+ * @param rowSpec the rowSpec
+ * @param columnSpec the columnSpec
*/
- public LayoutParams(Group rowGroup, Group columnGroup) {
+ public LayoutParams(Spec rowSpec, Spec columnSpec) {
this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
- rowGroup, columnGroup);
+ rowSpec, columnSpec);
}
/**
* Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
*/
public LayoutParams() {
- this(new Group(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT),
- new Group(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT));
+ this(new Spec(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT, Spec.DEFAULT_FLEXIBILITY),
+ new Spec(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT, Spec.DEFAULT_FLEXIBILITY));
}
// Copying constructors
@@ -1743,8 +1761,8 @@
*/
public LayoutParams(LayoutParams that) {
super(that);
- this.columnGroup = new Group(that.columnGroup);
- this.rowGroup = new Group(that.rowGroup);
+ this.columnSpec = new Spec(that.columnSpec);
+ this.rowSpec = new Spec(that.rowSpec);
}
// AttributeSet constructors
@@ -1793,7 +1811,8 @@
// This method could be parametrized and moved into MarginLayout.
private void reInitSuper(Context context, AttributeSet attrs) {
- TypedArray a = context.obtainStyledAttributes(attrs, styleable.ViewGroup_MarginLayout);
+ TypedArray a =
+ context.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
try {
int margin = a.getDimensionPixelSize(MARGIN, DEFAULT_MARGIN);
@@ -1829,21 +1848,21 @@
}
private void init(Context context, AttributeSet attrs, int defaultGravity) {
- TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GridLayout_Layout);
try {
int gravity = a.getInt(GRAVITY, defaultGravity);
int column = a.getInt(COLUMN, DEFAULT_COLUMN);
int columnSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
Interval hSpan = new Interval(column, column + columnSpan);
- int hFlexibility = a.getInt(COLUMN_FLEXIBILITY, Group.DEFAULT_FLEXIBILITY);
- this.columnGroup = new Group(hSpan, getColAlignment(gravity, width), hFlexibility);
+ int hFlexibility = a.getInt(COLUMN_FLEXIBILITY, Spec.DEFAULT_FLEXIBILITY);
+ this.columnSpec = new Spec(hSpan, getColAlignment(gravity, width), hFlexibility);
int row = a.getInt(ROW, DEFAULT_ROW);
int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
Interval vSpan = new Interval(row, row + rowSpan);
- int vFlexibility = a.getInt(ROW_FLEXIBILITY, Group.DEFAULT_FLEXIBILITY);
- this.rowGroup = new Group(vSpan, getRowAlignment(gravity, height), vFlexibility);
+ int vFlexibility = a.getInt(ROW_FLEXIBILITY, Spec.DEFAULT_FLEXIBILITY);
+ this.rowSpec = new Spec(vSpan, getRowAlignment(gravity, height), vFlexibility);
} finally {
a.recycle();
}
@@ -1858,8 +1877,8 @@
* @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
*/
public void setGravity(int gravity) {
- columnGroup = columnGroup.copyWriteAlignment(getColAlignment(gravity, width));
- rowGroup = rowGroup.copyWriteAlignment(getRowAlignment(gravity, height));
+ columnSpec = columnSpec.copyWriteAlignment(getColAlignment(gravity, width));
+ rowSpec = rowSpec.copyWriteAlignment(getRowAlignment(gravity, height));
}
@Override
@@ -1868,12 +1887,12 @@
this.height = attributes.getLayoutDimension(heightAttr, DEFAULT_HEIGHT);
}
- private void setRowGroupSpan(Interval span) {
- rowGroup = rowGroup.copyWriteSpan(span);
+ private void setRowSpecSpan(Interval span) {
+ rowSpec = rowSpec.copyWriteSpan(span);
}
- private void setColumnGroupSpan(Interval span) {
- columnGroup = columnGroup.copyWriteSpan(span);
+ private void setColumnSpecSpan(Interval span) {
+ columnSpec = columnSpec.copyWriteSpan(span);
}
}
@@ -2019,14 +2038,14 @@
}
/*
- For each Group (with a given alignment) we need to store the amount of space required
+ For each group (with a given alignment) we need to store the amount of space required
before the alignment point and the amount of space required after it. One side of this
calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
simple optimisations are possible.
The general algorithm therefore is to create a Map (actually a PackedMap) from
- Group to Bounds and to loop through all Views in the group taking the maximum
+ group to Bounds and to loop through all Views in the group taking the maximum
of the values for each View.
*/
private static class Bounds {
@@ -2067,11 +2086,11 @@
return before - alignment.getAlignmentValue(c, size);
}
- protected void include(View c, Group group, GridLayout gridLayout, Axis axis) {
- this.flexibility &= group.flexibility;
+ protected void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
+ this.flexibility &= spec.flexibility;
int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
// todo test this works correctly when the returned value is UNDEFINED
- int before = group.alignment.getAlignmentValue(c, size);
+ int before = spec.alignment.getAlignmentValue(c, size);
include(before, size - before);
}
@@ -2176,16 +2195,13 @@
}
/**
- * A group specifies either the horizontal or vertical characteristics of a group of
+ * A spec defines either the horizontal or vertical characteristics of a group of
* cells.
- * <p>
- * Groups are immutable and so may be shared between views with the same
- * {@code span} and {@code alignment}.
*/
- public static class Group {
+ public static class Spec {
private static final int DEFAULT_FLEXIBILITY = UNDEFINED_FLEXIBILITY;
- private static final Group GONE = new Group(Interval.GONE, Alignment.GONE);
+ private static final Spec GONE = new Spec(Interval.GONE, Alignment.GONE);
/**
* The grid indices of the leading and trailing edges of this cell group for the
@@ -2200,7 +2216,7 @@
* For row groups, this specifies the vertical alignment.
* For column groups, this specifies the horizontal alignment.
*/
- public final Alignment alignment;
+ final Alignment alignment;
/**
* The flexibility field tells GridLayout how to derive minimum and maximum size
@@ -2212,82 +2228,48 @@
*
* @see GridLayout#CAN_STRETCH
*/
- public int flexibility = DEFAULT_FLEXIBILITY;
+ final int flexibility;
- /**
- * Construct a new Group, {@code group}, where:
- * <ul>
- * <li> {@code group.span = span} </li>
- * <li> {@code group.alignment = alignment} </li>
- * </ul>
- *
- * @param span the span
- * @param alignment the alignment
- */
- private Group(Interval span, Alignment alignment) {
- this.span = span;
- this.alignment = alignment;
- }
-
- private Group(Interval span, Alignment alignment, int flexibility) {
+ private Spec(Interval span, Alignment alignment, int flexibility) {
this.span = span;
this.alignment = alignment;
this.flexibility = flexibility;
}
+ private Spec(Interval span, Alignment alignment) {
+ this(span, alignment, DEFAULT_FLEXIBILITY);
+ }
+
/* Copying constructor */
- private Group(Group that) {
- this.span = that.span;
- this.alignment = that.alignment;
- this.flexibility = that.flexibility;
+ private Spec(Spec that) {
+ this(that.span, that.alignment, that.flexibility);
+ }
+
+ Spec(int start, int size, Alignment alignment, int flexibility) {
+ this(new Interval(start, start + size), alignment, flexibility);
+ }
+
+ private Spec copyWriteSpan(Interval span) {
+ return new Spec(span, alignment, flexibility);
+ }
+
+ private Spec copyWriteAlignment(Alignment alignment) {
+ return new Spec(span, alignment, flexibility);
+ }
+
+ private Spec copyWriteFlexibility(int flexibility) {
+ return new Spec(span, alignment, flexibility);
}
/**
- * Construct a new Group, {@code group}, where:
- * <ul>
- * <li> {@code group.span = [start, start + size]} </li>
- * <li> {@code group.alignment = alignment} </li>
- * </ul>
- *
- * @param start the start
- * @param size the size
- * @param alignment the alignment
- */
- public Group(int start, int size, Alignment alignment) {
- this(new Interval(start, start + size), alignment);
- }
-
- /**
- * Construct a new Group, {@code group}, where:
- * <ul>
- * <li> {@code group.span = [start, start + 1]} </li>
- * <li> {@code group.alignment = alignment} </li>
- * </ul>
- *
- * @param start the start index
- * @param alignment the alignment
- */
- public Group(int start, Alignment alignment) {
- this(start, 1, alignment);
- }
-
- private Group copyWriteSpan(Interval span) {
- return new Group(span, alignment, flexibility);
- }
-
- private Group copyWriteAlignment(Alignment alignment) {
- return new Group(span, alignment, flexibility);
- }
-
- /**
- * Returns {@code true} if the {@link #getClass class}, {@link #alignment} and {@code span}
- * properties of this Group and the supplied parameter are pairwise equal,
+ * Returns {@code true} if the {@code class}, {@code alignment} and {@code span}
+ * properties of this Spec and the supplied parameter are pairwise equal,
* {@code false} otherwise.
*
- * @param that the object to compare this group with
+ * @param that the object to compare this spec with
*
* @return {@code true} if the specified object is equal to this
- * {@code Group}; {@code false} otherwise
+ * {@code Spec}; {@code false} otherwise
*/
@Override
public boolean equals(Object that) {
@@ -2298,12 +2280,12 @@
return false;
}
- Group group = (Group) that;
+ Spec spec = (Spec) that;
- if (!alignment.equals(group.alignment)) {
+ if (!alignment.equals(spec.alignment)) {
return false;
}
- if (!span.equals(group.span)) {
+ if (!span.equals(spec.span)) {
return false;
}
@@ -2319,12 +2301,93 @@
}
/**
+ * Temporary backward compatibility class for Launcher - to avoid
+ * dependent multi-project commit. This class will be deleted after
+ * AppsCustomizePagedView is updated to new API.
+ *
+ * @hide
+ */
+ @Deprecated
+ public static class Group extends Spec {
+ /**
+ * @deprecated Please replace with {@link #spec(int, int, Alignment)}
+ * @hide
+ */
+ @Deprecated
+ public Group(int start, int size, Alignment alignment) {
+ super(start, size, alignment, UNDEFINED_FLEXIBILITY);
+ }
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + size]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * <li> {@code spec.flexibility = flexibility} </li>
+ * </ul>
+ *
+ * @param start the start
+ * @param size the size
+ * @param alignment the alignment
+ * @param flexibility the flexibility
+ */
+ public static Spec spec(int start, int size, Alignment alignment, int flexibility) {
+ return new Spec(start, size, alignment, flexibility);
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + 1]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * <li> {@code spec.flexibility = flexibility} </li>
+ * </ul>
+ *
+ * @param start the start
+ * @param alignment the alignment
+ * @param flexibility the flexibility
+ */
+ public static Spec spec(int start, Alignment alignment, int flexibility) {
+ return spec(start, 1, alignment, flexibility);
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + size]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * </ul>
+ *
+ * @param start the start
+ * @param size the size
+ * @param alignment the alignment
+ */
+ public static Spec spec(int start, int size, Alignment alignment) {
+ return spec(start, size, alignment, Spec.DEFAULT_FLEXIBILITY);
+ }
+
+ /**
+ * Return a Spec, {@code spec}, where:
+ * <ul>
+ * <li> {@code spec.span = [start, start + 1]} </li>
+ * <li> {@code spec.alignment = alignment} </li>
+ * </ul>
+ *
+ * @param start the start index
+ * @param alignment the alignment
+ */
+ public static Spec spec(int start, Alignment alignment) {
+ return spec(start, 1, alignment);
+ }
+
+ /**
* Alignments specify where a view should be placed within a cell group and
* what size it should be.
* <p>
- * The {@link LayoutParams} class contains a {@link LayoutParams#rowGroup rowGroup}
- * and a {@link LayoutParams#columnGroup columnGroup} each of which contains an
- * {@link Group#alignment alignment}. Overall placement of the view in the cell
+ * The {@link LayoutParams} class contains a {@link LayoutParams#rowSpec rowSpec}
+ * and a {@link LayoutParams#columnSpec columnSpec} each of which contains an
+ * {@code alignment}. Overall placement of the view in the cell
* group is specified by the two alignments which act along each axis independently.
* <p>
* The GridLayout class defines the most common alignments used in general layout:
@@ -2425,8 +2488,8 @@
/**
* Indicates that a view should be <em>centered</em> with the other views in its cell group.
- * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and {@link
- * LayoutParams#columnGroup columnGroups}.
+ * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and {@link
+ * LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment CENTER = new Alignment() {
public int getAlignmentValue(View view, int viewSize) {
@@ -2437,7 +2500,7 @@
/**
* Indicates that a view should be aligned with the <em>baselines</em>
* of the other views in its cell group.
- * This constant may only be used as an alignment in {@link LayoutParams#rowGroup rowGroups}.
+ * This constant may only be used as an alignment in {@link LayoutParams#rowSpec rowSpecs}.
*
* @see View#getBaseline()
*/
@@ -2488,8 +2551,8 @@
/**
* Indicates that a view should expanded to fit the boundaries of its cell group.
- * This constant may be used in both {@link LayoutParams#rowGroup rowGroups} and
- * {@link LayoutParams#columnGroup columnGroups}.
+ * This constant may be used in both {@link LayoutParams#rowSpec rowSpecs} and
+ * {@link LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment FILL = new Alignment() {
public int getAlignmentValue(View view, int viewSize) {
@@ -2513,42 +2576,30 @@
/**
* Indicates that a view requests precisely the size specified by its layout parameters.
*
- * @see Group#flexibility
- *
- * @hide
+ * @see Spec#flexibility
*/
- public static final int FIXED = 0;
+ private static final int NONE = 0;
/**
* Indicates that a view's size should lie between its minimum and the size specified by
* its layout parameters.
*
- * @see Group#flexibility
- *
- * @hide
+ * @see Spec#flexibility
*/
- public static final int CAN_SHRINK = 1;
+ private static final int CAN_SHRINK = 1;
/**
* Indicates that a view's size should be greater than or equal to the size specified by
* its layout parameters.
*
- * @see Group#flexibility
+ * @see Spec#flexibility
*/
public static final int CAN_STRETCH = 2;
/**
- * Indicates that a view will ignore its measurement, and can take any size that is greater
- * than its minimum.
- *
- * @see Group#flexibility
- */
- private static final int CAN_SHRINK_OR_STRETCH = CAN_SHRINK | CAN_STRETCH;
-
- /**
* A default value for flexibility.
*
- * @see Group#flexibility
+ * @see Spec#flexibility
*/
private static final int UNDEFINED_FLEXIBILITY = UNDEFINED | CAN_SHRINK | CAN_STRETCH;
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 7c9be1e..b428301 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -498,13 +498,6 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
-
- if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
- // Don't handle edge touches immediately -- they may actually belong to one of our
- // descendants.
- return false;
- }
-
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 5642877..f057d07 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -62,6 +62,7 @@
private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
private int mDropDownHorizontalOffset;
private int mDropDownVerticalOffset;
+ private boolean mDropDownVerticalOffsetSet;
private boolean mDropDownAlwaysVisible = false;
private boolean mForceIgnoreOutsideTouch = false;
@@ -404,6 +405,9 @@
* @return The vertical offset of the popup from its anchor in pixels.
*/
public int getVerticalOffset() {
+ if (!mDropDownVerticalOffsetSet) {
+ return 0;
+ }
return mDropDownVerticalOffset;
}
@@ -414,6 +418,7 @@
*/
public void setVerticalOffset(int offset) {
mDropDownVerticalOffset = offset;
+ mDropDownVerticalOffsetSet = true;
}
/**
@@ -1061,21 +1066,27 @@
}
}
- // Max height available on the screen for a popup.
- boolean ignoreBottomDecorations =
- mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
- final int maxHeight = mPopup.getMaxAvailableHeight(
- getAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
-
- // getMaxAvailableHeight() subtracts the padding, so we put it back,
+ // getMaxAvailableHeight() subtracts the padding, so we put it back
// to get the available height for the whole window
int padding = 0;
Drawable background = mPopup.getBackground();
if (background != null) {
background.getPadding(mTempRect);
padding = mTempRect.top + mTempRect.bottom;
+
+ // If we don't have an explicit vertical offset, determine one from the window
+ // background so that content will line up.
+ if (!mDropDownVerticalOffsetSet) {
+ mDropDownVerticalOffset = -mTempRect.top;
+ }
}
+ // Max height available on the screen for a popup.
+ boolean ignoreBottomDecorations =
+ mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+ final int maxHeight = mPopup.getMaxAvailableHeight(
+ getAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
+
if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
return maxHeight + padding;
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e7a9e41..1f29b16 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3588,17 +3588,6 @@
return null;
}
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- //noinspection SimplifiableIfStatement
- if (mItemsCanFocus && ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
- // Don't handle edge touches immediately -- they may actually belong to one of our
- // descendants.
- return false;
- }
- return super.onTouchEvent(ev);
- }
-
/**
* Returns the set of checked items ids. The result is only valid if the
* choice mode has not been set to {@link #CHOICE_MODE_NONE}.
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 4c47d37..867ebb4 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -53,6 +53,10 @@
// This ensures that we don't stay continually bound to the service and that it can be destroyed
// if we need the memory elsewhere in the system.
private static final int sUnbindServiceDelay = 5000;
+
+ // Default height for the default loading view, in case we cannot get inflate the first view
+ private static final int sDefaultLoadingViewHeight = 50;
+
// Type defs for controlling different messages across the main and worker message queues
private static final int sDefaultMessageType = 0;
private static final int sUnbindServiceMessageType = 1;
@@ -386,21 +390,39 @@
// Create a new loading view
synchronized (mCache) {
+ boolean customLoadingViewAvailable = false;
+
if (mUserLoadingView != null) {
- // A user-specified loading view
- View loadingView = mUserLoadingView.apply(parent.getContext(), parent);
- loadingView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(0));
- layout.addView(loadingView);
- } else {
+ // Try to inflate user-specified loading view
+ try {
+ View loadingView = mUserLoadingView.apply(parent.getContext(), parent);
+ loadingView.setTagInternal(com.android.internal.R.id.rowTypeId,
+ new Integer(0));
+ layout.addView(loadingView);
+ customLoadingViewAvailable = true;
+ } catch (Exception e) {
+ Log.w(TAG, "Error inflating custom loading view, using default loading" +
+ "view instead", e);
+ }
+ }
+ if (!customLoadingViewAvailable) {
// A default loading view
// Use the size of the first row as a guide for the size of the loading view
if (mFirstViewHeight < 0) {
- View firstView = mFirstView.apply(parent.getContext(), parent);
- firstView.measure(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mFirstViewHeight = firstView.getMeasuredHeight();
- mFirstView = null;
+ try {
+ View firstView = mFirstView.apply(parent.getContext(), parent);
+ firstView.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mFirstViewHeight = firstView.getMeasuredHeight();
+ mFirstView = null;
+ } catch (Exception e) {
+ float density = mContext.getResources().getDisplayMetrics().density;
+ mFirstViewHeight = (int)
+ Math.round(sDefaultLoadingViewHeight * density);
+ mFirstView = null;
+ Log.w(TAG, "Error inflating first RemoteViews" + e);
+ }
}
// Compose the loading view text
@@ -937,24 +959,40 @@
indexMetaData.isRequested = true;
int typeId = indexMetaData.typeId;
- // Reuse the convert view where possible
- if (layout != null) {
- if (convertViewTypeId == typeId) {
- rv.reapply(context, convertViewChild);
- return layout;
+ try {
+ // Reuse the convert view where possible
+ if (layout != null) {
+ if (convertViewTypeId == typeId) {
+ rv.reapply(context, convertViewChild);
+ return layout;
+ }
+ layout.removeAllViews();
+ } else {
+ layout = new RemoteViewsFrameLayout(context);
}
- layout.removeAllViews();
- } else {
- layout = new RemoteViewsFrameLayout(context);
+
+ // Otherwise, create a new view to be returned
+ View newView = rv.apply(context, parent);
+ newView.setTagInternal(com.android.internal.R.id.rowTypeId,
+ new Integer(typeId));
+ layout.addView(newView);
+ return layout;
+
+ } catch (Exception e){
+ // We have to make sure that we successfully inflated the RemoteViews, if not
+ // we return the loading view instead.
+ Log.w(TAG, "Error inflating RemoteViews at position: " + position + ", using" +
+ "loading view instead" + e);
+
+ RemoteViewsFrameLayout loadingView = null;
+ final RemoteViewsMetaData metaData = mCache.getMetaData();
+ synchronized (metaData) {
+ loadingView = metaData.createLoadingView(position, convertView, parent);
+ }
+ return loadingView;
+ } finally {
+ if (hasNewItems) loadNextIndexInBackground();
}
-
- // Otherwise, create a new view to be returned
- View newView = rv.apply(context, parent);
- newView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(typeId));
- layout.addView(newView);
- if (hasNewItems) loadNextIndexInBackground();
-
- return layout;
} else {
// If the cache does not have the RemoteViews at this position, then create a
// loading view and queue the actual position to be loaded in the background
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 12775a4..e59f731 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -65,7 +65,6 @@
static final float MAX_SCROLL_FACTOR = 0.5f;
-
private long mLastScroll;
private final Rect mTempRect = new Rect();
@@ -506,13 +505,6 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
-
- if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
- // Don't handle edge touches immediately -- they may actually belong to one of our
- // descendants.
- return false;
- }
-
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
@@ -1438,17 +1430,6 @@
final boolean movingDown = velocityY > 0;
- View currentFocused = findFocus();
- View newFocused =
- findFocusableViewInMyBounds(movingDown, mScroller.getFinalY(), currentFocused);
- if (newFocused == null) {
- newFocused = this;
- }
-
- if (newFocused != currentFocused) {
- newFocused.requestFocus(movingDown ? View.FOCUS_DOWN : View.FOCUS_UP);
- }
-
if (mFlingStrictSpan == null) {
mFlingStrictSpan = StrictMode.enterCriticalSpan("ScrollView-fling");
}
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index d6e426f..665109a 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -18,18 +18,23 @@
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.ActionProvider;
+import android.view.Menu;
import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.SubMenu;
import android.view.View;
import com.android.internal.R;
/**
* This is a provider for a share action. It is responsible for creating views
- * that enable data sharing and also to perform a default action for showing
- * a share dialog.
+ * that enable data sharing and also to show a sub menu with sharing activities
+ * if the hosting item is placed on the overflow menu.
* <p>
* Here is how to use the action provider with custom backing file in a {@link MenuItem}:
* </p>
@@ -47,15 +52,13 @@
* // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
* // line if using the default share history file is desired.
* mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
- * // Get the action view and hold onto it to set the share intent.
- * mActionView = menuItem.getActionView();
* . . .
* }
*
* // Somewhere in the application.
* public void doShare(Intent shareIntent) {
* // When you want to share set the share intent.
- * mShareActionProvider.setShareIntent(mActionView, shareIntent);
+ * mShareActionProvider.setShareIntent(shareIntent);
* }
* </pre>
* </code>
@@ -70,11 +73,34 @@
public class ShareActionProvider extends ActionProvider {
/**
+ * The default for the maximal number of activities shown in the sub-menu.
+ */
+ private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4;
+
+ /**
+ * The the maximum number activities shown in the sub-menu.
+ */
+ private int mMaxShownActivityCount = DEFAULT_INITIAL_ACTIVITY_COUNT;
+
+ /**
+ * Listener for handling menu item clicks.
+ */
+ private final ShareMenuItemOnMenuItemClickListener mOnMenuItemClickListener =
+ new ShareMenuItemOnMenuItemClickListener();
+
+ /**
* The default name for storing share history.
*/
public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+ /**
+ * Context for accessing resources.
+ */
private final Context mContext;
+
+ /**
+ * The name of the file with share history data.
+ */
private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME;
/**
@@ -92,13 +118,17 @@
*/
@Override
public View onCreateActionView() {
+ // Create the view and set its data model.
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
activityChooserView.setActivityChooserModel(dataModel);
+
+ // Lookup and set the expand action icon.
TypedValue outTypedValue = new TypedValue();
mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
+
return activityChooserView;
}
@@ -106,12 +136,43 @@
* {@inheritDoc}
*/
@Override
- public void onPerformDefaultAction(View actionView) {
- if (actionView instanceof ActivityChooserView) {
- ActivityChooserView activityChooserView = (ActivityChooserView) actionView;
- activityChooserView.showPopup();
- } else {
- throw new IllegalArgumentException("actionView not instance of ActivityChooserView");
+ public boolean hasSubMenu() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onPrepareSubMenu(SubMenu subMenu) {
+ // Clear since the order of items may change.
+ subMenu.clear();
+
+ ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
+ PackageManager packageManager = mContext.getPackageManager();
+
+ final int expandedActivityCount = dataModel.getActivityCount();
+ final int collapsedActivityCount = Math.min(expandedActivityCount, mMaxShownActivityCount);
+
+ // Populate the sub-menu with a sub set of the activities.
+ for (int i = 0; i < collapsedActivityCount; i++) {
+ ResolveInfo activity = dataModel.getActivity(i);
+ subMenu.add(0, i, i, activity.loadLabel(packageManager))
+ .setIcon(activity.loadIcon(packageManager))
+ .setOnMenuItemClickListener(mOnMenuItemClickListener);
+ }
+
+ if (collapsedActivityCount < expandedActivityCount) {
+ // Add a sub-menu for showing all activities as a list item.
+ SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
+ collapsedActivityCount,
+ mContext.getString(R.string.activity_chooser_view_see_all));
+ for (int i = 0; i < expandedActivityCount; i++) {
+ ResolveInfo activity = dataModel.getActivity(i);
+ expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
+ .setIcon(activity.loadIcon(packageManager))
+ .setOnMenuItemClickListener(mOnMenuItemClickListener);
+ }
}
}
@@ -147,18 +208,29 @@
* </code>
* </p>
*
- * @param actionView An action view created by {@link #onCreateActionView()}.
* @param shareIntent The share intent.
*
* @see Intent#ACTION_SEND
* @see Intent#ACTION_SEND_MULTIPLE
*/
- public void setShareIntent(View actionView, Intent shareIntent) {
- if (actionView instanceof ActivityChooserView) {
- ActivityChooserView activityChooserView = (ActivityChooserView) actionView;
- activityChooserView.getDataModel().setIntent(shareIntent);
- } else {
- throw new IllegalArgumentException("actionView not instance of ActivityChooserView");
+ public void setShareIntent(Intent shareIntent) {
+ ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
+ mShareHistoryFileName);
+ dataModel.setIntent(shareIntent);
+ }
+
+ /**
+ * Reusable listener for handling share item clicks.
+ */
+ private class ShareMenuItemOnMenuItemClickListener implements OnMenuItemClickListener {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
+ mShareHistoryFileName);
+ final int itemId = item.getItemId();
+ Intent launchIntent = dataModel.chooseActivity(itemId);
+ mContext.startActivity(launchIntent);
+ return true;
}
}
}
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 485c678..2fba18b 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -165,10 +165,17 @@
ViewGroup.LayoutParams.WRAP_CONTENT);
popup.setBackgroundDrawable(a.getDrawable(
com.android.internal.R.styleable.Spinner_popupBackground));
- popup.setVerticalOffset(a.getDimensionPixelOffset(
- com.android.internal.R.styleable.Spinner_dropDownVerticalOffset, 0));
- popup.setHorizontalOffset(a.getDimensionPixelOffset(
- com.android.internal.R.styleable.Spinner_dropDownHorizontalOffset, 0));
+ final int verticalOffset = a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.Spinner_dropDownVerticalOffset, 0);
+ if (verticalOffset != 0) {
+ popup.setVerticalOffset(verticalOffset);
+ }
+
+ final int horizontalOffset = a.getDimensionPixelOffset(
+ com.android.internal.R.styleable.Spinner_dropDownHorizontalOffset, 0);
+ if (horizontalOffset != 0) {
+ popup.setHorizontalOffset(horizontalOffset);
+ }
mPopup = popup;
break;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e350ec4..769f5e3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -64,6 +64,13 @@
import android.text.Spanned;
import android.text.SpannedString;
import android.text.StaticLayout;
+import android.text.TextDirectionHeuristic;
+import android.text.TextDirectionHeuristics;
+import android.text.TextDirectionHeuristics.AnyStrong;
+import android.text.TextDirectionHeuristics.CharCount;
+import android.text.TextDirectionHeuristics.FirstStrong;
+import android.text.TextDirectionHeuristics.TextDirectionAlgorithm;
+import android.text.TextDirectionHeuristics.TextDirectionHeuristicImpl;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
@@ -260,9 +267,12 @@
class Drawables {
final Rect mCompoundRect = new Rect();
- Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight;
- int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight;
- int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight;
+ Drawable mDrawableTop, mDrawableBottom, mDrawableLeft, mDrawableRight,
+ mDrawableStart, mDrawableEnd;
+ int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight,
+ mDrawableSizeStart, mDrawableSizeEnd;
+ int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight,
+ mDrawableHeightStart, mDrawableHeightEnd;
int mDrawablePadding;
}
private Drawables mDrawables;
@@ -352,6 +362,8 @@
INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END;
}
+ private boolean bResolvedDrawables = false;
+
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -494,7 +506,7 @@
int buffertype = 0;
boolean selectallonfocus = false;
Drawable drawableLeft = null, drawableTop = null, drawableRight = null,
- drawableBottom = null;
+ drawableBottom = null, drawableStart = null, drawableEnd = null;
int drawablePadding = 0;
int ellipsize = -1;
boolean singleLine = false;
@@ -571,6 +583,14 @@
drawableBottom = a.getDrawable(attr);
break;
+ case com.android.internal.R.styleable.TextView_drawableStart:
+ drawableStart = a.getDrawable(attr);
+ break;
+
+ case com.android.internal.R.styleable.TextView_drawableEnd:
+ drawableEnd = a.getDrawable(attr);
+ break;
+
case com.android.internal.R.styleable.TextView_drawablePadding:
drawablePadding = a.getDimensionPixelSize(attr, drawablePadding);
break;
@@ -980,6 +1000,7 @@
setCompoundDrawablesWithIntrinsicBounds(
drawableLeft, drawableTop, drawableRight, drawableBottom);
+ setRelativeDrawablesIfNeeded(drawableStart, drawableEnd);
setCompoundDrawablePadding(drawablePadding);
// Same as setSingleLine(), but make sure the transformation method and the maximum number
@@ -1105,6 +1126,42 @@
setTypeface(tf, styleIndex);
}
+ private void setRelativeDrawablesIfNeeded(Drawable start, Drawable end) {
+ boolean hasRelativeDrawables = (start != null) || (end != null);
+ if (hasRelativeDrawables) {
+ Drawables dr = mDrawables;
+ if (dr == null) {
+ mDrawables = dr = new Drawables();
+ }
+ final Rect compoundRect = dr.mCompoundRect;
+ int[] state = getDrawableState();
+ if (start != null) {
+ start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+ start.setState(state);
+ start.copyBounds(compoundRect);
+ start.setCallback(this);
+
+ dr.mDrawableStart = start;
+ dr.mDrawableSizeStart = compoundRect.width();
+ dr.mDrawableHeightStart = compoundRect.height();
+ } else {
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ }
+ if (end != null) {
+ end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+ end.setState(state);
+ end.copyBounds(compoundRect);
+ end.setCallback(this);
+
+ dr.mDrawableEnd = end;
+ dr.mDrawableSizeEnd = compoundRect.width();
+ dr.mDrawableHeightEnd = compoundRect.height();
+ } else {
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ }
+ }
+ }
+
@Override
public void setEnabled(boolean enabled) {
if (enabled == isEnabled()) {
@@ -1119,6 +1176,7 @@
}
}
super.setEnabled(enabled);
+ prepareCursorControllers();
}
/**
@@ -1410,6 +1468,40 @@
}
/**
+ * Returns the start padding of the view, plus space for the start
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getCompoundPaddingStart() {
+ resolveDrawables();
+ switch(getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ return getCompoundPaddingLeft();
+ case LAYOUT_DIRECTION_RTL:
+ return getCompoundPaddingRight();
+ }
+ }
+
+ /**
+ * Returns the end padding of the view, plus space for the end
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getCompoundPaddingEnd() {
+ resolveDrawables();
+ switch(getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ return getCompoundPaddingRight();
+ case LAYOUT_DIRECTION_RTL:
+ return getCompoundPaddingLeft();
+ }
+ }
+
+ /**
* Returns the extended top padding of the view, including both the
* top Drawable if any and any extra space to keep more than maxLines
* of text from showing. It is only valid to call this after measuring.
@@ -1492,6 +1584,26 @@
}
/**
+ * Returns the total start padding of the view, including the start
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getTotalPaddingStart() {
+ return getCompoundPaddingStart();
+ }
+
+ /**
+ * Returns the total end padding of the view, including the end
+ * Drawable if any.
+ *
+ * @hide
+ */
+ public int getTotalPaddingEnd() {
+ return getCompoundPaddingEnd();
+ }
+
+ /**
* Returns the total top padding of the view, including the top
* Drawable if any, the extra space to keep more than maxLines
* from showing, and the vertical offset for gravity, if any.
@@ -1678,6 +1790,185 @@
}
/**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use null if you do not
+ * want a Drawable there. The Drawables must already have had
+ * {@link Drawable#setBounds} called.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelative(Drawable start, Drawable top,
+ Drawable end, Drawable bottom) {
+ Drawables dr = mDrawables;
+
+ final boolean drawables = start != null || top != null
+ || end != null || bottom != null;
+
+ if (!drawables) {
+ // Clearing drawables... can we free the data structure?
+ if (dr != null) {
+ if (dr.mDrawablePadding == 0) {
+ mDrawables = null;
+ } else {
+ // We need to retain the last set padding, so just clear
+ // out all of the fields in the existing structure.
+ if (dr.mDrawableStart != null) dr.mDrawableStart.setCallback(null);
+ dr.mDrawableStart = null;
+ if (dr.mDrawableTop != null) dr.mDrawableTop.setCallback(null);
+ dr.mDrawableTop = null;
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.setCallback(null);
+ dr.mDrawableEnd = null;
+ if (dr.mDrawableBottom != null) dr.mDrawableBottom.setCallback(null);
+ dr.mDrawableBottom = null;
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+ dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+ }
+ }
+ } else {
+ if (dr == null) {
+ mDrawables = dr = new Drawables();
+ }
+
+ if (dr.mDrawableStart != start && dr.mDrawableStart != null) {
+ dr.mDrawableStart.setCallback(null);
+ }
+ dr.mDrawableStart = start;
+
+ if (dr.mDrawableTop != top && dr.mDrawableTop != null) {
+ dr.mDrawableTop.setCallback(null);
+ }
+ dr.mDrawableTop = top;
+
+ if (dr.mDrawableEnd != end && dr.mDrawableEnd != null) {
+ dr.mDrawableEnd.setCallback(null);
+ }
+ dr.mDrawableEnd = end;
+
+ if (dr.mDrawableBottom != bottom && dr.mDrawableBottom != null) {
+ dr.mDrawableBottom.setCallback(null);
+ }
+ dr.mDrawableBottom = bottom;
+
+ final Rect compoundRect = dr.mCompoundRect;
+ int[] state;
+
+ state = getDrawableState();
+
+ if (start != null) {
+ start.setState(state);
+ start.copyBounds(compoundRect);
+ start.setCallback(this);
+ dr.mDrawableSizeStart = compoundRect.width();
+ dr.mDrawableHeightStart = compoundRect.height();
+ } else {
+ dr.mDrawableSizeStart = dr.mDrawableHeightStart = 0;
+ }
+
+ if (end != null) {
+ end.setState(state);
+ end.copyBounds(compoundRect);
+ end.setCallback(this);
+ dr.mDrawableSizeEnd = compoundRect.width();
+ dr.mDrawableHeightEnd = compoundRect.height();
+ } else {
+ dr.mDrawableSizeEnd = dr.mDrawableHeightEnd = 0;
+ }
+
+ if (top != null) {
+ top.setState(state);
+ top.copyBounds(compoundRect);
+ top.setCallback(this);
+ dr.mDrawableSizeTop = compoundRect.height();
+ dr.mDrawableWidthTop = compoundRect.width();
+ } else {
+ dr.mDrawableSizeTop = dr.mDrawableWidthTop = 0;
+ }
+
+ if (bottom != null) {
+ bottom.setState(state);
+ bottom.copyBounds(compoundRect);
+ bottom.setCallback(this);
+ dr.mDrawableSizeBottom = compoundRect.height();
+ dr.mDrawableWidthBottom = compoundRect.width();
+ } else {
+ dr.mDrawableSizeBottom = dr.mDrawableWidthBottom = 0;
+ }
+ }
+
+ resolveDrawables();
+ invalidate();
+ requestLayout();
+ }
+
+ /**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use 0 if you do not
+ * want a Drawable there. The Drawables' bounds will be set to
+ * their intrinsic bounds.
+ *
+ * @param start Resource identifier of the start Drawable.
+ * @param top Resource identifier of the top Drawable.
+ * @param end Resource identifier of the end Drawable.
+ * @param bottom Resource identifier of the bottom Drawable.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end,
+ int bottom) {
+ resetResolvedDrawables();
+ final Resources resources = getContext().getResources();
+ setCompoundDrawablesRelativeWithIntrinsicBounds(
+ start != 0 ? resources.getDrawable(start) : null,
+ top != 0 ? resources.getDrawable(top) : null,
+ end != 0 ? resources.getDrawable(end) : null,
+ bottom != 0 ? resources.getDrawable(bottom) : null);
+ }
+
+ /**
+ * Sets the Drawables (if any) to appear to the start of, above,
+ * to the end of, and below the text. Use null if you do not
+ * want a Drawable there. The Drawables' bounds will be set to
+ * their intrinsic bounds.
+ *
+ * @attr ref android.R.styleable#TextView_drawableStart
+ * @attr ref android.R.styleable#TextView_drawableTop
+ * @attr ref android.R.styleable#TextView_drawableEnd
+ * @attr ref android.R.styleable#TextView_drawableBottom
+ *
+ * @hide
+ */
+ public void setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable start, Drawable top,
+ Drawable end, Drawable bottom) {
+
+ resetResolvedDrawables();
+ if (start != null) {
+ start.setBounds(0, 0, start.getIntrinsicWidth(), start.getIntrinsicHeight());
+ }
+ if (end != null) {
+ end.setBounds(0, 0, end.getIntrinsicWidth(), end.getIntrinsicHeight());
+ }
+ if (top != null) {
+ top.setBounds(0, 0, top.getIntrinsicWidth(), top.getIntrinsicHeight());
+ }
+ if (bottom != null) {
+ bottom.setBounds(0, 0, bottom.getIntrinsicWidth(), bottom.getIntrinsicHeight());
+ }
+ setCompoundDrawablesRelative(start, top, end, bottom);
+ }
+
+ /**
* Returns drawables for the left, top, right, and bottom borders.
*/
public Drawable[] getCompoundDrawables() {
@@ -1692,6 +1983,22 @@
}
/**
+ * Returns drawables for the start, top, end, and bottom borders.
+ *
+ * @hide
+ */
+ public Drawable[] getCompoundDrawablesRelative() {
+ final Drawables dr = mDrawables;
+ if (dr != null) {
+ return new Drawable[] {
+ dr.mDrawableStart, dr.mDrawableTop, dr.mDrawableEnd, dr.mDrawableBottom
+ };
+ } else {
+ return new Drawable[] { null, null, null, null };
+ }
+ }
+
+ /**
* Sets the size of the padding between the compound drawables and
* the text.
*
@@ -2494,6 +2801,12 @@
if (dr.mDrawableRight != null && dr.mDrawableRight.isStateful()) {
dr.mDrawableRight.setState(state);
}
+ if (dr.mDrawableStart != null && dr.mDrawableStart.isStateful()) {
+ dr.mDrawableStart.setState(state);
+ }
+ if (dr.mDrawableEnd != null && dr.mDrawableEnd.isStateful()) {
+ dr.mDrawableEnd.setState(state);
+ }
}
}
@@ -2841,8 +3154,7 @@
// Do not change the movement method for text that support text selection as it
// would prevent an arbitrary cursor displacement.
- final boolean hasTextSelection = this instanceof EditText || mTextIsSelectable;
- if (mLinksClickable && !hasTextSelection) {
+ if (mLinksClickable && !textCanBeSelected()) {
setMovementMethod(LinkMovementMethod.getInstance());
}
}
@@ -3546,7 +3858,17 @@
mErrorWasChanged = true;
final Drawables dr = mDrawables;
if (dr != null) {
- setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon, dr.mDrawableBottom);
+ switch (getResolvedLayoutDirection()) {
+ default:
+ case LAYOUT_DIRECTION_LTR:
+ setCompoundDrawables(dr.mDrawableLeft, dr.mDrawableTop, icon,
+ dr.mDrawableBottom);
+ break;
+ case LAYOUT_DIRECTION_RTL:
+ setCompoundDrawables(icon, dr.mDrawableTop, dr.mDrawableRight,
+ dr.mDrawableBottom);
+ break;
+ }
} else {
setCompoundDrawables(null, null, icon, null);
}
@@ -4048,6 +4370,9 @@
if (mSelectionModifierCursorController != null) {
observer.addOnTouchModeChangeListener(mSelectionModifierCursorController);
}
+
+ // Resolve drawables as the layout direction has been resolved
+ resolveDrawables();
}
@Override
@@ -4077,6 +4402,8 @@
}
hideControllers();
+
+ resetResolvedDrawables();
}
@Override
@@ -4111,7 +4438,8 @@
final boolean verified = super.verifyDrawable(who);
if (!verified && mDrawables != null) {
return who == mDrawables.mDrawableLeft || who == mDrawables.mDrawableTop ||
- who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom;
+ who == mDrawables.mDrawableRight || who == mDrawables.mDrawableBottom ||
+ who == mDrawables.mDrawableStart || who == mDrawables.mDrawableEnd;
}
return verified;
}
@@ -4132,6 +4460,12 @@
if (mDrawables.mDrawableBottom != null) {
mDrawables.mDrawableBottom.jumpToCurrentState();
}
+ if (mDrawables.mDrawableStart != null) {
+ mDrawables.mDrawableStart.jumpToCurrentState();
+ }
+ if (mDrawables.mDrawableEnd != null) {
+ mDrawables.mDrawableEnd.jumpToCurrentState();
+ }
}
}
@@ -4192,7 +4526,8 @@
if (mDrawables != null) {
final Drawables drawables = mDrawables;
if (who == drawables.mDrawableLeft || who == drawables.mDrawableRight ||
- who == drawables.mDrawableTop || who == drawables.mDrawableBottom) {
+ who == drawables.mDrawableTop || who == drawables.mDrawableBottom ||
+ who == drawables.mDrawableStart || who == drawables.mDrawableEnd) {
return getResolvedLayoutDirection();
}
}
@@ -4211,6 +4546,8 @@
if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha);
if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha);
if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha);
+ if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha);
+ if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha);
}
return true;
}
@@ -4228,7 +4565,9 @@
* {@link android.R.styleable#TextView_textIsSelectable} XML attribute to make this TextView
* selectable (text is not selectable by default).
*
- * Note that the content of an EditText is always selectable.
+ * Note that this method simply returns the state of this flag. Although this flag has to be set
+ * in order to select text in non-editable TextView, the content of an {@link EditText} can
+ * always be selected, independently of the value of this flag.
*
* @return True if the text displayed in this TextView can be selected by the user.
*
@@ -4465,12 +4804,12 @@
selStart = getSelectionStart();
selEnd = getSelectionEnd();
- if ((isCursorVisible() || mTextIsSelectable) && selStart >= 0 && isEnabled()) {
+ if (selStart >= 0) {
if (mHighlightPath == null)
mHighlightPath = new Path();
if (selStart == selEnd) {
- if (!mTextIsSelectable &&
+ if (isCursorVisible() &&
(SystemClock.uptimeMillis() - mShowCursor) % (2 * BLINK) < BLINK) {
if (mHighlightPathBogus) {
mHighlightPath.reset();
@@ -4489,7 +4828,7 @@
highlight = mHighlightPath;
drawCursor = mCursorCount > 0;
}
- } else {
+ } else if (textCanBeSelected()) {
if (mHighlightPathBogus) {
mHighlightPath.reset();
mLayout.getSelectionPath(selStart, selEnd, mHighlightPath);
@@ -5500,6 +5839,7 @@
if (curs >= 0) {
mHighlightPathBogus = true;
makeBlink();
+ bringPointIntoView(curs);
}
checkForResize();
@@ -5660,14 +6000,17 @@
Layout.Alignment alignment = getLayoutAlignment();
boolean shouldEllipsize = mEllipsize != null && mInput == null;
+ if (mTextDir == null) {
+ resolveTextDirection();
+ }
if (mText instanceof Spannable) {
mLayout = new DynamicLayout(mText, mTransformed, mTextPaint, w,
- alignment, mSpacingMult,
+ alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mInput == null ? mEllipsize : null,
ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
- boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring);
+ boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
if (boring != null) {
mBoring = boring;
}
@@ -5704,23 +6047,23 @@
} else if (shouldEllipsize) {
mLayout = new StaticLayout(mTransformed,
0, mTransformed.length(),
- mTextPaint, w, alignment, mSpacingMult,
+ mTextPaint, w, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mEllipsize,
ellipsisWidth);
} else {
mLayout = new StaticLayout(mTransformed, mTextPaint,
- w, alignment, mSpacingMult, mSpacingAdd,
+ w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
} else if (shouldEllipsize) {
mLayout = new StaticLayout(mTransformed,
0, mTransformed.length(),
- mTextPaint, w, alignment, mSpacingMult,
+ mTextPaint, w, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mEllipsize,
ellipsisWidth);
} else {
mLayout = new StaticLayout(mTransformed, mTextPaint,
- w, alignment, mSpacingMult, mSpacingAdd,
+ w, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
}
@@ -5732,7 +6075,7 @@
if (shouldEllipsize) hintWidth = w;
if (hintBoring == UNKNOWN_BORING) {
- hintBoring = BoringLayout.isBoring(mHint, mTextPaint,
+ hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
mHintBoring);
if (hintBoring != null) {
mHintBoring = hintBoring;
@@ -5770,23 +6113,23 @@
} else if (shouldEllipsize) {
mHintLayout = new StaticLayout(mHint,
0, mHint.length(),
- mTextPaint, hintWidth, alignment, mSpacingMult,
+ mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mEllipsize,
ellipsisWidth);
} else {
mHintLayout = new StaticLayout(mHint, mTextPaint,
- hintWidth, alignment, mSpacingMult, mSpacingAdd,
+ hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
} else if (shouldEllipsize) {
mHintLayout = new StaticLayout(mHint,
0, mHint.length(),
- mTextPaint, hintWidth, alignment, mSpacingMult,
+ mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
mSpacingAdd, mIncludePad, mEllipsize,
ellipsisWidth);
} else {
mHintLayout = new StaticLayout(mHint, mTextPaint,
- hintWidth, alignment, mSpacingMult, mSpacingAdd,
+ hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
mIncludePad);
}
}
@@ -5887,6 +6230,10 @@
BoringLayout.Metrics boring = UNKNOWN_BORING;
BoringLayout.Metrics hintBoring = UNKNOWN_BORING;
+ if (mTextDir == null) {
+ resolveTextDirection();
+ }
+
int des = -1;
boolean fromexisting = false;
@@ -5899,7 +6246,7 @@
}
if (des < 0) {
- boring = BoringLayout.isBoring(mTransformed, mTextPaint, mBoring);
+ boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
if (boring != null) {
mBoring = boring;
}
@@ -6212,6 +6559,15 @@
int scrollx, scrolly;
+ // Convert to left, center, or right alignment.
+ if (a == Layout.Alignment.ALIGN_NORMAL) {
+ a = dir == Layout.DIR_LEFT_TO_RIGHT ? Layout.Alignment.ALIGN_LEFT :
+ Layout.Alignment.ALIGN_RIGHT;
+ } else if (a == Layout.Alignment.ALIGN_OPPOSITE){
+ a = dir == Layout.DIR_LEFT_TO_RIGHT ? Layout.Alignment.ALIGN_RIGHT :
+ Layout.Alignment.ALIGN_LEFT;
+ }
+
if (a == Layout.Alignment.ALIGN_CENTER) {
/*
* Keep centered if possible, or, if it is too wide to fit,
@@ -6230,28 +6586,11 @@
scrollx = left;
}
}
- } else if (a == Layout.Alignment.ALIGN_NORMAL) {
- /*
- * Keep leading edge in view.
- */
-
- if (dir < 0) {
- int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
- scrollx = right - hspace;
- } else {
- scrollx = (int) FloatMath.floor(mLayout.getLineLeft(line));
- }
- } else /* a == Layout.Alignment.ALIGN_OPPOSITE */ {
- /*
- * Keep trailing edge in view.
- */
-
- if (dir < 0) {
- scrollx = (int) FloatMath.floor(mLayout.getLineLeft(line));
- } else {
- int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
- scrollx = right - hspace;
- }
+ } else if (a == Layout.Alignment.ALIGN_RIGHT) {
+ int right = (int) FloatMath.ceil(mLayout.getLineRight(line));
+ scrollx = right - hspace;
+ } else { // a == Layout.Alignment.ALIGN_LEFT (will also be the default)
+ scrollx = (int) FloatMath.floor(mLayout.getLineLeft(line));
}
if (ht < vspace) {
@@ -6279,6 +6618,8 @@
public boolean bringPointIntoView(int offset) {
boolean changed = false;
+ if (mLayout == null) return changed;
+
int line = mLayout.getLineForOffset(offset);
// FIXME: Is it okay to truncate this, or should we round?
@@ -6293,20 +6634,24 @@
int grav;
switch (mLayout.getParagraphAlignment(line)) {
- case ALIGN_NORMAL:
+ case ALIGN_LEFT:
grav = 1;
break;
-
- case ALIGN_OPPOSITE:
+ case ALIGN_RIGHT:
grav = -1;
break;
-
+ case ALIGN_NORMAL:
+ grav = mLayout.getParagraphDirection(line);
+ break;
+ case ALIGN_OPPOSITE:
+ grav = -mLayout.getParagraphDirection(line);
+ break;
+ case ALIGN_CENTER:
default:
grav = 0;
+ break;
}
- grav *= mLayout.getParagraphDirection(line);
-
int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight();
int vspace = mBottom - mTop - getExtendedPaddingTop() - getExtendedPaddingBottom();
@@ -7454,9 +7799,6 @@
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
- if (hasInsertionController()) {
- getInsertionController().onTouchEvent(event);
- }
if (hasSelectionController()) {
getSelectionController().onTouchEvent(event);
}
@@ -7884,7 +8226,8 @@
// prepareCursorController() relies on this method.
// If you change this condition, make sure prepareCursorController is called anywhere
// the value of this condition might be changed.
- return mText instanceof Spannable && mMovement != null && mMovement.canSelectArbitrarily();
+ if (mMovement == null || !mMovement.canSelectArbitrarily()) return false;
+ return isTextEditable() || (mTextIsSelectable && mText instanceof Spannable && isEnabled());
}
private boolean canCut() {
@@ -7972,6 +8315,10 @@
final int minOffset = extractRangeStartFromLong(lastTouchOffsets);
final int maxOffset = extractRangeEndFromLong(lastTouchOffsets);
+ // Safety check in case standard touch event handling has been bypassed
+ if (minOffset < 0 || minOffset >= mText.length()) return false;
+ if (maxOffset < 0 || maxOffset >= mText.length()) return false;
+
int selectionStart, selectionEnd;
// If a URLSpan (web address, email, phone...) is found at that position, select it.
@@ -9111,7 +9458,7 @@
@Override
public void onClick(View v) {
if (canPaste()) {
- paste(getSelectionStart(), getSelectionEnd());
+ onTextContextMenuItem(ID_PASTE);
}
hide();
}
@@ -9727,13 +10074,6 @@
public void hide();
/**
- * This method is called by {@link #onTouchEvent(MotionEvent)} and gives the controller
- * a chance to become active and/or visible.
- * @param event The touch event
- */
- public boolean onTouchEvent(MotionEvent event);
-
- /**
* Called when the view is detached from window. Perform house keeping task, such as
* stopping Runnable thread that would otherwise keep a reference on the context, thus
* preventing the activity from being recycled.
@@ -9760,10 +10100,6 @@
}
}
- public boolean onTouchEvent(MotionEvent ev) {
- return false;
- }
-
public void onTouchModeChanged(boolean isInTouchMode) {
if (!isInTouchMode) {
hide();
@@ -9822,52 +10158,49 @@
if (mEndHandle != null) mEndHandle.hide();
}
- public boolean onTouchEvent(MotionEvent event) {
+ public void onTouchEvent(MotionEvent event) {
// This is done even when the View does not have focus, so that long presses can start
// selection and tap can move cursor from this tap position.
- if (isTextEditable() || mTextIsSelectable) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- final float x = event.getX();
- final float y = event.getY();
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ final float x = event.getX();
+ final float y = event.getY();
- // Remember finger down position, to be able to start selection from there
- mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y);
+ // Remember finger down position, to be able to start selection from there
+ mMinTouchOffset = mMaxTouchOffset = getOffsetForPosition(x, y);
- // Double tap detection
- long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
- if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
- isPositionOnText(x, y)) {
- final float deltaX = x - mPreviousTapPositionX;
- final float deltaY = y - mPreviousTapPositionY;
- final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
- if (distanceSquared < mSquaredTouchSlopDistance) {
- showSuggestions();
- mDiscardNextActionUp = true;
- }
+ // Double tap detection
+ long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
+ if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
+ isPositionOnText(x, y)) {
+ final float deltaX = x - mPreviousTapPositionX;
+ final float deltaY = y - mPreviousTapPositionY;
+ final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+ if (distanceSquared < mSquaredTouchSlopDistance) {
+ showSuggestions();
+ mDiscardNextActionUp = true;
}
+ }
- mPreviousTapPositionX = x;
- mPreviousTapPositionY = y;
+ mPreviousTapPositionX = x;
+ mPreviousTapPositionY = y;
- break;
+ break;
- case MotionEvent.ACTION_POINTER_DOWN:
- case MotionEvent.ACTION_POINTER_UP:
- // Handle multi-point gestures. Keep min and max offset positions.
- // Only activated for devices that correctly handle multi-touch.
- if (mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) {
- updateMinAndMaxOffsets(event);
- }
- break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ case MotionEvent.ACTION_POINTER_UP:
+ // Handle multi-point gestures. Keep min and max offset positions.
+ // Only activated for devices that correctly handle multi-touch.
+ if (mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)) {
+ updateMinAndMaxOffsets(event);
+ }
+ break;
- case MotionEvent.ACTION_UP:
- mPreviousTapUpTime = SystemClock.uptimeMillis();
- break;
- }
+ case MotionEvent.ACTION_UP:
+ mPreviousTapUpTime = SystemClock.uptimeMillis();
+ break;
}
- return false;
}
/**
@@ -10123,11 +10456,21 @@
return mInBatchEditControllers;
}
+ private class TextViewDirectionHeuristic extends TextDirectionHeuristicImpl {
+ private TextViewDirectionHeuristic(TextDirectionAlgorithm algorithm) {
+ super(algorithm);
+ }
+ @Override
+ protected boolean defaultIsRtl() {
+ return getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL;
+ }
+ }
+
/**
* Resolve the text direction.
*
* Text direction of paragraphs in a TextView is determined using a heuristic. If the correct
- * text direction cannot be determined by the heuristic, the view’s resolved layout direction
+ * text direction cannot be determined by the heuristic, the view's resolved layout direction
* determines the direction.
*
* This heuristic and result is applied individually to each paragraph in a TextView, based on
@@ -10136,157 +10479,89 @@
*/
@Override
protected void resolveTextDirection() {
- int resolvedTextDirection = TEXT_DIRECTION_UNDEFINED;
- switch(mTextDirection) {
+ super.resolveTextDirection();
+
+ int textDir = getResolvedTextDirection();
+ switch (textDir) {
default:
- case TEXT_DIRECTION_INHERIT:
- // Try to the text direction from the parent layout. If not possible, then we will
- // use the default layout direction to decide later
- if (mParent != null && mParent instanceof ViewGroup) {
- resolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
- }
- break;
case TEXT_DIRECTION_FIRST_STRONG:
- resolvedTextDirection = getTextDirectionFromFirstStrong(mText);
+ mTextDir = new TextViewDirectionHeuristic(FirstStrong.INSTANCE);
break;
case TEXT_DIRECTION_ANY_RTL:
- resolvedTextDirection = getTextDirectionFromAnyRtl(mText);
+ mTextDir = new TextViewDirectionHeuristic(AnyStrong.INSTANCE_RTL);
break;
case TEXT_DIRECTION_CHAR_COUNT:
- resolvedTextDirection = getTextDirectionFromCharCount(mText);
+ mTextDir = new TextViewDirectionHeuristic(CharCount.INSTANCE_DEFAULT);
break;
case TEXT_DIRECTION_LTR:
- resolvedTextDirection = TEXT_DIRECTION_LTR;
+ mTextDir = TextDirectionHeuristics.LTR;
break;
case TEXT_DIRECTION_RTL:
- resolvedTextDirection = TEXT_DIRECTION_RTL;
+ mTextDir = TextDirectionHeuristics.RTL;
break;
}
- // if we have been so far unable to get the text direction from the heuristics, then we are
- // falling back using the layout direction
- if (resolvedTextDirection == TEXT_DIRECTION_UNDEFINED) {
- switch(getResolvedLayoutDirection()) {
- default:
- case LAYOUT_DIRECTION_LTR:
- resolvedTextDirection = TEXT_DIRECTION_LTR;
- break;
- case LAYOUT_DIRECTION_RTL:
- resolvedTextDirection = TEXT_DIRECTION_RTL;
- break;
- }
- }
- mResolvedTextDirection = resolvedTextDirection;
}
/**
- * Get text direction following the "first strong" heuristic.
+ * Subclasses will need to override this method to implement their own way of resolving
+ * drawables depending on the layout direction.
*
- * @param cs the CharSequence used to get the text direction.
+ * A call to the super method will be required from the subclasses implementation.
*
- * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
- * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
*/
- private static int getTextDirectionFromFirstStrong(final CharSequence cs) {
- final int length = cs.length();
- if (length == 0) {
- return TEXT_DIRECTION_UNDEFINED;
+ protected void resolveDrawables() {
+ // No need to resolve twice
+ if (bResolvedDrawables) {
+ return;
}
- for(int i = 0; i < length; i++) {
- final char c = cs.charAt(i);
- final byte dir = Character.getDirectionality(c);
- if (isStrongLtrChar(dir)) {
- return TEXT_DIRECTION_LTR;
- } else if (isStrongRtlChar(dir)) {
- return TEXT_DIRECTION_RTL;
- }
+ // No drawable to resolve
+ if (mDrawables == null) {
+ return;
}
- return TEXT_DIRECTION_UNDEFINED;
- }
+ // No relative drawable to resolve
+ if (mDrawables.mDrawableStart == null && mDrawables.mDrawableEnd == null) {
+ bResolvedDrawables = true;
+ return;
+ }
- /**
- * Get text direction following the "any RTL" heuristic.
- *
- * @param cs the CharSequence used to get the text direction.
- *
- * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
- * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
- */
- private static int getTextDirectionFromAnyRtl(final CharSequence cs) {
- final int length = cs.length();
- if (length == 0) {
- return TEXT_DIRECTION_UNDEFINED;
- }
- boolean foundStrongLtr = false;
- boolean foundStrongRtl = false;
- for(int i = 0; i < length; i++) {
- final char c = cs.charAt(i);
- final byte dir = Character.getDirectionality(c);
- if (isStrongLtrChar(dir)) {
- foundStrongLtr = true;
- } else if (isStrongRtlChar(dir)) {
- foundStrongRtl = true;
+ Drawables dr = mDrawables;
+ switch(getResolvedLayoutDirection()) {
+ case LAYOUT_DIRECTION_RTL:
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableRight = dr.mDrawableStart;
+
+ dr.mDrawableSizeRight = dr.mDrawableSizeStart;
+ dr.mDrawableHeightRight = dr.mDrawableHeightStart;
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableLeft = dr.mDrawableEnd;
+
+ dr.mDrawableSizeLeft = dr.mDrawableSizeEnd;
+ dr.mDrawableHeightLeft = dr.mDrawableHeightEnd;
+ }
break;
- }
+
+ case LAYOUT_DIRECTION_LTR:
+ default:
+ if (dr.mDrawableStart != null) {
+ dr.mDrawableLeft = dr.mDrawableStart;
+
+ dr.mDrawableSizeLeft = dr.mDrawableSizeStart;
+ dr.mDrawableHeightLeft = dr.mDrawableHeightStart;
+ }
+ if (dr.mDrawableEnd != null) {
+ dr.mDrawableRight = dr.mDrawableEnd;
+
+ dr.mDrawableSizeRight = dr.mDrawableSizeEnd;
+ dr.mDrawableHeightRight = dr.mDrawableHeightEnd;
+ }
+ break;
}
- if (foundStrongRtl) {
- return TEXT_DIRECTION_RTL;
- }
- if (foundStrongLtr) {
- return TEXT_DIRECTION_LTR;
- }
- return TEXT_DIRECTION_UNDEFINED;
+ bResolvedDrawables = true;
}
- /**
- * Get text direction following the "char count" heuristic.
- *
- * @param cs the CharSequence used to get the text direction.
- *
- * @return {@link #TEXT_DIRECTION_RTL} if direction it RTL, {@link #TEXT_DIRECTION_LTR} if
- * direction it LTR or {@link #TEXT_DIRECTION_UNDEFINED} if direction cannot be found.
- */
- private int getTextDirectionFromCharCount(CharSequence cs) {
- final int length = cs.length();
- if (length == 0) {
- return TEXT_DIRECTION_UNDEFINED;
- }
- int countLtr = 0;
- int countRtl = 0;
- for(int i = 0; i < length; i++) {
- final char c = cs.charAt(i);
- final byte dir = Character.getDirectionality(c);
- if (isStrongLtrChar(dir)) {
- countLtr++;
- } else if (isStrongRtlChar(dir)) {
- countRtl++;
- }
- }
- final float percentLtr = ((float) countLtr) / (countLtr + countRtl);
- if (percentLtr > DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD) {
- return TEXT_DIRECTION_LTR;
- }
- final float percentRtl = ((float) countRtl) / (countLtr + countRtl);
- if (percentRtl > DEFAULT_TEXT_DIRECTION_CHAR_COUNT_THRESHOLD) {
- return TEXT_DIRECTION_RTL;
- }
- return TEXT_DIRECTION_UNDEFINED;
- }
-
- /**
- * Return true if the char direction is corresponding to a "strong RTL char" following the
- * Unicode Bidirectional Algorithm (UBA).
- */
- private static boolean isStrongRtlChar(final byte dir) {
- return (dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
- dir == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC);
- }
-
- /**
- * Return true if the char direction is corresponding to a "strong LTR char" following the
- * Unicode Bidirectional Algorithm (UBA).
- */
- private static boolean isStrongLtrChar(final byte dir) {
- return (dir == Character.DIRECTIONALITY_LEFT_TO_RIGHT);
+ protected void resetResolvedDrawables() {
+ bResolvedDrawables = false;
}
@ViewDebug.ExportedProperty(category = "text")
@@ -10390,6 +10665,8 @@
private BoringLayout mSavedLayout, mSavedHintLayout;
+ private TextDirectionHeuristic mTextDir = null;
+
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
private InputFilter[] mFilters = NO_FILTERS;
private static final Spanned EMPTY_SPANNED = new SpannedString("");
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 423e735c..0547438 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -20,6 +20,7 @@
import android.annotation.Widget;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +33,7 @@
import java.text.DateFormatSymbols;
import java.util.Calendar;
+import java.util.Locale;
/**
* A view for selecting the time of day, in either 24 hour or AM/PM mode. The
@@ -92,6 +94,8 @@
private Calendar mTempCalendar;
+ private Locale mCurrentLocale;
+
/**
* The callback interface used to indicate the time has been adjusted.
*/
@@ -116,6 +120,9 @@
public TimePicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ // initialization based on locale
+ setCurrentLocale(Locale.getDefault());
+
// process style attributes
TypedArray attributesArray = context.obtainStyledAttributes(
attrs, R.styleable.TimePicker, defStyle, 0);
@@ -211,8 +218,6 @@
updateHourControl();
updateAmPmControl();
- // initialize to current time
- mTempCalendar = Calendar.getInstance();
setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
// set to current time
@@ -248,6 +253,25 @@
return mIsEnabled;
}
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ setCurrentLocale(newConfig.locale);
+ }
+
+ /**
+ * Sets the current locale.
+ *
+ * @param locale The current locale.
+ */
+ private void setCurrentLocale(Locale locale) {
+ if (locale.equals(mCurrentLocale)) {
+ return;
+ }
+ mCurrentLocale = locale;
+ mTempCalendar = Calendar.getInstance(locale);
+ }
+
/**
* Used to save / restore state of time picker
*/
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 519acf5..f0a9441 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -36,6 +36,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Handler;
import android.view.ActionMode;
import android.view.LayoutInflater;
@@ -155,6 +156,11 @@
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
mContentHeight = mActionView.getContentHeight();
+
+ // Older apps get the home button interaction enabled by default.
+ // Newer apps need to enable it explicitly.
+ setHomeButtonEnabled(mContext.getApplicationInfo().targetSdkVersion <
+ Build.VERSION_CODES.ICE_CREAM_SANDWICH);
}
public void onConfigurationChanged(Configuration newConfig) {
@@ -266,8 +272,8 @@
}
@Override
- public void setDisplayDisableHomeEnabled(boolean disableHome) {
- setDisplayOptions(disableHome ? DISPLAY_DISABLE_HOME : 0, DISPLAY_DISABLE_HOME);
+ public void setHomeButtonEnabled(boolean enable) {
+ mActionView.setHomeButtonEnabled(enable);
}
@Override
@@ -492,7 +498,7 @@
@Override
public int getHeight() {
- return mActionView.getHeight();
+ return mContainerView.getHeight();
}
@Override
diff --git a/core/java/com/android/internal/app/NetInitiatedActivity.java b/core/java/com/android/internal/app/NetInitiatedActivity.java
index 6039cc2..e1166f1 100755
--- a/core/java/com/android/internal/app/NetInitiatedActivity.java
+++ b/core/java/com/android/internal/app/NetInitiatedActivity.java
@@ -23,6 +23,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.widget.Toast;
import android.util.Log;
import android.location.LocationManager;
@@ -44,8 +46,12 @@
private static final int POSITIVE_BUTTON = AlertDialog.BUTTON_POSITIVE;
private static final int NEGATIVE_BUTTON = AlertDialog.BUTTON_NEGATIVE;
+ private static final int GPS_NO_RESPONSE_TIME_OUT = 1;
// Received ID from intent, -1 when no notification is in progress
private int notificationId = -1;
+ private int timeout = -1;
+ private int default_response = -1;
+ private int default_response_timeout = 6;
/** Used to detect when NI request is received */
private BroadcastReceiver mNetInitiatedReceiver = new BroadcastReceiver() {
@@ -58,6 +64,21 @@
}
};
+ private final Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case GPS_NO_RESPONSE_TIME_OUT: {
+ if (notificationId != -1) {
+ sendUserResponse(default_response);
+ }
+ finish();
+ }
+ break;
+ default:
+ }
+ }
+ };
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -75,8 +96,11 @@
p.mNegativeButtonListener = this;
notificationId = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_NOTIF_ID, -1);
- if (DEBUG) Log.d(TAG, "onCreate, notifId: " + notificationId);
+ timeout = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_TIMEOUT, default_response_timeout);
+ default_response = intent.getIntExtra(GpsNetInitiatedHandler.NI_INTENT_KEY_DEFAULT_RESPONSE, GpsNetInitiatedHandler.GPS_NI_RESPONSE_ACCEPT);
+ if (DEBUG) Log.d(TAG, "onCreate() : notificationId: " + notificationId + " timeout: " + timeout + " default_response:" + default_response);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(GPS_NO_RESPONSE_TIME_OUT), (timeout * 1000));
setupAlert();
}
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
index 1ac191b..8c2c405 100755
--- a/core/java/com/android/internal/os/PkgUsageStats.java
+++ b/core/java/com/android/internal/os/PkgUsageStats.java
@@ -19,6 +19,9 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* implementation of PkgUsageStats associated with an
* application package.
@@ -28,6 +31,7 @@
public String packageName;
public int launchCount;
public long usageTime;
+ public Map<String, Long> componentResumeTimes;
public static final Parcelable.Creator<PkgUsageStats> CREATOR
= new Parcelable.Creator<PkgUsageStats>() {
@@ -46,31 +50,45 @@
+ " " + packageName + "}";
}
- public PkgUsageStats(String pkgName, int count, long time) {
+ public PkgUsageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
packageName = pkgName;
launchCount = count;
usageTime = time;
+ componentResumeTimes = new HashMap<String, Long>(lastResumeTimes);
}
public PkgUsageStats(Parcel source) {
packageName = source.readString();
launchCount = source.readInt();
usageTime = source.readLong();
+ final int N = source.readInt();
+ componentResumeTimes = new HashMap<String, Long>(N);
+ for (int i = 0; i < N; i++) {
+ String component = source.readString();
+ long lastResumeTime = source.readLong();
+ componentResumeTimes.put(component, lastResumeTime);
+ }
}
public PkgUsageStats(PkgUsageStats pStats) {
packageName = pStats.packageName;
launchCount = pStats.launchCount;
usageTime = pStats.usageTime;
+ componentResumeTimes = new HashMap<String, Long>(pStats.componentResumeTimes);
}
public int describeContents() {
return 0;
}
- public void writeToParcel(Parcel dest, int parcelableFlags){
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(packageName);
dest.writeInt(launchCount);
dest.writeLong(usageTime);
+ dest.writeInt(componentResumeTimes.size());
+ for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
+ dest.writeString(ent.getKey());
+ dest.writeLong(ent.getValue());
+ }
}
}
diff --git a/services/java/com/android/server/ProcessStats.java b/core/java/com/android/internal/os/ProcessStats.java
similarity index 99%
rename from services/java/com/android/server/ProcessStats.java
rename to core/java/com/android/internal/os/ProcessStats.java
index f693ed1..ea5ce09 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/core/java/com/android/internal/os/ProcessStats.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.internal.os;
import static android.os.Process.*;
@@ -182,7 +182,7 @@
public String baseName;
public String name;
- int nameWidth;
+ public int nameWidth;
public long base_uptime;
public long rel_uptime;
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index a3b7795..9af7e96 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -900,6 +900,7 @@
}
}
+ boolean usingWrapper = false;
if (pipeFd != null && pid > 0) {
DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
int innerPid = -1;
@@ -924,6 +925,7 @@
if (parentPid > 0) {
Log.i(TAG, "Wrapped process has pid " + innerPid);
pid = innerPid;
+ usingWrapper = true;
} else {
Log.w(TAG, "Wrapped process reported a pid that is not a child of "
+ "the process that we forked: childPid=" + pid
@@ -934,6 +936,7 @@
try {
mSocketOutStream.writeInt(pid);
+ mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error reading from command socket", ex);
return true;
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index b754d94..69b80d9 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -40,6 +40,7 @@
/** Non system protocols */
public static final int BASE_WIFI = 0x00020000;
+ public static final int BASE_WIFI_WATCHDOG = 0x00021000;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index b86eb13..80f68ac 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -20,7 +20,8 @@
import android.content.Context;
import android.content.res.Resources;
-import android.util.Log;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.util.SparseBooleanArray;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
@@ -60,6 +61,9 @@
private OpenOverflowRunnable mPostedOpenRunnable;
+ final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
+ int mOpenSubMenuId;
+
public ActionMenuPresenter() {
super(com.android.internal.R.layout.action_menu_layout,
com.android.internal.R.layout.action_menu_item_layout);
@@ -196,8 +200,12 @@
topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
}
View anchor = findViewForItem(topSubMenu.getItem());
- if (anchor == null) return false;
+ if (anchor == null) {
+ if (mOverflowButton == null) return false;
+ anchor = mOverflowButton;
+ }
+ mOpenSubMenuId = subMenu.getItem().getItemId();
mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
mActionButtonPopup.setAnchorView(anchor);
mActionButtonPopup.show();
@@ -426,6 +434,57 @@
super.onCloseMenu(menu, allMenusAreClosing);
}
+ @Override
+ public Parcelable onSaveInstanceState() {
+ SavedState state = new SavedState();
+ state.openSubMenuId = mOpenSubMenuId;
+ return state;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ SavedState saved = (SavedState) state;
+ if (saved.openSubMenuId > 0) {
+ MenuItem item = mMenu.findItem(saved.openSubMenuId);
+ if (item != null) {
+ SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+ onSubMenuSelected(subMenu);
+ }
+ }
+ }
+
+ private static class SavedState implements Parcelable {
+ public int openSubMenuId;
+
+ SavedState() {
+ }
+
+ SavedState(Parcel in) {
+ openSubMenuId = in.readInt();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(openSubMenuId);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR
+ = new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
private class OverflowMenuButton extends ImageButton implements ActionMenuChildView {
public OverflowMenuButton(Context context) {
super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle);
@@ -460,6 +519,7 @@
public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
boolean overflowOnly) {
super(context, menu, anchorView, overflowOnly);
+ setCallback(mPopupPresenterCallback);
}
@Override
@@ -482,6 +542,19 @@
// Give a reasonable anchor to nested submenus.
setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
}
+
+ setCallback(mPopupPresenterCallback);
+
+ boolean preserveIconSpacing = false;
+ final int count = subMenu.size();
+ for (int i = 0; i < count; i++) {
+ MenuItem childItem = subMenu.getItem(i);
+ if (childItem.isVisible() && childItem.getIcon() != null) {
+ preserveIconSpacing = true;
+ break;
+ }
+ }
+ setForceShowIcon(preserveIconSpacing);
}
@Override
@@ -489,6 +562,20 @@
super.onDismiss();
mSubMenu.close();
mActionButtonPopup = null;
+ mOpenSubMenuId = 0;
+ }
+ }
+
+ private class PopupPresenterCallback implements MenuPresenter.Callback {
+
+ @Override
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
+ return false;
+ }
+
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
}
}
diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
index ddbb08c..ed9d34a 100644
--- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
@@ -39,6 +39,8 @@
protected MenuView mMenuView;
+ private int mId;
+
/**
* Construct a new BaseMenuPresenter.
*
@@ -200,4 +202,12 @@
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
return false;
}
+
+ public int getId() {
+ return mId;
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
}
diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
index f717904..d1b1dae 100644
--- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
@@ -23,6 +23,7 @@
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -35,7 +36,12 @@
private IconMenuItemView mMoreView;
private int mMaxItems = -1;
+ int mOpenSubMenuId;
+ SubMenuPresenterCallback mSubMenuPresenterCallback = new SubMenuPresenterCallback();
+ MenuDialogHelper mOpenSubMenu;
+
private static final String VIEWS_TAG = "android:menu:icon";
+ private static final String OPEN_SUBMENU_KEY = "android:menu:icon:submenu";
public IconMenuPresenter() {
super(com.android.internal.R.layout.icon_menu_layout,
@@ -86,7 +92,11 @@
if (!subMenu.hasVisibleItems()) return false;
// The window manager will give us a token.
- new MenuDialogHelper(subMenu).show(null);
+ MenuDialogHelper helper = new MenuDialogHelper(subMenu);
+ helper.setPresenterCallback(mSubMenuPresenterCallback);
+ helper.show(null);
+ mOpenSubMenu = helper;
+ mOpenSubMenuId = subMenu.getItem().getItemId();
super.onSubMenuSelected(subMenu);
return true;
}
@@ -137,5 +147,49 @@
if (viewStates != null) {
((View) mMenuView).restoreHierarchyState(viewStates);
}
+ int subMenuId = inState.getInt(OPEN_SUBMENU_KEY, 0);
+ if (subMenuId > 0 && mMenu != null) {
+ MenuItem item = mMenu.findItem(subMenuId);
+ if (item != null) {
+ onSubMenuSelected((SubMenuBuilder) item.getSubMenu());
+ }
+ }
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ if (mMenuView == null) {
+ return null;
+ }
+
+ Bundle state = new Bundle();
+ saveHierarchyState(state);
+ if (mOpenSubMenuId > 0) {
+ state.putInt(OPEN_SUBMENU_KEY, mOpenSubMenuId);
+ }
+ return state;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ restoreHierarchyState((Bundle) state);
+ }
+
+ class SubMenuPresenterCallback implements MenuPresenter.Callback {
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ mOpenSubMenuId = 0;
+ if (mOpenSubMenu != null) {
+ mOpenSubMenu.dismiss();
+ mOpenSubMenu = null;
+ }
+ }
+
+ @Override
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
+ return false;
+ }
+
}
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 0c3c605..a1e16d4 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -22,6 +22,7 @@
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
@@ -50,6 +51,8 @@
private LayoutInflater mInflater;
+ private boolean mForceShowIcon;
+
public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs);
@@ -99,6 +102,10 @@
setEnabled(itemData.isEnabled());
}
+ public void setForceShowIcon(boolean forceShow) {
+ mPreserveIconSpacing = mForceShowIcon = forceShow;
+ }
+
public void setTitle(CharSequence title) {
if (title != null) {
mTitleView.setText(title);
@@ -189,12 +196,12 @@
}
public void setIcon(Drawable icon) {
- final boolean showIcon = mItemData.shouldShowIcon();
+ final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
if (!showIcon && !mPreserveIconSpacing) {
return;
}
- if (mIconView == null && icon == null) {
+ if (mIconView == null && icon == null && !mPreserveIconSpacing) {
return;
}
@@ -213,6 +220,19 @@
}
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mIconView != null && mPreserveIconSpacing) {
+ // Enforce minimum icon spacing
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+ if (lp.height > 0 && iconLp.width <= 0) {
+ iconLp.width = lp.height;
+ }
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
private void insertIconView() {
LayoutInflater inflater = getInflater();
mIconView = (ImageView) inflater.inflate(com.android.internal.R.layout.list_menu_item_icon,
@@ -241,7 +261,7 @@
}
public boolean showsIcon() {
- return false;
+ return mForceShowIcon;
}
private LayoutInflater getInflater() {
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index 27e4191..146c7ac 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -47,6 +47,8 @@
private Callback mCallback;
private MenuAdapter mAdapter;
+ private int mId;
+
public static final String VIEWS_TAG = "android:menu:list";
/**
@@ -182,6 +184,31 @@
}
}
+ public void setId(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ if (mMenuView == null) {
+ return null;
+ }
+
+ Bundle state = new Bundle();
+ saveHierarchyState(state);
+ return state;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ restoreHierarchyState((Bundle) state);
+ }
+
private class MenuAdapter extends BaseAdapter {
public int getCount() {
ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index fdfa954..164d581 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -25,9 +25,10 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Parcelable;
-import android.util.Log;
import android.util.SparseArray;
+import android.view.ActionProvider;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -38,7 +39,6 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -49,6 +49,8 @@
public class MenuBuilder implements Menu {
private static final String LOGTAG = "MenuBuilder";
+ private static final String PRESENTER_KEY = "android:menu:presenters";
+
private static final int[] sCategoryToOrder = new int[] {
1, /* No category */
4, /* CONTAINER */
@@ -254,6 +256,58 @@
return result;
}
+ private void dispatchSaveInstanceState(Bundle outState) {
+ if (mPresenters.isEmpty()) return;
+
+ SparseArray<Parcelable> presenterStates = new SparseArray<Parcelable>();
+
+ for (WeakReference<MenuPresenter> ref : mPresenters) {
+ final MenuPresenter presenter = ref.get();
+ if (presenter == null) {
+ mPresenters.remove(ref);
+ } else {
+ final int id = presenter.getId();
+ if (id > 0) {
+ final Parcelable state = presenter.onSaveInstanceState();
+ if (state != null) {
+ presenterStates.put(id, state);
+ }
+ }
+ }
+ }
+
+ outState.putSparseParcelableArray(PRESENTER_KEY, presenterStates);
+ }
+
+ private void dispatchRestoreInstanceState(Bundle state) {
+ SparseArray<Parcelable> presenterStates = state.getSparseParcelableArray(PRESENTER_KEY);
+
+ if (presenterStates == null || mPresenters.isEmpty()) return;
+
+ for (WeakReference<MenuPresenter> ref : mPresenters) {
+ final MenuPresenter presenter = ref.get();
+ if (presenter == null) {
+ mPresenters.remove(ref);
+ } else {
+ final int id = presenter.getId();
+ if (id > 0) {
+ Parcelable parcel = presenterStates.get(id);
+ if (parcel != null) {
+ presenter.onRestoreInstanceState(parcel);
+ }
+ }
+ }
+ }
+ }
+
+ public void savePresenterStates(Bundle outState) {
+ dispatchSaveInstanceState(outState);
+ }
+
+ public void restorePresenterStates(Bundle state) {
+ dispatchRestoreInstanceState(state);
+ }
+
public void setCallback(Callback cb) {
mCallback = cb;
}
@@ -745,7 +799,7 @@
if (itemImpl == null || !itemImpl.isEnabled()) {
return false;
}
-
+
boolean invoked = itemImpl.invoke();
if (itemImpl.hasCollapsibleActionView()) {
@@ -754,7 +808,12 @@
} else if (item.hasSubMenu()) {
close(false);
- invoked |= dispatchSubMenuSelected((SubMenuBuilder) item.getSubMenu());
+ final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+ final ActionProvider provider = item.getActionProvider();
+ if (provider != null && provider.hasSubMenu()) {
+ provider.onPrepareSubMenu(subMenu);
+ }
+ invoked |= dispatchSubMenuSelected(subMenu);
if (!invoked) close(true);
} else {
if ((flags & FLAG_PERFORM_NO_CLOSE) == 0) {
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 20b7d80..541d101 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -164,10 +164,7 @@
}
}
- if (mActionProvider != null) {
- // The action view is created by the provider in this case.
- View actionView = getActionView();
- mActionProvider.onPerformDefaultAction(actionView);
+ if (mActionProvider != null && mActionProvider.onPerformDefaultAction()) {
return true;
}
@@ -323,11 +320,6 @@
}
void setSubMenu(SubMenuBuilder subMenu) {
- if ((mMenu != null) && (mMenu instanceof SubMenu)) {
- throw new UnsupportedOperationException(
- "Attempt to add a sub-menu to a sub-menu.");
- }
-
mSubMenu = subMenu;
subMenu.setHeaderTitle(getTitle());
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index cffbb4e..6265618 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -18,15 +18,17 @@
import android.content.Context;
import android.content.res.Resources;
-import android.util.DisplayMetrics;
+import android.os.Parcelable;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
import android.widget.ListAdapter;
import android.widget.ListPopupWindow;
import android.widget.PopupWindow;
@@ -57,6 +59,10 @@
private Callback mPresenterCallback;
+ boolean mForceShowIcon;
+
+ private ViewGroup mMeasureParent;
+
public MenuPopupHelper(Context context, MenuBuilder menu) {
this(context, menu, null, false);
}
@@ -85,6 +91,10 @@
mAnchorView = anchor;
}
+ public void setForceShowIcon(boolean forceShow) {
+ mForceShowIcon = forceShow;
+ }
+
public void show() {
if (!tryShow()) {
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
@@ -169,7 +179,10 @@
itemType = positionType;
itemView = null;
}
- itemView = adapter.getView(i, itemView, null);
+ if (mMeasureParent == null) {
+ mMeasureParent = new FrameLayout(mContext);
+ }
+ itemView = adapter.getView(i, itemView, mMeasureParent);
itemView.measure(widthMeasureSpec, heightMeasureSpec);
width = Math.max(width, itemView.getMeasuredWidth());
}
@@ -227,6 +240,18 @@
if (subMenu.hasVisibleItems()) {
MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
subPopup.setCallback(mPresenterCallback);
+
+ boolean preserveIconSpacing = false;
+ final int count = subMenu.size();
+ for (int i = 0; i < count; i++) {
+ MenuItem childItem = subMenu.getItem(i);
+ if (childItem.isVisible() && childItem.getIcon() != null) {
+ preserveIconSpacing = true;
+ break;
+ }
+ }
+ subPopup.setForceShowIcon(preserveIconSpacing);
+
if (subPopup.tryShow()) {
if (mPresenterCallback != null) {
mPresenterCallback.onOpenSubMenu(subMenu);
@@ -292,8 +317,25 @@
}
MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+ if (mForceShowIcon) {
+ ((ListMenuItemView) convertView).setForceShowIcon(true);
+ }
itemView.initialize(getItem(position), 0);
return convertView;
}
}
+
+ @Override
+ public int getId() {
+ return 0;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ return null;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java
index bd66448..d913a39 100644
--- a/core/java/com/android/internal/view/menu/MenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/MenuPresenter.java
@@ -17,6 +17,7 @@
package com.android.internal.view.menu;
import android.content.Context;
+import android.os.Parcelable;
import android.view.Menu;
import android.view.ViewGroup;
@@ -125,4 +126,24 @@
* @return true if this presenter collapsed the action view, false otherwise.
*/
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item);
+
+ /**
+ * Returns an ID for determining how to save/restore instance state.
+ * @return a valid ID value.
+ */
+ public int getId();
+
+ /**
+ * Returns a Parcelable describing the current state of the presenter.
+ * It will be passed to the {@link #onRestoreInstanceState(Parcelable)}
+ * method of the presenter sharing the same ID later.
+ * @return The saved instance state
+ */
+ public Parcelable onSaveInstanceState();
+
+ /**
+ * Supplies the previously saved instance state to be restored.
+ * @param state The previously saved instance state
+ */
+ public void onRestoreInstanceState(Parcelable state);
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 09bc1fc..678751c 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -337,6 +337,7 @@
if (mActionMenuPresenter == null) {
mActionMenuPresenter = new ActionMenuPresenter();
mActionMenuPresenter.setCallback(cb);
+ mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);
mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
}
@@ -369,6 +370,19 @@
mMenuView = menuView;
}
+ public boolean hasExpandedActionView() {
+ return mExpandedMenuPresenter != null &&
+ mExpandedMenuPresenter.mCurrentExpandedItem != null;
+ }
+
+ public void collapseActionView() {
+ final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
+ mExpandedMenuPresenter.mCurrentExpandedItem;
+ if (item != null) {
+ item.collapseActionView();
+ }
+ }
+
public void setCustomNavigationView(View view) {
final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
if (mCustomNavView != null && showCustom) {
@@ -433,22 +447,40 @@
}
}
+ public void setHomeButtonEnabled(boolean enable) {
+ mHomeLayout.setEnabled(enable);
+ // Make sure the home button has an accurate content description for accessibility.
+ if (!enable) {
+ mHomeLayout.setContentDescription(null);
+ } else if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_up_description));
+ } else {
+ mHomeLayout.setContentDescription(mContext.getResources().getText(
+ R.string.action_bar_home_description));
+ }
+ }
+
public void setDisplayOptions(int options) {
final int flagsChanged = options ^ mDisplayOptions;
mDisplayOptions = options;
- if ((flagsChanged & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
- final boolean disableHome = (options & ActionBar.DISPLAY_DISABLE_HOME) != 0;
- mHomeLayout.setEnabled(!disableHome);
- }
-
if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
final int vis = showHome ? VISIBLE : GONE;
mHomeLayout.setVisibility(vis);
if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
- mHomeLayout.setUp((options & ActionBar.DISPLAY_HOME_AS_UP) != 0);
+ final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+ mHomeLayout.setUp(setUp);
+
+ // Showing home as up implicitly enables interaction with it.
+ // In honeycomb it was always enabled, so make this transition
+ // a bit easier for developers in the common case.
+ // (It would be silly to show it as up without responding to it.)
+ if (setUp) {
+ setHomeButtonEnabled(true);
+ }
}
if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
@@ -486,7 +518,7 @@
}
// Make sure the home button has an accurate content description for accessibility.
- if ((options & ActionBar.DISPLAY_DISABLE_HOME) != 0) {
+ if (!mHomeLayout.isEnabled()) {
mHomeLayout.setContentDescription(null);
} else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
mHomeLayout.setContentDescription(mContext.getResources().getText(
@@ -1253,7 +1285,7 @@
@Override
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
mExpandedActionView = item.getActionView();
- mExpandedHomeLayout.setIcon(item.getIcon());
+ mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
mCurrentExpandedItem = item;
if (mExpandedActionView.getParent() != ActionBarView.this) {
addView(mExpandedActionView);
@@ -1301,5 +1333,19 @@
item.setActionViewExpanded(false);
return true;
}
+
+ @Override
+ public int getId() {
+ return 0;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ return null;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ }
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index d034eab..bbddf29 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -114,6 +114,23 @@
private static final AtomicBoolean sHaveNonZeroPasswordFile = new AtomicBoolean(false);
private static FileObserver sPasswordObserver;
+ private static class PasswordFileObserver extends FileObserver {
+ public PasswordFileObserver(String path, int mask) {
+ super(path, mask);
+ }
+
+ @Override
+ public void onEvent(int event, String path) {
+ if (LOCK_PATTERN_FILE.equals(path)) {
+ Log.d(TAG, "lock pattern file changed");
+ sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
+ } else if (LOCK_PASSWORD_FILE.equals(path)) {
+ Log.d(TAG, "lock password file changed");
+ sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
+ }
+ }
+ }
+
public DevicePolicyManager getDevicePolicyManager() {
if (mDevicePolicyManager == null) {
mDevicePolicyManager =
@@ -143,18 +160,7 @@
sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
int fileObserverMask = FileObserver.CLOSE_WRITE | FileObserver.DELETE |
FileObserver.MOVED_TO | FileObserver.CREATE;
- sPasswordObserver = new FileObserver(dataSystemDirectory, fileObserverMask) {
- @Override
- public void onEvent(int event, String path) {
- if (LOCK_PATTERN_FILE.equals(path)) {
- Log.d(TAG, "lock pattern file changed");
- sHaveNonZeroPatternFile.set(new File(sLockPatternFilename).length() > 0);
- } else if (LOCK_PASSWORD_FILE.equals(path)) {
- Log.d(TAG, "lock password file changed");
- sHaveNonZeroPasswordFile.set(new File(sLockPasswordFilename).length() > 0);
- }
- }
- };
+ sPasswordObserver = new PasswordFileObserver(dataSystemDirectory, fileObserverMask);
sPasswordObserver.startWatching();
}
}
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
index 2871073..c446cfb 100644
--- a/core/java/com/android/server/NetworkManagementSocketTagger.java
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -16,24 +16,37 @@
package com.android.server;
+import android.os.SystemProperties;
+import android.util.Log;
+
import dalvik.system.SocketTagger;
+
import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.math.BigInteger;
import java.net.SocketException;
import java.nio.charset.Charsets;
+import libcore.io.IoUtils;
+
/**
* Assigns tags to sockets for traffic stats.
*/
public final class NetworkManagementSocketTagger extends SocketTagger {
+ private static final String TAG = "NetworkManagementSocketTagger";
+ private static final boolean LOGD = false;
- private static final boolean LOGI = false;
- private static final boolean ENABLE_TAGGING = false;
+ /**
+ * {@link SystemProperties} key that indicates if {@code qtaguid} bandwidth
+ * controls have been enabled.
+ */
+ // TODO: remove when always enabled, or once socket tagging silently fails.
+ public static final String PROP_QTAGUID_ENABLED = "net.qtaguid_enabled";
private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() {
- @Override protected SocketTags initialValue() {
+ @Override
+ protected SocketTags initialValue() {
return new SocketTags();
}
};
@@ -50,11 +63,12 @@
threadSocketTags.get().statsUid = uid;
}
- @Override public void tag(FileDescriptor fd) throws SocketException {
+ @Override
+ public void tag(FileDescriptor fd) throws SocketException {
final SocketTags options = threadSocketTags.get();
- if (LOGI) {
- System.logI("tagSocket(" + fd.getInt$() + ") with statsTag="
- + options.statsTag + ", statsUid=" + options.statsUid);
+ if (LOGD) {
+ Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=" + options.statsTag
+ + ", statsUid=" + options.statsUid);
}
try {
// TODO: skip tagging when options would be no-op
@@ -82,9 +96,10 @@
internalModuleCtrl(cmd);
}
- @Override public void untag(FileDescriptor fd) throws SocketException {
- if (LOGI) {
- System.logI("untagSocket(" + fd.getInt$() + ")");
+ @Override
+ public void untag(FileDescriptor fd) throws SocketException {
+ if (LOGD) {
+ Log.i(TAG, "untagSocket(" + fd.getInt$() + ")");
}
try {
unTagSocketFd(fd);
@@ -125,31 +140,22 @@
*
*/
private void internalModuleCtrl(String cmd) throws IOException {
- if (!ENABLE_TAGGING) return;
+ if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
- final FileOutputStream procOut;
- // TODO: Use something like
- // android.os.SystemProperties.getInt("persist.bandwidth.enable", 0)
- // to see if tagging should happen or not.
+ // TODO: migrate to native library for tagging commands
+ FileOutputStream procOut = null;
try {
procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl");
- } catch (FileNotFoundException e) {
- if (LOGI) {
- System.logI("Can't talk to kernel module:" + e);
- }
- return;
- }
- try {
procOut.write(cmd.getBytes(Charsets.US_ASCII));
} finally {
- procOut.close();
+ IoUtils.closeQuietly(procOut);
}
}
/**
* Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned
* base-10 format like {@code 2147483647}. Currently strips signed bit to
- * avoid using {@link java.math.BigInteger}.
+ * avoid using {@link BigInteger}.
*/
public static String tagToKernel(int tag) {
// TODO: eventually write in hex, since that's what proc exports
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 63fa504..06dc083 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -145,7 +145,6 @@
android_server_Watchdog.cpp \
android_ddm_DdmHandleNativeHeap.cpp \
com_android_internal_os_ZygoteInit.cpp \
- com_android_internal_graphics_NativeUtils.cpp \
android_backup_BackupDataInput.cpp \
android_backup_BackupDataOutput.cpp \
android_backup_FileBackupHelperBase.cpp \
@@ -224,22 +223,14 @@
LOCAL_SHARED_LIBRARIES += libbluedroid libdbus
endif
-ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += \
libdl
- # we need to access the private Bionic header
- # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
-endif
+# we need to access the private Bionic header
+# <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
LOCAL_LDLIBS += -lpthread -ldl
-ifeq ($(TARGET_SIMULATOR),true)
-ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
-LOCAL_LDLIBS += -lrt
-endif
-endif
-
ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endif
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a61217a..6ab8fe3 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -115,7 +115,6 @@
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
extern int register_android_graphics_PixelFormat(JNIEnv* env);
-extern int register_com_android_internal_graphics_NativeUtils(JNIEnv *env);
extern int register_android_view_Display(JNIEnv* env);
extern int register_android_view_GLES20Canvas(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
@@ -623,27 +622,11 @@
}
/* enable debugging; set suspend=y to pause during VM init */
-#ifdef HAVE_ANDROID_OS
/* use android ADB transport */
opt.optionString =
"-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
-#else
- /* use TCP socket; address=0 means start at port 8000 and probe up */
- LOGI("Using TCP socket for JDWP\n");
- opt.optionString =
- "-agentlib:jdwp=transport=dt_socket,suspend=n,server=y,address=0";
-#endif
mOptions.add(opt);
- char enableDPBuf[sizeof("-Xdeadlockpredict:") + PROPERTY_VALUE_MAX];
- property_get("dalvik.vm.deadlock-predict", propBuf, "");
- if (strlen(propBuf) > 0) {
- strcpy(enableDPBuf, "-Xdeadlockpredict:");
- strcat(enableDPBuf, propBuf);
- opt.optionString = enableDPBuf;
- mOptions.add(opt);
- }
-
LOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
/* extended JNI checking */
@@ -1154,7 +1137,6 @@
REG_JNI(register_android_graphics_Typeface),
REG_JNI(register_android_graphics_Xfermode),
REG_JNI(register_android_graphics_YuvImage),
- REG_JNI(register_com_android_internal_graphics_NativeUtils),
REG_JNI(register_android_database_CursorWindow),
REG_JNI(register_android_database_SQLiteCompiledSql),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 258ffa5..ea35006 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -116,7 +116,7 @@
bool forcePurgeable = false) {
int sampleSize = 1;
SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
- SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
+ SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;
bool doDither = true;
bool isMutable = false;
bool isPurgeable = forcePurgeable ||
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 942aa8a..682c3c4 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -799,24 +799,6 @@
x, y, flags, paint);
}
- static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
- jcharArray text, int index, int count,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
- jchar* textArray = env->GetCharArrayElements(text, NULL);
- drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
- env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
- }
-
- static void drawTextWithGlyphs__StringIIFFIPaint(JNIEnv* env, jobject,
- SkCanvas* canvas, jstring text,
- int start, int end,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
-
- const jchar* textArray = env->GetStringChars(text, NULL);
- drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
- env->ReleaseStringChars(text, textArray);
- }
-
static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
// TODO: need to suppress this code after the GL renderer is modified for not
@@ -833,16 +815,6 @@
paint->setTextEncoding(oldEncoding);
}
- static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
- jcharArray glyphs, int index, int count,
- jfloat x, jfloat y, int flags, SkPaint* paint) {
- jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
-
- doDrawGlyphs(canvas, glyphArray, index, count, x, y, flags, paint);
-
- env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT);
- }
-
static void drawTextRun___CIIIIFFIPaint(
JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
int count, int contextIndex, int contextCount,
@@ -1044,12 +1016,6 @@
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
{"native_drawText","(ILjava/lang/String;IIFFII)V",
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
- {"native_drawTextWithGlyphs","(I[CIIFFII)V",
- (void*) SkCanvasGlue::drawTextWithGlyphs___CIIFFIPaint},
- {"native_drawTextWithGlyphs","(ILjava/lang/String;IIFFII)V",
- (void*) SkCanvasGlue::drawTextWithGlyphs__StringIIFFIPaint},
- {"native_drawGlyphs","(I[CIIFFII)V",
- (void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint},
{"native_drawTextRun","(I[CIIIIFFII)V",
(void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
{"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 203b5ef..c22b071 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -44,7 +44,6 @@
// Returns an ASCII decimal number read from the specified file, -1 on error.
static jlong readNumber(char const* filename) {
-#ifdef HAVE_ANDROID_OS
char buf[80];
int fd = open(filename, O_RDONLY);
if (fd < 0) {
@@ -62,21 +61,42 @@
close(fd);
buf[len] = '\0';
return atoll(buf);
-#else // Simulator
- return -1;
-#endif
}
-// Return the number from the first file which exists and contains data
-static jlong tryBoth(char const* a, char const* b) {
- jlong num = readNumber(a);
- return num >= 0 ? num : readNumber(b);
+static const char* mobile_iface_list[] = {
+ "rmnet0",
+ "rmnet1",
+ "rmnet2",
+ "rmnet3",
+ "ppp0",
+ 0
+};
+
+static jlong getAll(const char** iface_list, const char* what) {
+
+ char filename[80];
+ int idx = 0;
+ bool supported = false;
+ jlong total = 0;
+ while (iface_list[idx] != 0) {
+
+ snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s",
+ iface_list[idx], what);
+ jlong number = readNumber(filename);
+ if (number >= 0) {
+ supported = true;
+ total += number;
+ }
+ idx++;
+ }
+ if (supported) return total;
+
+ return -1;
}
// Returns the sum of numbers from the specified path under /sys/class/net/*,
// -1 if no such file exists.
static jlong readTotal(char const* suffix) {
-#ifdef HAVE_ANDROID_OS
char filename[PATH_MAX] = "/sys/class/net/";
DIR *dir = opendir(filename);
if (dir == NULL) {
@@ -98,9 +118,6 @@
closedir(dir);
return total;
-#else // Simulator
- return -1;
-#endif
}
// Mobile stats get accessed a lot more often than total stats.
@@ -108,27 +125,19 @@
// each file every time (rather than caching which ones exist).
static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) {
- return tryBoth(
- "/sys/class/net/rmnet0/statistics/tx_packets",
- "/sys/class/net/ppp0/statistics/tx_packets");
+ return getAll(mobile_iface_list, "tx_packets");
}
static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) {
- return tryBoth(
- "/sys/class/net/rmnet0/statistics/rx_packets",
- "/sys/class/net/ppp0/statistics/rx_packets");
+ return getAll(mobile_iface_list, "rx_packets");
}
static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) {
- return tryBoth(
- "/sys/class/net/rmnet0/statistics/tx_bytes",
- "/sys/class/net/ppp0/statistics/tx_bytes");
+ return getAll(mobile_iface_list, "tx_bytes");
}
static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) {
- return tryBoth(
- "/sys/class/net/rmnet0/statistics/rx_bytes",
- "/sys/class/net/ppp0/statistics/rx_bytes");
+ return getAll(mobile_iface_list, "rx_bytes");
}
static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) {
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 2297834..3a3f07e 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -27,6 +27,7 @@
#include <sys/time.h>
#include <errno.h>
#include <assert.h>
+#include <ctype.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
@@ -35,28 +36,50 @@
namespace android
{
-static jfieldID dalvikPss_field;
-static jfieldID dalvikPrivateDirty_field;
-static jfieldID dalvikSharedDirty_field;
-static jfieldID nativePss_field;
-static jfieldID nativePrivateDirty_field;
-static jfieldID nativeSharedDirty_field;
-static jfieldID otherPss_field;
-static jfieldID otherPrivateDirty_field;
-static jfieldID otherSharedDirty_field;
+enum {
+ HEAP_UNKNOWN,
+ HEAP_DALVIK,
+ HEAP_NATIVE,
+ HEAP_CURSOR,
+ HEAP_ASHMEM,
+ HEAP_UNKNOWN_DEV,
+ HEAP_SO,
+ HEAP_JAR,
+ HEAP_APK,
+ HEAP_TTF,
+ HEAP_DEX,
+ HEAP_UNKNOWN_MAP,
+
+ _NUM_HEAP,
+ _NUM_CORE_HEAP = HEAP_NATIVE+1
+};
+
+struct stat_fields {
+ jfieldID pss_field;
+ jfieldID privateDirty_field;
+ jfieldID sharedDirty_field;
+};
+
+struct stat_field_names {
+ const char* pss_name;
+ const char* privateDirty_name;
+ const char* sharedDirty_name;
+};
+
+static stat_fields stat_fields[_NUM_CORE_HEAP];
+
+static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
+ { "otherPss", "otherPrivateDirty", "otherSharedDirty" },
+ { "dalvikPss", "dalvikPrivateDirty", "dalvikSharedDirty" },
+ { "nativePss", "nativePrivateDirty", "nativeSharedDirty" }
+};
+
+jfieldID otherStats_field;
struct stats_t {
- int dalvikPss;
- int dalvikPrivateDirty;
- int dalvikSharedDirty;
-
- int nativePss;
- int nativePrivateDirty;
- int nativeSharedDirty;
-
- int otherPss;
- int otherPrivateDirty;
- int otherSharedDirty;
+ int pss;
+ int privateDirty;
+ int sharedDirty;
};
#define BINDER_STATS "/proc/binder/stats"
@@ -94,48 +117,71 @@
static void read_mapinfo(FILE *fp, stats_t* stats)
{
char line[1024];
- int len;
+ int len, nameLen;
bool skip, done = false;
- unsigned start = 0, size = 0, resident = 0, pss = 0;
+ unsigned size = 0, resident = 0, pss = 0;
unsigned shared_clean = 0, shared_dirty = 0;
unsigned private_clean = 0, private_dirty = 0;
unsigned referenced = 0;
unsigned temp;
- int isNativeHeap;
- int isDalvikHeap;
- int isSqliteHeap;
+ unsigned long int start;
+ unsigned long int end = 0;
+ unsigned long int prevEnd = 0;
+ char* name;
+ int name_pos;
- if(fgets(line, 1024, fp) == 0) return;
+ int whichHeap = HEAP_UNKNOWN;
+ int prevHeap = HEAP_UNKNOWN;
+
+ if(fgets(line, sizeof(line), fp) == 0) return;
while (!done) {
- isNativeHeap = 0;
- isDalvikHeap = 0;
- isSqliteHeap = 0;
+ prevHeap = whichHeap;
+ prevEnd = end;
+ whichHeap = HEAP_UNKNOWN;
skip = false;
len = strlen(line);
if (len < 1) return;
line[--len] = 0;
- /* ignore guard pages */
- if (len > 18 && line[17] == '-') skip = true;
+ if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
+ skip = true;
+ } else {
+ while (isspace(line[name_pos])) {
+ name_pos += 1;
+ }
+ name = line + name_pos;
+ nameLen = strlen(name);
- start = strtoul(line, 0, 16);
-
- if (strstr(line, "[heap]")) {
- isNativeHeap = 1;
- } else if (strstr(line, "/dalvik-LinearAlloc")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/mspace/dalvik-heap")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/dalvik-heap-bitmap/")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/data/dalvik-cache/")) {
- isDalvikHeap = 1;
- } else if (strstr(line, "/tmp/sqlite-heap")) {
- isSqliteHeap = 1;
+ if (strstr(name, "[heap]") == name) {
+ whichHeap = HEAP_NATIVE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-") == name) {
+ whichHeap = HEAP_DALVIK;
+ } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) {
+ whichHeap = HEAP_CURSOR;
+ } else if (strstr(name, "/dev/ashmem/") == name) {
+ whichHeap = HEAP_ASHMEM;
+ } else if (strstr(name, "/dev/") == name) {
+ whichHeap = HEAP_UNKNOWN_DEV;
+ } else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
+ whichHeap = HEAP_SO;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".jar") == 0) {
+ whichHeap = HEAP_JAR;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".apk") == 0) {
+ whichHeap = HEAP_APK;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
+ whichHeap = HEAP_TTF;
+ } else if (nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) {
+ whichHeap = HEAP_DEX;
+ } else if (nameLen > 0) {
+ whichHeap = HEAP_UNKNOWN_MAP;
+ } else if (start == prevEnd && prevHeap == HEAP_SO) {
+ // bss section of a shared library.
+ whichHeap = HEAP_SO;
+ }
}
//LOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap,
@@ -171,21 +217,9 @@
}
if (!skip) {
- if (isNativeHeap) {
- stats->nativePss += pss;
- stats->nativePrivateDirty += private_dirty;
- stats->nativeSharedDirty += shared_dirty;
- } else if (isDalvikHeap) {
- stats->dalvikPss += pss;
- stats->dalvikPrivateDirty += private_dirty;
- stats->dalvikSharedDirty += shared_dirty;
- } else if ( isSqliteHeap) {
- // ignore
- } else {
- stats->otherPss += pss;
- stats->otherPrivateDirty += private_dirty;
- stats->otherSharedDirty += shared_dirty;
- }
+ stats[whichHeap].pss += pss;
+ stats[whichHeap].privateDirty += private_dirty;
+ stats[whichHeap].sharedDirty += shared_dirty;
}
}
}
@@ -206,22 +240,38 @@
static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
jint pid, jobject object)
{
- stats_t stats;
- memset(&stats, 0, sizeof(stats_t));
+ stats_t stats[_NUM_HEAP];
+ memset(&stats, 0, sizeof(stats));
- load_maps(pid, &stats);
+ load_maps(pid, stats);
- env->SetIntField(object, dalvikPss_field, stats.dalvikPss);
- env->SetIntField(object, dalvikPrivateDirty_field, stats.dalvikPrivateDirty);
- env->SetIntField(object, dalvikSharedDirty_field, stats.dalvikSharedDirty);
+ for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+ stats[HEAP_UNKNOWN].pss += stats[i].pss;
+ stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
+ stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
+ }
+
+ for (int i=0; i<_NUM_CORE_HEAP; i++) {
+ env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
+ env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
+ env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
+ }
- env->SetIntField(object, nativePss_field, stats.nativePss);
- env->SetIntField(object, nativePrivateDirty_field, stats.nativePrivateDirty);
- env->SetIntField(object, nativeSharedDirty_field, stats.nativeSharedDirty);
+ jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
- env->SetIntField(object, otherPss_field, stats.otherPss);
- env->SetIntField(object, otherPrivateDirty_field, stats.otherPrivateDirty);
- env->SetIntField(object, otherSharedDirty_field, stats.otherSharedDirty);
+ jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
+ if (otherArray == NULL) {
+ return;
+ }
+
+ int j=0;
+ for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
+ otherArray[j++] = stats[i].pss;
+ otherArray[j++] = stats[i].privateDirty;
+ otherArray[j++] = stats[i].sharedDirty;
+ }
+
+ env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
}
static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
@@ -278,7 +328,6 @@
jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
-#ifdef HAVE_ANDROID_OS
/* pulled out of bionic */
extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
@@ -414,7 +463,6 @@
fprintf(fp, "END\n");
}
-#endif /*HAVE_ANDROID_OS*/
/*
* Dump the native heap, writing human-readable output to the specified
@@ -449,13 +497,9 @@
return;
}
-#ifdef HAVE_ANDROID_OS
LOGD("Native heap dump starting...\n");
dumpNativeHeap(fp);
LOGD("Native heap dump complete.\n");
-#else
- fprintf(fp, "Native heap dump not available on this platform\n");
-#endif
fclose(fp);
}
@@ -493,19 +537,18 @@
int register_android_os_Debug(JNIEnv *env)
{
jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
-
- dalvikPss_field = env->GetFieldID(clazz, "dalvikPss", "I");
- dalvikPrivateDirty_field = env->GetFieldID(clazz, "dalvikPrivateDirty", "I");
- dalvikSharedDirty_field = env->GetFieldID(clazz, "dalvikSharedDirty", "I");
- nativePss_field = env->GetFieldID(clazz, "nativePss", "I");
- nativePrivateDirty_field = env->GetFieldID(clazz, "nativePrivateDirty", "I");
- nativeSharedDirty_field = env->GetFieldID(clazz, "nativeSharedDirty", "I");
-
- otherPss_field = env->GetFieldID(clazz, "otherPss", "I");
- otherPrivateDirty_field = env->GetFieldID(clazz, "otherPrivateDirty", "I");
- otherSharedDirty_field = env->GetFieldID(clazz, "otherSharedDirty", "I");
-
+ for (int i=0; i<_NUM_CORE_HEAP; i++) {
+ stat_fields[i].pss_field =
+ env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
+ stat_fields[i].privateDirty_field =
+ env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
+ stat_fields[i].sharedDirty_field =
+ env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
+ }
+
+ otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
+
return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index 89dce89..8d65cbc 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -28,11 +28,8 @@
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
-
-#if HAVE_ANDROID_OS
#include <sys/ioctl.h>
#include <linux/msdos_fs.h>
-#endif
namespace android {
@@ -53,7 +50,6 @@
jstring file, jint mode,
jint uid, jint gid)
{
- #if HAVE_ANDROID_OS
const jchar* str = env->GetStringCritical(file, 0);
String8 file8;
if (str) {
@@ -70,15 +66,11 @@
}
}
return chmod(file8.string(), mode) == 0 ? 0 : errno;
- #else
- return ENOSYS;
- #endif
}
jint android_os_FileUtils_getPermissions(JNIEnv* env, jobject clazz,
jstring file, jintArray outArray)
{
- #if HAVE_ANDROID_OS
const jchar* str = env->GetStringCritical(file, 0);
String8 file8;
if (str) {
@@ -107,9 +99,6 @@
}
env->ReleasePrimitiveArrayCritical(outArray, array, 0);
return 0;
- #else
- return ENOSYS;
- #endif
}
jint android_os_FileUtils_setUMask(JNIEnv* env, jobject clazz, jint mask)
@@ -119,7 +108,6 @@
jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path)
{
- #if HAVE_ANDROID_OS
if (path == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return -1;
@@ -137,9 +125,6 @@
env->ReleaseStringUTFChars(path, pathStr);
return result;
- #else
- return -1;
- #endif
}
jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring path, jobject fileStatus) {
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
index 9ae4a63..dc16990 100644
--- a/core/jni/android_os_Power.cpp
+++ b/core/jni/android_os_Power.cpp
@@ -70,16 +70,11 @@
static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
{
-#ifdef HAVE_ANDROID_OS
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
-#else
- sync();
-#endif
}
static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason)
{
-#ifdef HAVE_ANDROID_OS
if (reason == NULL) {
android_reboot(ANDROID_RB_RESTART, 0, 0);
} else {
@@ -88,9 +83,6 @@
env->ReleaseStringUTFChars(reason, chars); // In case it fails.
}
jniThrowIOException(env, errno);
-#else
- sync();
-#endif
}
static JNINativeMethod method_table[] = {
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 2b09442..8f84b81 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -1115,7 +1115,7 @@
LOGV("... uuid = %s", uuid);
dbus_message_ref(msg); // increment refcount because we pass to java
- env->CallBooleanMethod(nat->me, method_onAgentAuthorize,
+ env->CallVoidMethod(nat->me, method_onAgentAuthorize,
env->NewStringUTF(object_path), env->NewStringUTF(uuid),
int(msg));
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 1166ae4..86e7cc0 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -1396,7 +1396,6 @@
LOG_AND_FREE_DBUS_ERROR(&err);
}
} else {
- LOGE("--_Call made getting the patch...");
if (!dbus_message_get_args(reply, &err,
DBUS_TYPE_OBJECT_PATH, &c_path,
DBUS_TYPE_INVALID)) {
@@ -1405,7 +1404,6 @@
}
} else {
path = env->NewStringUTF(c_path);
- LOGE("----Path is %s", c_path);
}
dbus_message_unref(reply);
}
@@ -1459,7 +1457,6 @@
const char *c_device_path = env->GetStringUTFChars(devicePath, NULL);
const char *c_app_path = env->GetStringUTFChars(appPath, NULL);
const char *c_config = env->GetStringUTFChars(config, NULL);
- LOGE("Params...%s, %s, %s \n", c_device_path, c_app_path, c_config);
DBusMessage *reply = dbus_func_args(env, nat->conn,
c_device_path,
@@ -1531,7 +1528,6 @@
DBusError err;
dbus_error_init(&err);
- LOGE("---Args %s", c_device_path);
DBusMessage *reply = dbus_func_args(env, nat->conn,
c_device_path,
DBUS_HEALTH_DEVICE_IFACE, "GetProperties",
@@ -1566,8 +1562,6 @@
DBusError err;
dbus_error_init(&err);
- LOGE("---Args %s", c_channel_path);
-
DBusMessage *reply = dbus_func_args(env, nat->conn,
c_channel_path,
DBUS_HEALTH_CHANNEL_IFACE, "GetProperties",
@@ -1596,7 +1590,6 @@
if (!strcmp(c_name, "Application")) {
path = (jstring) env->GetObjectArrayElement(str_array, i+1);
- LOGE("----Path is %s", env->GetStringUTFChars(path, NULL));
env->ReleaseStringUTFChars(name, c_name);
return path;
}
@@ -1655,13 +1648,11 @@
fd = dbus_returns_unixfd(env, reply);
if (fd == -1) return NULL;
- LOGE("---got fd %d\n", fd);
// Create FileDescriptor object
jobject fileDesc = jniCreateFileDescriptor(env, fd);
if (fileDesc == NULL) {
// FileDescriptor constructor has thrown an exception
releaseChannelFdNative(env, object, channelPath);
- LOGE("---File Desc is null");
return NULL;
}
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 0fbe0e7..2c7bb84 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -58,9 +58,6 @@
static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
{
-#ifndef HAVE_ANDROID_OS
- return false;
-#else /* HAVE_ANDROID_OS */
int len;
char key[PROPERTY_KEY_MAX];
char buf[PROPERTY_VALUE_MAX];
@@ -93,7 +90,6 @@
len = property_get(key, buf, "");
int logLevel = toLevel(buf);
return (logLevel >= 0 && level >= logLevel) ? true : false;
-#endif /* HAVE_ANDROID_OS */
}
/*
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 0960b25..47d343a 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -318,17 +318,15 @@
jint pid, jint adj)
{
#ifdef HAVE_OOM_ADJ
- if (ProcessState::self()->supportsProcesses()) {
- char text[64];
- sprintf(text, "/proc/%d/oom_adj", pid);
- int fd = open(text, O_WRONLY);
- if (fd >= 0) {
- sprintf(text, "%d", adj);
- write(fd, text, strlen(text));
- close(fd);
- }
- return true;
+ char text[64];
+ sprintf(text, "/proc/%d/oom_adj", pid);
+ int fd = open(text, O_WRONLY);
+ if (fd >= 0) {
+ sprintf(text, "%d", adj);
+ write(fd, text, strlen(text));
+ close(fd);
}
+ return true;
#endif
return false;
}
@@ -354,25 +352,12 @@
jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
{
- #if HAVE_ANDROID_OS
return setuid(uid) == 0 ? 0 : errno;
- #else
- return ENOSYS;
- #endif
}
jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
{
- #if HAVE_ANDROID_OS
return setgid(uid) == 0 ? 0 : errno;
- #else
- return ENOSYS;
- #endif
-}
-
-jboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)
-{
- return ProcessState::self()->supportsProcesses();
}
static int pid_compare(const void* v1, const void* v2)
@@ -878,7 +863,6 @@
{"setGid", "(I)I", (void*)android_os_Process_setGid},
{"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
{"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
- {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
{"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
{"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
{"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 681f43f..e201964 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -859,10 +859,8 @@
const char* const kActivityThreadPathName = "android/app/ActivityThread";
-int register_android_app_ActivityThread(JNIEnv* env)
-{
- return AndroidRuntime::registerNativeMethods(
- env, kActivityThreadPathName,
+int register_android_app_ActivityThread(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kActivityThreadPathName,
gActivityThreadMethods, NELEM(gActivityThreadMethods));
}
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index b046b23..9484c6b 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -19,11 +19,48 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
#include <gui/SurfaceTexture.h>
+#include <gui/SurfaceTextureClient.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
namespace android {
// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+static struct {
+ jmethodID set;
+ jfieldID left;
+ jfieldID top;
+ jfieldID right;
+ jfieldID bottom;
+} gRectClassInfo;
+
+static struct {
+ jfieldID nativeCanvas;
+ jfieldID surfaceFormat;
+} gCanvasClassInfo;
+
+static struct {
+ jfieldID nativeWindow;
+} gTextureViewClassInfo;
+
+#define GET_INT(object, field) \
+ env->GetIntField(object, field)
+
+#define SET_INT(object, field, value) \
+ env->SetIntField(object, field, value)
+
+#define INVOKEV(object, method, ...) \
+ env->CallVoidMethod(object, method, __VA_ARGS__)
+
+// ----------------------------------------------------------------------------
// Native layer
// ----------------------------------------------------------------------------
@@ -34,6 +71,118 @@
surfaceTexture->setDefaultBufferSize(width, height);
}
+static inline SkBitmap::Config convertPixelFormat(int32_t format) {
+ switch (format) {
+ case WINDOW_FORMAT_RGBA_8888:
+ return SkBitmap::kARGB_8888_Config;
+ case WINDOW_FORMAT_RGBX_8888:
+ return SkBitmap::kARGB_8888_Config;
+ case WINDOW_FORMAT_RGB_565:
+ return SkBitmap::kRGB_565_Config;
+ default:
+ return SkBitmap::kNo_Config;
+ }
+}
+
+/**
+ * This is a private API, and this implementation is also provided in the NDK.
+ * However, the NDK links against android_runtime, which means that using the
+ * NDK implementation would create a circular dependency between the libraries.
+ */
+static int32_t native_window_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
+ Rect* inOutDirtyBounds) {
+ return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
+}
+
+static int32_t native_window_unlockAndPost(ANativeWindow* window) {
+ return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
+}
+
+static void android_view_TextureView_createNativeWindow(JNIEnv* env, jobject textureView,
+ jobject surface) {
+
+ sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+ sp<ANativeWindow> window = new SurfaceTextureClient(surfaceTexture);
+
+ window->incStrong(0);
+ SET_INT(textureView, gTextureViewClassInfo.nativeWindow, jint(window.get()));
+}
+
+static void android_view_TextureView_destroyNativeWindow(JNIEnv* env, jobject textureView) {
+
+ ANativeWindow* nativeWindow = (ANativeWindow*)
+ GET_INT(textureView, gTextureViewClassInfo.nativeWindow);
+
+ if (nativeWindow) {
+ sp<ANativeWindow> window(nativeWindow);
+ window->decStrong(0);
+ SET_INT(textureView, gTextureViewClassInfo.nativeWindow, 0);
+ }
+}
+
+static void android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
+ jint nativeWindow, jobject canvas, jobject dirtyRect) {
+
+ if (!nativeWindow) {
+ return;
+ }
+
+ ANativeWindow_Buffer buffer;
+
+ Rect rect;
+ if (dirtyRect) {
+ rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
+ rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
+ rect.right = GET_INT(dirtyRect, gRectClassInfo.right);
+ rect.bottom = GET_INT(dirtyRect, gRectClassInfo.bottom);
+ } else {
+ rect.set(Rect(0x3FFF, 0x3FFF));
+ }
+
+ sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
+ native_window_lock(window.get(), &buffer, &rect);
+
+ ssize_t bytesCount = buffer.stride * bytesPerPixel(buffer.format);
+
+ SkBitmap bitmap;
+ bitmap.setConfig(convertPixelFormat(buffer.format), buffer.width, buffer.height, bytesCount);
+
+ if (buffer.format == WINDOW_FORMAT_RGBX_8888) {
+ bitmap.setIsOpaque(true);
+ }
+
+ if (buffer.width > 0 && buffer.height > 0) {
+ bitmap.setPixels(buffer.bits);
+ } else {
+ bitmap.setPixels(NULL);
+ }
+
+ SET_INT(canvas, gCanvasClassInfo.surfaceFormat, buffer.format);
+ SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+ nativeCanvas->setBitmapDevice(bitmap);
+
+ SkRect clipRect;
+ clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
+ nativeCanvas->clipRect(clipRect);
+
+ if (dirtyRect) {
+ INVOKEV(dirtyRect, gRectClassInfo.set,
+ int(rect.left), int(rect.top), int(rect.right), int(rect.bottom));
+ }
+}
+
+static void android_view_TextureView_unlockCanvasAndPost(JNIEnv* env, jobject,
+ jint nativeWindow, jobject canvas) {
+
+ SkCanvas* nativeCanvas = (SkCanvas*) GET_INT(canvas, gCanvasClassInfo.nativeCanvas);
+ nativeCanvas->setBitmapDevice(SkBitmap());
+
+ if (nativeWindow) {
+ sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
+ native_window_unlockAndPost(window.get());
+ }
+}
+
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -42,10 +191,47 @@
static JNINativeMethod gMethods[] = {
{ "nSetDefaultBufferSize", "(Landroid/graphics/SurfaceTexture;II)V",
- (void*) android_view_TextureView_setDefaultBufferSize }
+ (void*) android_view_TextureView_setDefaultBufferSize },
+
+ { "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
+ (void*) android_view_TextureView_createNativeWindow },
+ { "nDestroyNativeWindow", "()V",
+ (void*) android_view_TextureView_destroyNativeWindow },
+
+ { "nLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)V",
+ (void*) android_view_TextureView_lockCanvas },
+ { "nUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
+ (void*) android_view_TextureView_unlockCanvasAndPost },
};
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(!var, "Unable to find class " className);
+
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+ var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+ LOG_FATAL_IF(!var, "Unable to find method " methodName);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(!var, "Unable to find field" fieldName);
+
int register_android_view_TextureView(JNIEnv* env) {
+ jclass clazz;
+ FIND_CLASS(clazz, "android/graphics/Rect");
+ GET_METHOD_ID(gRectClassInfo.set, clazz, "set", "(IIII)V");
+ GET_FIELD_ID(gRectClassInfo.left, clazz, "left", "I");
+ GET_FIELD_ID(gRectClassInfo.top, clazz, "top", "I");
+ GET_FIELD_ID(gRectClassInfo.right, clazz, "right", "I");
+ GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
+
+ FIND_CLASS(clazz, "android/graphics/Canvas");
+ GET_FIELD_ID(gCanvasClassInfo.nativeCanvas, clazz, "mNativeCanvas", "I");
+ GET_FIELD_ID(gCanvasClassInfo.surfaceFormat, clazz, "mSurfaceFormat", "I");
+
+ FIND_CLASS(clazz, "android/view/TextureView");
+ GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "I");
+
return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/com_android_internal_graphics_NativeUtils.cpp b/core/jni/com_android_internal_graphics_NativeUtils.cpp
deleted file mode 100644
index 9cc43606..0000000
--- a/core/jni/com_android_internal_graphics_NativeUtils.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AWT"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "GraphicsJNI.h"
-#include <android_runtime/AndroidRuntime.h>
-
-#include "SkCanvas.h"
-#include "SkDevice.h"
-#include "SkPicture.h"
-#include "SkTemplates.h"
-
-namespace android
-{
-
-static jboolean scrollRect(JNIEnv* env, jobject graphics2D, jobject canvas, jobject rect, int dx, int dy) {
- if (canvas == NULL) {
- jniThrowNullPointerException(env, NULL);
- return false;
- }
-
- SkIRect src, *srcPtr = NULL;
- if (NULL != rect) {
- GraphicsJNI::jrect_to_irect(env, rect, &src);
- srcPtr = &src;
- }
- SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
- const SkBitmap& bitmap = c->getDevice()->accessBitmap(true);
- return bitmap.scrollRect(srcPtr, dx, dy, NULL);
-}
-
-static JNINativeMethod method_table[] = {
- { "nativeScrollRect",
- "(Landroid/graphics/Canvas;Landroid/graphics/Rect;II)Z",
- (void*)scrollRect}
-};
-
-int register_com_android_internal_graphics_NativeUtils(JNIEnv *env) {
- return AndroidRuntime::registerNativeMethods(
- env, "com/android/internal/graphics/NativeUtils",
- method_table, NELEM(method_table));
-}
-
-}
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index 86fd9cb..7e5dede 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -27,13 +27,11 @@
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
-#ifdef HAVE_ANDROID_OS
#include <linux/capability.h>
#include <linux/prctl.h>
#include <sys/prctl.h>
extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
-#endif
namespace android {
@@ -168,7 +166,6 @@
static void com_android_internal_os_ZygoteInit_setCapabilities (JNIEnv *env,
jobject clazz, jlong permitted, jlong effective)
{
-#ifdef HAVE_ANDROID_OS
struct __user_cap_header_struct capheader;
struct __user_cap_data_struct capdata;
int err;
@@ -190,15 +187,11 @@
jniThrowIOException(env, errno);
return;
}
-#endif /* HAVE_ANDROID_OS */
}
static jlong com_android_internal_os_ZygoteInit_capgetPermitted (JNIEnv *env,
jobject clazz, jint pid)
{
-#ifndef HAVE_ANDROID_OS
- return (jlong)0;
-#else
struct __user_cap_header_struct capheader;
struct __user_cap_data_struct capdata;
int err;
@@ -217,7 +210,6 @@
}
return (jlong) capdata.permitted;
-#endif /* HAVE_ANDROID_OS */
}
static jint com_android_internal_os_ZygoteInit_selectReadable (
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 49eaf19..0397dfa 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1489,9 +1489,6 @@
android:excludeFromRecents="true">
</activity>
- <service android:name="com.android.server.LoadAverageService"
- android:exported="true" />
-
<service android:name="com.android.internal.service.wallpaper.ImageWallpaper"
android:permission="android.permission.BIND_WALLPAPER">
</service>
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
index 5225a81..acbbb38 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
index 2e7e973..6009528 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
index 4591627..30727d7 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
index 9cf1826..7cea5e1 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
index a47ef40..ba0d612 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
index 9b50c73..e8646b9 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
index a0d36de..14cb4c9 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
index 805b9567..80fd218 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
index b0fba52..1014d8a 100644
--- a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
index 3ef8935..18cd171 100644
--- a/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index 9769bbb..ad2cb5a 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame_holo.9.png b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
index 9769bbb..ad2cb5a 100644
--- a/core/res/res/drawable-hdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
index a0bd4e3..4836da1 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
index 12abcd2..c299931 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
index adb8104..86edad7 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
index d7c6bbf..53ee68b 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
index 42cfc52..606adaf 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
index 9a08e15..14d2e5e 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
index 5d86b2a..2646332 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
index ad22f5b..48ec0a4 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
index 923f92d..dd5dd39 100644
--- a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
index afada39..12d65be 100644
--- a/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 06cfc70..b9105de 100755
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame_holo.9.png b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
index 06cfc70..b9105de 100755
--- a/core/res/res/drawable-mdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
index b33e117..077e4d3 100644
--- a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
index d84d427..357c17f 100644
--- a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
index 9c0ff47..5b510721 100644
--- a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
index 331a4f2..2705a39 100644
--- a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
index cdc887d..101876f 100644
--- a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
index bdb6824..0df1503 100644
--- a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
index 600efb3..344a4e2 100644
--- a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
index aa8401d..249848f 100644
--- a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png
new file mode 100644
index 0000000..92acc47
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png
new file mode 100644
index 0000000..4e54b4b6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/menu_dropdown_panel_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
index f7debee..9f39a77 100644
--- a/core/res/res/drawable-xhdpi/toast_frame.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
index f7debee..9f39a77 100644
--- a/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
+++ b/core/res/res/drawable-xhdpi/toast_frame_holo.9.png
Binary files differ
diff --git a/core/res/res/layout/activity_chooser_list_footer.xml b/core/res/res/layout/activity_chooser_list_footer.xml
deleted file mode 100644
index c05ba1a..0000000
--- a/core/res/res/layout/activity_chooser_list_footer.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/list_footer"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="vertical">
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="2dip"
- android:background="@android:color/holo_blue_light" />
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="48dip"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:duplicateParentState="true"
- android:singleLine="true"
- android:text="@string/activity_chooser_view_see_all" />
-
-</LinearLayout>
diff --git a/core/res/res/layout/activity_chooser_list_header.xml b/core/res/res/layout/activity_chooser_list_header.xml
deleted file mode 100644
index 0fb256f..0000000
--- a/core/res/res/layout/activity_chooser_list_header.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/list_header"
- android:paddingLeft="16dip"
- android:paddingRight="16dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="?android:attr/dropdownListPreferredItemHeight"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:duplicateParentState="true"
- android:singleLine="true" />
-
- <View
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="2dip"
- android:src="@drawable/divider_strong_holo" />
-
-</LinearLayout>
diff --git a/core/res/res/layout/activity_chooser_view.xml b/core/res/res/layout/activity_chooser_view.xml
index ccf49fc..50b1878 100644
--- a/core/res/res/layout/activity_chooser_view.xml
+++ b/core/res/res/layout/activity_chooser_view.xml
@@ -23,13 +23,9 @@
style="?android:attr/actionButtonStyle">
<ImageButton android:id="@+id/default_activity_button"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_marginLeft="16dip" />
+ style="@style/Widget.ActivityChooserViewButton" />
<ImageButton android:id="@+id/expand_activities_button"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_marginLeft="16dip" />
+ style="@style/Widget.ActivityChooserViewButton" />
</LinearLayout>
diff --git a/core/res/res/layout/activity_chooser_view_list_item.xml b/core/res/res/layout/activity_chooser_view_list_item.xml
index 61b7e70..88498d9 100644
--- a/core/res/res/layout/activity_chooser_view_list_item.xml
+++ b/core/res/res/layout/activity_chooser_view_list_item.xml
@@ -18,26 +18,36 @@
android:id="@+id/list_item"
android:layout_width="match_parent"
android:layout_height="?android:attr/dropdownListPreferredItemHeight"
- android:gravity="center_vertical"
android:paddingLeft="16dip"
- android:paddingRight="16dip">
+ android:paddingRight="16dip"
+ android:minWidth="196dip"
+ android:background="?android:attr/activatedBackgroundIndicator"
+ android:orientation="vertical" >
- <ImageView
- android:id="@+id/icon"
- android:layout_width="32dip"
- android:layout_height="32dip"
- android:layout_gravity="center_vertical"
- android:layout_marginRight="8dip"
- android:duplicateParentState="true" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:duplicateParentState="true" >
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
- android:singleLine="true"
- android:duplicateParentState="true"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal" />
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="8dip"
+ android:duplicateParentState="true" />
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
+ android:duplicateParentState="true"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ </LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/list_menu_item_icon.xml b/core/res/res/layout/list_menu_item_icon.xml
index 6ff14dd..27dd9b8 100644
--- a/core/res/res/layout/list_menu_item_icon.xml
+++ b/core/res/res/layout/list_menu_item_icon.xml
@@ -19,6 +19,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginRight="8dip"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="-8dip"
+ android:layout_marginTop="8dip"
+ android:layout_marginBottom="8dip"
+ android:scaleType="centerInside"
android:duplicateParentState="true" />
diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml
index fef017d..1a12c01 100644
--- a/core/res/res/layout/popup_menu_item_layout.xml
+++ b/core/res/res/layout/popup_menu_item_layout.xml
@@ -18,7 +18,6 @@
android:layout_width="match_parent"
android:layout_height="?android:attr/dropdownListPreferredItemHeight"
android:minWidth="196dip"
- android:paddingLeft="16dip"
android:paddingRight="16dip">
<!-- Icon will be inserted here. -->
@@ -29,6 +28,7 @@
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
+ android:layout_marginLeft="16dip"
android:duplicateParentState="true">
<TextView
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index fb898ee..4e7981a 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -44,8 +44,8 @@
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
+ android:paddingTop="@dimen/preference_screen_header_vertical_padding"
+ android:paddingBottom="@dimen/preference_screen_header_vertical_padding"
android:drawSelectorOnTop="false"
android:cacheColorHint="@android:color/transparent"
android:listPreferredItemHeight="48dp"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 8a75bd0..6d9f2fe 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -931,6 +931,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lees blaaier se geskiedenis en boekmerke"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Laat die program toe om al die URL\'e te lees wat die blaaier besoek het, asook al die blaaier se boekmerke."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"skryf blaaier se geskiedenis en boekmerke"</string>
@@ -1437,8 +1461,8 @@
<skip />
<!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
<skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 52745b9..9fff387 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -931,6 +931,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">"፣ "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"የአሳሽ ታሪኮች እና ዕልባቶች አንብብ።"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"ትግበራው ማሰሻው የጎበኛቸውን ሁሉ URL ኦች፣ እና የማሰሻውን ዕልባቶች ሁሉ ለማንበብ ይፈቅዳል።"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"የአሳሾች ታሪክ እና ዕልባቶች ፃፍ"</string>
@@ -1437,8 +1461,8 @@
<skip />
<!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
<skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f37410b..70fc500 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">"، "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"قراءة سجل المتصفح والإشارات"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"للسماح للتطبيق بقراءة جميع عناوين URL التي انتقل إليها المتصفح. وجميع إشارات المتصفح."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"كتابة سجل المتصفح والإشارات"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"إذا شغّلت سعة تخزين USB، فستتوقف بعض التطبيقات التي تستخدمها وربما تصبح غير متاحة لحين إيقاف تشغيل سعة تخزين USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"أخفقت عملية USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"موافق"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"التوصيل كجهاز وسائط"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"التوصيل ككاميرا"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"التوصيل كأداة تثبيت"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"المس للاطلاع على خيارات USB الأخرى"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"تهيئة وحدة تخزين USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"تنسيق بطاقة SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"هل تريد تهيئة وحدة تخزين USB، ومحو كل الملفات المخزنة بها؟ لا يمكن عكس هذا الإجراء!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"إمكانية الدخول"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"الخلفية"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"تم تنشيط الشبكة الظاهرية الخاصة (VPN)."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط الشبكة الظاهرية الخاصة (VPN) بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"انقر لإدارة الشبكة."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"تم الاتصال بـ <xliff:g id="SESSION">%s</xliff:g>. انقر لإدارة الشبكة."</string>
<string name="upload_file" msgid="2897957172366730416">"اختيار ملف"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"الصلاحية:"</string>
<string name="issued_on" msgid="5895017404361397232">"تاريخ الإصدار:"</string>
<string name="expires_on" msgid="3676242949915959821">"تنتهي الصلاحية في:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"الرقم المسلسل:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"بصمات الأصابع:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"بصمة أصبع SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"بصمة أصبع SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"عرض الكل..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 9147fb5..b67812a 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"четене на историята и отметките на браузъра"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Разрешава на приложението да чете всички URL адреси, посетени от браузъра, и всички негови отметки."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"запис в историята и отметките на браузъра"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Ако включите работата като USB устройство за съхранение, някои използвани от вас приложения ще спрат и може да бъдат недостъпни, докато не я изключите."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Операцията през USB не бе успешна"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Свързан като медийно устройство"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Свързан като камера"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Свързан като инсталационна програма"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Докоснете за други опции за USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Форматиране на USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Форматиране на SD картата"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Да се форматира ли USB хранилището, изтривайки всички файлове в него? Действието не може да бъде отменено!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Достъпност"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Тапет"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN е активирана."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Докоснете за управление на мрежата."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Свързана с/ъс <xliff:g id="SESSION">%s</xliff:g>. Докоснете, за да управлявате мрежата."</string>
<string name="upload_file" msgid="2897957172366730416">"Избор на файл"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Валидност:"</string>
<string name="issued_on" msgid="5895017404361397232">"Издаден на:"</string>
<string name="expires_on" msgid="3676242949915959821">"Изтича на:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Сериен номер:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Пръстови отпечатъци:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Пръстов отпечатък SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Пръстов отпечатък SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Вижте всички..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index b7117b9..c7b1735 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"llegir l\'historial i les adreces d\'interès del navegador"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permet a l\'aplicació llegir tots els URL que ha visitat el navegador i totes les adreces d\'interès del navegador."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escriure l\'historial i les adreces d\'interès del navegador"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Si activeu l\'emmagatzematge USB, algunes de les aplicacions que utilitzeu s\'aturaran i pot ser que no estiguin disponibles fins que desactiveu l\'emmagatzematge USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Error de l\'operació d\'USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"D\'acord"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connectat com a dispositiu multimèdia"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connectat com a càmera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connectat com a instal·lador"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Toca per obtenir altres opcions d\'USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formata l\'emmag. USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formata la targeta SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Vols formatar l\'emmagatzematge USB i esborrar tots els fitxers que hi ha emmagatzemats? L\'acció no es podrà desfer."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilitat"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Empaperat"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Canvi de l\'empaperat"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN activada."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
<string name="vpn_text" msgid="1610714069627824309">"Pica per gestionar la xarxa."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Connectat a <xliff:g id="SESSION">%s</xliff:g>. Pica per gestionar la xarxa."</string>
<string name="upload_file" msgid="2897957172366730416">"Trieu un fitxer"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validesa:"</string>
<string name="issued_on" msgid="5895017404361397232">"Emès el:"</string>
<string name="expires_on" msgid="3676242949915959821">"Caduca el:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Número de sèrie:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Empremtes"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Empremta SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Empremta SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Mostra-ho tot"</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ecd83dd..944eb2f 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"čtení historie a záložek Prohlížeče"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Umožňuje aplikaci číst všechny navštívené adresy URL a záložky Prohlížeče."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"zápis do historie a záložek Prohlížeče"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Pokud zapnete úložiště USB, dojde k zastavení některých používaných aplikací. Tyto aplikace pravděpodobně nebudou k dispozici až do vypnutí úložiště USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Chyba operace na rozhraní USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Připojeno jako mediální zařízení"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Připojeno jako fotoaparát"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Připojeno jako instalátor"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Dotykem zobrazíte další možnosti USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formátovat úložiště USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formátovat kartu SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Chcete úložiště USB zformátovat a tím smazat všechny soubory, které v něm jsou uloženy? Tuto akci nelze vrátit zpět."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Usnadnění"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"Síť VPN je aktivována."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
<string name="vpn_text" msgid="1610714069627824309">"Klepnutím zobrazíte správu sítě."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Připojeno k relaci <xliff:g id="SESSION">%s</xliff:g>. Klepnutím můžete síť spravovat."</string>
<string name="upload_file" msgid="2897957172366730416">"Zvolit soubor"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Platnost:"</string>
<string name="issued_on" msgid="5895017404361397232">"Datum vydání:"</string>
<string name="expires_on" msgid="3676242949915959821">"Platnost vyprší:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Sériové číslo:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Digitální otisky:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Digitální otisk SHA-256"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Digitální otisk SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Zobrazit vše..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 67de2aa..c573322 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"læs browserens oversigt og bogmærker"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Tillader, at applikationen læser alle de webadresser, browseren har besøgt, og alle browserens bogmærker."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"skriv browserens oversigt og bogmærker"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Hvis du slår USB-lagring til, vil nogle af de applikationer, som du bruger, stoppe, og de kan være utilgængelige, indtil du slår USB-lagring til igen."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-handlingen mislykkedes"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Tilsluttet som en medieenhed"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Tilsluttet som et kamera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Tilsluttet som et installationsprogram"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Tryk for at se andre valgmuligheder for USB-tilslutning"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formater USB-lager"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formater SD-kort"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Vil du formatere USB-lager og slette alle filer, som er gemt der? Handlingen kan ikke fortrydes!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgængelighed"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapet"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Skift tapet"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN er aktiveret."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Tryk for at administrere netværket."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Forbundet til <xliff:g id="SESSION">%s</xliff:g>. Tryk for at administrere netværket."</string>
<string name="upload_file" msgid="2897957172366730416">"Vælg fil"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Gyldighed:"</string>
<string name="issued_on" msgid="5895017404361397232">"Udstedt den:"</string>
<string name="expires_on" msgid="3676242949915959821">"Udløber den:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serienummer:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Fingeraftryk:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256-fingeraftryk:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1-fingeraftryk:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Se alle..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index b4203b6..723d0a9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Browserverlauf und Lesezeichen lesen"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der App, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Browserverlauf und Lesezeichen schreiben"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Wenn Sie den USB-Speicher aktivieren, werden einige von Ihnen verwendete Anwendungen angehalten und sind möglicherweise nicht verfügbar, bis Sie den USB-Speicher wieder deaktivieren."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-Vorgang fehlgeschlagen"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Als Mediengerät angeschlossen"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Als Kamera angeschlossen"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Als Installationsprogramm angeschlossen"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Zum Anzeigen weiterer USB-Optionen tippen"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB-Sp. formatieren"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD-Karte formatieren"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"USB-Speicher formatieren und alle darin befindlichen Dateien löschen? Diese Aktion kann nicht rückgängig gemacht werden!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Eingabehilfen"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Hintergrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN ist aktiviert."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
<string name="vpn_text" msgid="1610714069627824309">"Zum Verwalten des Netzwerks tippen"</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Verbunden mit <xliff:g id="SESSION">%s</xliff:g>. Zum Verwalten des Netzwerks tippen"</string>
<string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Gültigkeit:"</string>
<string name="issued_on" msgid="5895017404361397232">"Ausgegeben am:"</string>
<string name="expires_on" msgid="3676242949915959821">"Läuft ab am:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Seriennummer:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Fingerabdrücke:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256-Fingerabdruck:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1-Fingerabdruck:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Alle anzeigen..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ae72132..22a74b9 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ανάγνωση ιστορικού και σελιδοδεικτών προγράμματος περιήγησης"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Επιτρέπει στην εφαρμογή την ανάγνωση όλων των διευθύνσεων URL που το πρόγραμμα περιήγησης έχει επισκεφθεί και όλων των σελιδοδεικτών του προγράμματος περιήγησης."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"εγγραφή ιστορικού και σελιδοδεικτών προγράμματος περιήγησης"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Εάν ενεργοποιήσετε τον αποθηκευτικό χώρο USB, ορισμένες από τις εφαρμογές που χρησιμοποιείτε θα σταματήσουν και ενδέχεται να μην είναι διαθέσιμες μέχρι να απενεργοποιήσετε τον αποθηκευτικό χώρο USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Απέτυχε η λειτουργία USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ΟΚ"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Συνδεδεμένο ως συσκευή πολυμέσων"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Συνδεδεμένο ως φωτογραφική μηχανή"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Συνδεδεμένο ως πρόγραμμα εγκατάστασης"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Αγγίξτε για άλλες επιλογές USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Διαγρ. απ. χώρου USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Διαμόρφωση κάρτας SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Να γίνει διαγραφή του αποθηκευτικού χώρου USB, η οποία θα διαγράψει όλα τα αρχεία που έχετε αποθηκεύσει εκεί; Η ενέργεια είναι μη αναστρέψιμη!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Προσβασιμότητα"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ταπετσαρία"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"Το VPN είναι ενεργοποιημένο."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Πατήστε για να διαχειριστείτε το δίκτυο."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Συνδέθηκε με <xliff:g id="SESSION">%s</xliff:g>. Πατήστε για να διαχειριστείτε το δίκτυο."</string>
<string name="upload_file" msgid="2897957172366730416">"Επιλογή αρχείου"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Ισχύς:"</string>
<string name="issued_on" msgid="5895017404361397232">"Εκδόθηκε στις:"</string>
<string name="expires_on" msgid="3676242949915959821">"Λήγει στις:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Σειριακός αριθμός:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Αποτυπώματα"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Αποτύπωμα SHA-256"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Αποτύπωμα SHA-1"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Εμφάνιση όλων..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index d26628c..2bf09f6 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -701,6 +701,18 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Province"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Postcode"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"State"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Zip code"</string>
+ <string name="autofill_county" msgid="237073771020362891">"County"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Island"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"District"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Department"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Prefecture"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Parish"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Area"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Emirate"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"read Browser\'s history and bookmarks"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Allows the application to read all the URLs that the browser has visited and all of the browser\'s bookmarks."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"write Browser\'s history and bookmarks"</string>
@@ -944,14 +956,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"If you turn on USB storage, some applications that you are using will stop and may be unavailable until you turn off USB storage."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB operation failed"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connected as a media device"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connected as a camera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connected as an installer"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Touch for other USB options"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Format USB storage"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Format SD card"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Format USB storage, erasing all files stored there? Action cannot be reversed!"</string>
@@ -1015,10 +1023,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibility"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN is activated."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Tap to manage the network."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Connected to <xliff:g id="SESSION">%s</xliff:g>. Tap to manage the network."</string>
<string name="upload_file" msgid="2897957172366730416">"Choose file"</string>
@@ -1095,18 +1101,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validity:"</string>
<string name="issued_on" msgid="5895017404361397232">"Issued on:"</string>
<string name="expires_on" msgid="3676242949915959821">"Expires on:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serial number:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Fingerprints:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 fingerprint"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 fingerprint"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"See all..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 305b131..ea642c9 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leer historial y marcadores del navegador"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite a la aplicación leer todas las URL que ha visitado el navegador y todos los marcadores del navegador."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir historial y marcadores del navegador"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Si activas el almacenamiento USB, algunas aplicaciones que estás usando se detendrán y es posible que no estén disponibles hasta que desactives el almacenamiento USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Error en el funcionamiento del USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como un dispositivo de medios"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como un instalador"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Toca para otras opciones de USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatear almacenamiento USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatear tarjeta SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"¿Deseas formatear el almacenamiento USB y borrar todos los archivos almacenados aquí? ¡Esta acción no se puede cambiar!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Papel tapiz"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN está activado."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Pulsa para gestionar la red."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Pulsa para gestionar la red."</string>
<string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validez:"</string>
<string name="issued_on" msgid="5895017404361397232">"Emitido:"</string>
<string name="expires_on" msgid="3676242949915959821">"Expira el:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Número de serie:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Huellas digitales:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Huella digital SHA-256"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Huella digital SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Ver todas..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index f3d1d66..44e1c94 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -701,6 +701,18 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Provincia"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Código postal"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"Estado"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Código postal"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Condado"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Isla"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"Distrito"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Departamento"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Prefectura"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Distrito"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Área"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Emirato"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leer información de marcadores y del historial del navegador"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite que la aplicación lea todas las URL que ha visitado el navegador y todos sus marcadores."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir en marcadores y en el historial del navegador"</string>
@@ -944,14 +956,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Si activas el almacenamiento USB, se detendrán algunas aplicaciones que estás utilizando y estas no estarán disponibles hasta que lo desactives."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"No se ha podido realizar la operación USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Aceptar"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como un dispositivo de medios"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectado como una cámara"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectado como instalador"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Tocar para acceder a otras opciones de USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatear USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatear tarjeta SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"¿Quieres formatear el USB y borrar todos los archivos? Esta acción no se puede deshacer."</string>
@@ -1015,10 +1023,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fondo de pantalla"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN activada"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Toca para administrar la red."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toca para administrar la red."</string>
<string name="upload_file" msgid="2897957172366730416">"Seleccionar archivo"</string>
@@ -1095,18 +1101,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validez:"</string>
<string name="issued_on" msgid="5895017404361397232">"Fecha de emisión:"</string>
<string name="expires_on" msgid="3676242949915959821">"Fecha de caducidad:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Número de serie:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Huellas digitales:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Huella digital SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Huella digital SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Ver todas..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index aae9760..14943a1 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">"، "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"خواندن سابقه و نشانک های مرورگر"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"به برنامه کاربردی اجازه می دهد تا تمام URL های بازدید شده توسط مرورگر و تمام نشانک های آن را بخواند."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"نوشتن سابقه مرورگر و نشانک ها"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"در صورت روشن کردن دستگاه ذخیره سازی USB، برخی از برنامه هایی که از آنها استفاده می کنید متوقف می شوند و تا زمانی که دستگاه ذخیره سازی USB را خاموش نکنید امکان استفاده از آنها وجود نخواهد داشت."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"عملکرد USB انجام نشد"</string>
<string name="dlg_ok" msgid="7376953167039865701">"تأیید"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"متصل شده به عنوان دستگاه رسانه ای"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"متصل شده به عنوان دوربین"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"متصل شده به عنوان نصب کننده"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"برای سایر گزینه های USB لمس کنید"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"فرمت کردن حافظه USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"فرمت کردن کارت SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"فرمت کردن حافظه USB، همه فایل های ذخیره شده در آنجا پاک شود؟ عملکرد قابل بازگشت نیست!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"قابلیت دسترسی"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"تصویر زمینه"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر تصویر زمینه"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN فعال است."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
<string name="vpn_text" msgid="1610714069627824309">"برای مدیریت شبکه ضربه بزنید."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"به <xliff:g id="SESSION">%s</xliff:g> متصل شد. برای مدیریت شبکه ضربه بزنید."</string>
<string name="upload_file" msgid="2897957172366730416">"انتخاب فایل"</string>
@@ -1093,20 +1111,15 @@
<string name="org_unit" msgid="7265981890422070383">"واحد سازمانی:"</string>
<string name="issued_by" msgid="2647584988057481566">"صادر شده توسط:"</string>
<string name="validity_period" msgid="8818886137545983110">"اعتبار:"</string>
- <string name="issued_on" msgid="5895017404361397232">"تاریخ صدور:"</string>
+ <string name="issued_on" msgid="5895017404361397232">"صادر شده در:"</string>
<string name="expires_on" msgid="3676242949915959821">"تاریخ انقضا:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"شماره سریال:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"اثر انگشت:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"اثر انگشت SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"اثر انگشت SHA-1"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"مشاهده همه..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 962383a..fcae45c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lue selaimen historiaa ja kirjanmerkkejä"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Antaa sovelluksen lukea kaikki selaimen käyttämät URL-osoitteet ja selaimen kirjanmerkit."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"kirjoita selaimen historiaa ja kirjanmerkkejä"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Jos otat USB-tallennustilan käyttöön, osa käyttämistäsi sovelluksista pysähtyy eivätkä ne välttämättä ole käytössä kunnes poistat USB-tallennustilan käytöstä."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-toiminto epäonnistui"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Kytketty medialaitteena"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Kytketty kamerana"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Kytketty asennusohjelmana"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Käytä muita USB-vaihtoehtoja koskettamalla"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Alusta USB-tila"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Alusta SD-kortti"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Haluatko alustaa USB-tilan ja poistaa kaikki siellä olevat tiedostot? Toimintoa ei voi peruuttaa!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Esteettömyys"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustakuva"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN on aktivoitu."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
<string name="vpn_text" msgid="1610714069627824309">"Napauta, niin voit hallinnoida verkkoa."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Yhdistetty: <xliff:g id="SESSION">%s</xliff:g>. Hallinnoi verkkoa napauttamalla."</string>
<string name="upload_file" msgid="2897957172366730416">"Valitse tiedosto"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Voimassa:"</string>
<string name="issued_on" msgid="5895017404361397232">"Myönnetty:"</string>
<string name="expires_on" msgid="3676242949915959821">"Vanhenee:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Sarjanumero"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Tunnistetiedostot:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256-tunnistetiedosto"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1-tunnistetiedosto"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Näytä kaikki..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f9aa46e..be75a7e 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lire l\'historique et les favoris du navigateur"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Autorise l\'application à lire toutes les URL auxquelles le navigateur a accédé et tous ses favoris."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"écrire dans l\'historique et les favoris du navigateur"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Si vous activez la mémoire de stockage USB, certaines applications en cours d\'utilisation seront fermées. Elles risquent de rester indisponibles jusqu\'à ce que la mémoire de stockage USB soit désactivée."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Échec du fonctionnement USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Connecté en tant qu\'appareil multimédia"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Connecté en tant qu\'appareil photo"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Connecté en tant que programme d\'installation"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Appuyez pour accéder aux autres options USB."</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formater la mémoire USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formater la carte SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formater la mémoire de stockage USB en effaçant tous les fichiers ? Cette action est irréversible."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilité"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fond d\'écran"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN activé"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Appuyez ici pour gérer le réseau."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Connecté à <xliff:g id="SESSION">%s</xliff:g>. Appuyez ici pour gérer le réseau."</string>
<string name="upload_file" msgid="2897957172366730416">"Sélectionner un fichier"</string>
@@ -1090,23 +1108,18 @@
<string name="issued_to" msgid="454239480274921032">"Délivré à :"</string>
<string name="common_name" msgid="2233209299434172646">"Nom commun :"</string>
<string name="org_name" msgid="6973561190762085236">"Organisation :"</string>
- <string name="org_unit" msgid="7265981890422070383">"Unité d\'organisation :"</string>
+ <string name="org_unit" msgid="7265981890422070383">"Unité organisationnelle :"</string>
<string name="issued_by" msgid="2647584988057481566">"Émis par :"</string>
<string name="validity_period" msgid="8818886137545983110">"Validité :"</string>
<string name="issued_on" msgid="5895017404361397232">"Date d\'émission :"</string>
<string name="expires_on" msgid="3676242949915959821">"Date d\'expiration :"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Numéro de série :"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Empreintes :"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Empreinte SHA-256 :"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Empreinte SHA-1 :"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Tout afficher..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index acb7f27..cf119d5 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"čitanje povijesti i oznaka preglednika"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Aplikaciji omogućuje čitanje svih URL-ova koje je preglednik posjetio i svih oznaka iz preglednika."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"pisanje povijesti i oznaka preglednika"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Ako uključite USB pohranjivanje, neke aplikacije koje koristite zaustavit će se i možda neće biti dostupne sve dok ne isključite USB pohranjivanje."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Rad USB-a nije uspio"</string>
<string name="dlg_ok" msgid="7376953167039865701">"U redu"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Spojen kao medijski uređaj"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Spojen kao fotoaparat"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Spojen kao instalacijski program"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Dodirnite za ostale opcije USB-a"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Format. USB memoriju"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatiraj SD karticu"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formatirati USB memoriju uz brisanje svih pohranjenih datoteka? Radnja se ne može poništiti!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Dostupnost"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadinska slika"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN je aktiviran."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
<string name="vpn_text" msgid="1610714069627824309">"Dotaknite za upravljanje mrežom."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Povezan sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dotaknite za upravljanje mrežom."</string>
<string name="upload_file" msgid="2897957172366730416">"Odaberite datoteku"</string>
@@ -1094,19 +1112,14 @@
<string name="issued_by" msgid="2647584988057481566">"Izdao:"</string>
<string name="validity_period" msgid="8818886137545983110">"Vrijedi do:"</string>
<string name="issued_on" msgid="5895017404361397232">"Izdano dana:"</string>
- <string name="expires_on" msgid="3676242949915959821">"Ističe dana:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="expires_on" msgid="3676242949915959821">"Istječe dana:"</string>
+ <string name="serial_number" msgid="758814067660862493">"Serijski broj:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Otisci prstiju:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 otisak prsta:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 otisak prsta:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Prikaži sve..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b27fb83..5fc1c31 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -701,6 +701,18 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Tartomány"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Irányítószám"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"Állam"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Irányítószám"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Ország"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Sziget"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"Körzet"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Osztály"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Prefektúra"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Közösség"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Terület"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Emirátus"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"böngészési előzmények és könyvjelzők olvasása"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Lehetővé teszi az alkalmazás számára a böngésző által felkeresett összes URL, valamint az összes könyvjelző olvasását."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"böngészési előzmények és könyvjelzők írása"</string>
@@ -944,14 +956,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Ha bekapcsolja az USB-tárat, egyes jelenleg használt alkalmazások leállnak és lehet, hogy nem lesznek elérhetők a tár újbóli kikapcsolásáig."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Az USB művelet sikertelen"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Csatlakoztatva médiaeszközként"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Csatlakoztatva kameraként"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Csatlakoztatva telepítőként"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Érintse meg a további USB-opciókért"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Az USB-tár formázása"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD-kártya formázása"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formázza az USB-tárat, törölve az összes ott tárolt fájlt? A művelet nem vonható vissza!"</string>
@@ -1015,10 +1023,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Kisegítő lehetőségek"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Háttérkép"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Háttérkép megváltoztatása"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN aktiválva."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
<string name="vpn_text" msgid="1610714069627824309">"Érintse meg a hálózat irányításához."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Csatlakozva ide: <xliff:g id="SESSION">%s</xliff:g>. Érintse meg a hálózat kezeléséhez."</string>
<string name="upload_file" msgid="2897957172366730416">"Fájl kiválasztása"</string>
@@ -1095,18 +1101,13 @@
<string name="validity_period" msgid="8818886137545983110">"Érvényesség:"</string>
<string name="issued_on" msgid="5895017404361397232">"Kiállítva:"</string>
<string name="expires_on" msgid="3676242949915959821">"Lejár:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Sorozatszám:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Ujjlenyomatok:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 ujjlenyomat:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 ujjlenyomat:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Összes megtekintése..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 2bfb6ce..fa7fefb 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"baca riwayat dan bookmark Peramban"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Izinkan aplikasi membaca semua URL yang telah dikunjungi Peramban, dam semua bookmark Peramban."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"tuliskan riwayat dan bookmark Peramban"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Jika Anda menghidupkan penyimpanan USB, sebagian aplikasi yang Anda gunakan akan berhenti dan mungkin tidak tersedia sampai Anda mematikan penyimpanan USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Operasi USB gagal"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Terhubung sebagai perangkat media"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Terhubung sebagai kamera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Terhubung sebagai pemasang"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Sentuh untuk opsi USB lainnya"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Format penyimpanan USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Format kartu SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Format penyimpanan USB, menghapus semua berkas yang disimpan di sana? Tindakan tidak dapat diurungkan!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Aksesibilitas"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN diaktifkan."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Ketuk untuk mengelola jaringan."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
<string name="upload_file" msgid="2897957172366730416">"Pilih berkas"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validitas:"</string>
<string name="issued_on" msgid="5895017404361397232">"Diterbitkan pada:"</string>
<string name="expires_on" msgid="3676242949915959821">"Kedaluwarsa pada:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Nomor seri:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Sidik jari:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Sidik jari SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Sidik jari SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Lihat semua..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index fcb4e3a..6e19cb5 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -491,8 +491,8 @@
<string name="permdesc_readNetworkUsageHistory" msgid="6040738474779135653">"Consente a un\'applicazione di leggere dati storici di utilizzo della rete per reti e applicazioni specifiche."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"gestione norme rete"</string>
<string name="permdesc_manageNetworkPolicy" msgid="3723795285132803958">"Consente a un\'applicazione di gestire le norme di rete e definire le regole specifiche delle applicazioni."</string>
- <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica dell\'effetto dell\'utilizzo della rete"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="8702285686629184404">"Consente la modifica dell\'effetto dell\'utilizzo della rete sulle applicazioni. Da non usare per normali applicazioni."</string>
+ <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"modifica calcolo dell\'utilizzo della rete"</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="8702285686629184404">"Consente di modificare le modalità di calcolo dell\'utilizzo della rete da parte delle applicazioni. Da non usare per normali applicazioni."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Imposta regole password"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Monitora tentativi di sblocco dello schermo"</string>
@@ -701,6 +701,18 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Provincia"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Codice postale"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"Stato"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Codice postale"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Contea"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Isola"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"Distretto"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Reparto"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Prefettura"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Parrocchia"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Area"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Emirato"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lettura cronologia e segnalibri del browser"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Consente all\'applicazione di leggere tutti gli URL visitati e tutti i segnalibri del browser."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"creazione cronologia e segnalibri del browser"</string>
@@ -944,14 +956,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Se attivi l\'archivio USB, alcune applicazioni in uso si bloccheranno e potrebbero risultare non disponibili finché non disattiverai l\'archivio USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Operazione USB non riuscita"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Collegato come dispositivo multimediale"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Collegato come fotocamera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Collegato come installer"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Tocca per altre opzioni USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatta archivio USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatta scheda SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formattare l\'archivio USB cancellando tutti i file memorizzati al suo interno? Questa azione è irreversibile."</string>
@@ -1015,10 +1023,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilità"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"La VPN è attiva."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Tocca per gestire la rete."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Collegata a <xliff:g id="SESSION">%s</xliff:g>. Tocca per gestire la rete."</string>
<string name="upload_file" msgid="2897957172366730416">"Scegli file"</string>
@@ -1095,18 +1101,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validità:"</string>
<string name="issued_on" msgid="5895017404361397232">"Rilasciato il:"</string>
<string name="expires_on" msgid="3676242949915959821">"Scade il:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Numero di serie:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Fingerprint:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Fingerprint SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Fingerprint SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Mostra tutto..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 31ae61f..9c8b81d 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"קרא היסטוריה וסימניות של דפדפן"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"מאפשר ליישום לקרוא את כל כתובות האתרים שבהן ביקר הדפדפן, ואת כל הסימניות של הדפדפן."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"כתיבת היסטוריה וסימניות של דפדפן"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"אם תפעיל אחסון USB, חלק מהיישומים שבהם אתה משתמש יעצרו ולא יהיו זמינים עד שתכבה את אחסון ה-USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"הפעלת ה-USB נכשלה"</string>
<string name="dlg_ok" msgid="7376953167039865701">"אישור"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"מחובר כמכשיר מדיה"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"מחובר כמצלמה"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"מחובר כמתקין"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"גע לקבלת אפשרויות USB נוספות"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"פרמט אמצעי אחסון מסוג USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"פרמוט כרטיס SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"לפרמט את אמצעי האחסון מסוג USB, תוך מחיקת כל הקבצים? הפעולה בלתי הפיכה!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"נגישות"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"טפט"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN מופעל."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"הקש כדי לנהל את הרשת."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"מחובר אל <xliff:g id="SESSION">%s</xliff:g>. הקש כדי לנהל את הרשת."</string>
<string name="upload_file" msgid="2897957172366730416">"בחר קובץ"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"חוקיות:"</string>
<string name="issued_on" msgid="5895017404361397232">"הונפק בתאריך:"</string>
<string name="expires_on" msgid="3676242949915959821">"פג תוקף ב:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"מספר סידורי:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"טביעות אצבע:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"טביעת אצבע SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"טביעת אצבע SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"הצג הכל..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 9b7e80e..7614dd1 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$3$2$1"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">"、 "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ブラウザの履歴とブックマークを読み取る"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"ブラウザでアクセスしたすべてのURLおよびブラウザのすべてのブックマークの読み取りをアプリケーションに許可します。"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"ブラウザの履歴とブックマークを書き込む"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"USBストレージをONにすると、使用中のアプリケーションの一部が停止し、USBストレージをOFFにするまで使用できなくなる場合があります。"</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB操作に失敗しました"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"メディアデバイスとして接続"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"カメラとして接続"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"インストーラとして接続"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"他のUSBオプションをタップしてください"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USBストレージのフォーマット"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SDカードをフォーマット"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"USBストレージをフォーマットして、保存されているすべてのファイルを消去しますか?この操作は元に戻せません。"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"ユーザー補助"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁紙"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPNが有効化されました。"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
<string name="vpn_text" msgid="1610714069627824309">"ネットワークを管理するにはタップしてください。"</string>
<string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>に接続しました。ネットワークを管理するにはタップしてください。"</string>
<string name="upload_file" msgid="2897957172366730416">"ファイルを選択"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"有効期間:"</string>
<string name="issued_on" msgid="5895017404361397232">"発行:"</string>
<string name="expires_on" msgid="3676242949915959821">"有効期限:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"シリアル番号:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"指紋:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256指紋:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1指紋:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"すべて見る..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 15b3240..b47d090 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$3$2$1"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"브라우저의 기록 및 북마크 읽기"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"애플리케이션이 브라우저로 방문한 모든 URL과 브라우저의 모든 북마크를 읽도록 허용합니다."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"브라우저의 기록 및 북마크 쓰기"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"USB 저장소를 사용하면 사용 중인 일부 애플리케이션이 중지되어 USB 저장소를 사용 중지할 때까지 사용할 수 없게 됩니다."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB 작업 실패"</string>
<string name="dlg_ok" msgid="7376953167039865701">"확인"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"미디어 기기로 연결됨"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"카메라로 연결됨"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"설치 프로그램으로 연결됨"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"다른 USB 옵션을 보려면 터치하세요."</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB 저장소 포맷"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD 카드 포맷"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"USB 저장소를 포맷하여 저장된 파일을 모두 지우시겠습니까? 수행한 후에는 작업을 취소할 수 없습니다."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"접근성"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"배경화면"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN이 활성화되어 있습니다."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
<string name="vpn_text" msgid="1610714069627824309">"네트워크를 관리하려면 누르세요."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g>에 연결되어 있습니다. 네트워크를 관리하려면 누르세요."</string>
<string name="upload_file" msgid="2897957172366730416">"파일 선택"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"유효성:"</string>
<string name="issued_on" msgid="5895017404361397232">"발급 날짜:"</string>
<string name="expires_on" msgid="3676242949915959821">"만료 날짜:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"일련번호:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"지문:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 지문:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 지문:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"전체 보기..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index b57455f..44d8dc6e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"skaityti naršyklės istoriją ir žymes"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Leidžia programai skaityti visus URL, kuriuose apsilankė naršyklė, ir visas naršyklės žymas."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"rašyti naršyklės istoriją ir žymes"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Jei įjungiate USB saugyklą, kai kurios naudojamos programos sustos ir gali būti negalimos, kol išjungsite USB saugyklą."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB operacija nepavyko"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Gerai"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Prij. kaip medijos įrenginys"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Prij. kaip fotoap."</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Prij. kaip diegimo programa"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Jei norite matyti kitas USB parinktis, palieskite"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Format. USB atmint."</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatuoti SD kortelę"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formatuoti USB atmintinę ištrinant visus joje saugomus failus? Veiksmo nebus galima atšaukti!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Pasiekiamumas"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Darbalaukio fonas"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Keisti darbalaukio foną"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN suaktyvintas."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
<string name="vpn_text" msgid="1610714069627824309">"Jei norite valdyti tinklą, palieskite."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Prisijungta prie <xliff:g id="SESSION">%s</xliff:g>. Jei norite valdyti tinklą, palieskite."</string>
<string name="upload_file" msgid="2897957172366730416">"Pasirinkti failą"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Galiojimas:"</string>
<string name="issued_on" msgid="5895017404361397232">"Išduota:"</string>
<string name="expires_on" msgid="3676242949915959821">"Galiojimas baigiasi:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serijos numeris:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Kontroliniai kodai"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 kontrolinis kodas"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 kontrolinis kodas"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Žr. viską..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 6fed017..bc8b64c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -701,6 +701,18 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Province"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Pasta indekss"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"Štats"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Pasta indekss"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Apgabals"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Sala"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"Rajons"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Departaments"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Prefektūra"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Pagasts"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Reģions"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Emirāts"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lasīt pārlūkprogrammas vēsturi un grāmatzīmes"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ļauj lietojumprogrammai lasīt visus URL, kas ir apmeklēti pārlūkprogrammā, un visas pārlūkprogrammas grāmatzīmes."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"rakstīt pārlūkprogrammas vēsturi un grāmatzīmes"</string>
@@ -944,14 +956,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Ja ieslēgsiet USB krātuvi, dažu joprojām lietoto lietojumprogrammu darbība tiks apturēta un tās, iespējams, nebūs pieejamas līdz brīdim, kad USB krātuve tiks izslēgta."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB darbība neizdevās."</string>
<string name="dlg_ok" msgid="7376953167039865701">"Labi"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Pievienots kā multivides ierīce"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Pievienots kā kamera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Pievienots kā instalēšanas programma"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Pieskarieties, lai skatītu citas USB opcijas."</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB kr. formatēšana"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD kartes formatēšana"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Vai formatēt USB krātuvi, dzēšot visus tajā saglabātos failus? Šo darbību nevar atcelt."</string>
@@ -1015,10 +1023,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Pieejamība"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fona tapete"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tapetes maiņa"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN ir aktivizēts."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
<string name="vpn_text" msgid="1610714069627824309">"Pieskarieties, lai pārvaldītu tīklu."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Ir izveidots savienojums ar: <xliff:g id="SESSION">%s</xliff:g>. Pieskarieties, lai pārvaldītu tīklu."</string>
<string name="upload_file" msgid="2897957172366730416">"Izvēlēties failu"</string>
@@ -1095,18 +1101,13 @@
<string name="validity_period" msgid="8818886137545983110">"Derīgums:"</string>
<string name="issued_on" msgid="5895017404361397232">"Izsniegšanas datums:"</string>
<string name="expires_on" msgid="3676242949915959821">"Derīguma termiņš:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Sērijas numurs:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Identifikatori"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 identifikators"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 identifikators:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Skatīt visas"</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 87b169d..2cf00e0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -729,6 +729,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"baca sejarah dan penanda halaman Penyemak imbas"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Membenarkan aplikasi membaca semua URL yang telah dilawati oleh Penyemak Imbas dan semua penanda halaman Penyemak Imbas."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"tulis sejarah dan penanda halaman Penyemak Imbas"</string>
@@ -972,14 +996,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Jika anda menghidupkan storan USB, sesetengah aplikasi yang anda sedang gunakan akan terhenti dan mungkin tidak akan tersedia sehingga anda memadamkan storan USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Pengendalian USB gagal"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Disambungkan sebagai peranti media"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Disambungkan sebagai kamera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Disambungkan sebagai pemasang"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Sentuh untuk mendapatkan pilihan USB yang lain"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Format storan USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Format kad SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Format storan USB, memadamkan semua fail yang disimpan? Tindakan tidak boleh dibalikkan!"</string>
@@ -1043,10 +1063,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Kebolehaksesan"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Kertas dinding"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN diaktifkan."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<!-- no translation found for vpn_text (1610714069627824309) -->
<skip />
<!-- no translation found for vpn_text_long (4907843483284977618) -->
@@ -1146,10 +1164,9 @@
<skip />
<!-- no translation found for sha1_fingerprint (7930330235269404581) -->
<skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Lihat semua..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ca40558..67429b5 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lese nettleserens logg og bokmerker"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Lar applikasjonen lese alle adresser nettleseren har besøkt, og alle nettleserens bokmerker."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"skrive til nettleserens logg og bokmerker"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Hvis du aktiverer USB-lagring, virker ikke lenger enkelte av programmene du bruker, og de kan være utilgjengelige inntil du deaktiverer USB-lagringen."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-operasjonen mislyktes"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Tilkoblet som medieenhet"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Tilkoblet som kamera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Tilkoblet som installasjonsprogram"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Berør for andre USB-alternativer"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formaterer USB-lagring"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatere minnekort"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Vil du formatere USB-lagring og slette alle lagrede filer? Handlingen kan ikke angres!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Tilgjengelighet"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrunnsbilde"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN er aktivert."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Trykk for å administrere nettverket."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Koblet til <xliff:g id="SESSION">%s</xliff:g>. Trykk for å administrere nettverket."</string>
<string name="upload_file" msgid="2897957172366730416">"Velg fil"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Gyldighet:"</string>
<string name="issued_on" msgid="5895017404361397232">"Utstedt den:"</string>
<string name="expires_on" msgid="3676242949915959821">"Utløper den:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serienummer:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Fingeravtrykk"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256-fingeravtrykk"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1-fingeravtrykk"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Se alle"</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 757091f..fe21bc8 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"browsergeschiedenis en bladwijzers lezen"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Hiermee kan een app de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"browsergeschiedenis en bladwijzers schrijven"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Als u USB-opslag inschakelt, worden bepaalde apps die u gebruikt, gestopt en worden deze mogelijk pas weer beschikbaar wanneer u USB-opslag uitschakelt."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-bewerking mislukt"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Gekoppeld als media-apparaat"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Gekoppeld als camera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Gekoppeld als installatieprogramma"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Raak aan voor andere USB-opties"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB-opslag formatt."</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD-kaart formatteren"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"USB-opslag formatteren en alle opgeslagen bestanden wissen? Actie kan niet ongedaan worden gemaakt."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Toegankelijkheid"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Achtergrond"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN is geactiveerd."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Tik om het netwerk te beheren."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Verbonden met <xliff:g id="SESSION">%s</xliff:g>. Tik om het netwerk te beheren."</string>
<string name="upload_file" msgid="2897957172366730416">"Bestand kiezen"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Geldigheid:"</string>
<string name="issued_on" msgid="5895017404361397232">"Uitgegeven op:"</string>
<string name="expires_on" msgid="3676242949915959821">"Verloopt op:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serienummer:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Vingerafdrukken:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256-vingerafdruk"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1-vingerafdruk:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Alle bekijken..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 85f2bad..60c9bdb 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"odczyt historii i zakładek przeglądarki"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Umożliwia aplikacji odczyt wszystkich adresów URL odwiedzonych przez przeglądarkę, a także wszystkich zakładek przeglądarki."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"zapis historii i zakładek przeglądarki"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Po włączeniu nośnika USB niektóre używane aplikacje zostaną zatrzymane i mogą być niedostępne do chwili wyłączenia nośnika USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Operacja USB nie powiodła się"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Podłączono jako urządzenie multimedialne."</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Podłączono jako aparat."</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Podłączono jako nośnik instalacyjny."</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Dotknij, aby wyświetlić inne opcje USB."</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatuj nośnik USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatuj kartę SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Czy sformatować nośnik USB i wymazać wszystkie zapisane na nim pliki? Tej czynności nie można cofnąć."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Ułatwienia dostępu"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"Obsługa sieci VPN została włączona"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Dotknij, aby zarządzać siecią."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Nawiązano połączenie: <xliff:g id="SESSION">%s</xliff:g>. Dotknij, aby zarządzać siecią."</string>
<string name="upload_file" msgid="2897957172366730416">"Wybierz plik"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Ważność:"</string>
<string name="issued_on" msgid="5895017404361397232">"Data wystawienia:"</string>
<string name="expires_on" msgid="3676242949915959821">"Wygasa:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Numer seryjny:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Odciski cyfrowe:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Odcisk cyfrowy SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Odcisk cyfrowy SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Pokaż wszystkie"</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 9761b71..6af09f3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ler histórico e marcadores do browser"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite que a aplicação leia todos os URLs visitados pelo browser e todos os marcadores do browser."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"gravar histórico e marcadores do browser"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Se activar o armazenamento USB, algumas aplicações que estiver a utilizar serão paradas e poderão ficar indisponíveis até desactivar o armazenamento USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Falha na operação USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ligado como um aparelho multimédia"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ligado como uma câmara"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ligado como um instalador"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Toque para outras opções USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatar armaz. USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatar cartão SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formatar armazenamento USB e apagar todos os ficheiros armazenados? Não é possível reverter a acção!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagem de fundo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar imagem de fundo"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"A VPN está ativa"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Toque para gerir a rede."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Ligado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerir a rede."</string>
<string name="upload_file" msgid="2897957172366730416">"Escolher ficheiro"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validade:"</string>
<string name="issued_on" msgid="5895017404361397232">"Emitido em:"</string>
<string name="expires_on" msgid="3676242949915959821">"Expira em:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Número de série:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Impressões digitais:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Impressão digital SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Impressão digital SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Ver tudo..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a56523f..d762274 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ler histórico e favoritos do Navegador"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite que o aplicativo leia todos os URLs visitados pelo Navegador e todos os favoritos do Navegador."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"gravar histórico e favoritos do Navegador"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Se você ativar o armazenamento USB, alguns aplicativos que estão em uso serão interrompidos e poderão não estar disponíveis até você desativar o armazenamento USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Falha de operação de USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectado como um dispositivo de mídia"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectadas como uma câmera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectados como um instalador"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Toque para obter outras opções USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatar armaz. USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatar cartão SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formatar o armazenamento USB, apagando todos os arquivos armazenados? A ação não pode ser revertida!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Acessibilidade"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Plano de fundo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"A VPN está ativada."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Toque para gerenciar a rede."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Conectado a <xliff:g id="SESSION">%s</xliff:g>. Toque para gerenciar a rede."</string>
<string name="upload_file" msgid="2897957172366730416">"Escolher arquivo"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validade:"</string>
<string name="issued_on" msgid="5895017404361397232">"Emitido em:"</string>
<string name="expires_on" msgid="3676242949915959821">"Expira em:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Número de série:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Impressões digitais"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Impressão digital SHA-256"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Impressão digital SHA-1"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Ver todos..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 7048c69..5fd5d45 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -781,6 +781,30 @@
<skip />
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leger la cronologia ed ils segnapaginas dal navigatur"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"\"Permetta a l\'applicaziun da leger tut las URLs visitadas, sco era ils segnapaginas dal navigatur.\""</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"scriver en la cronologia ed en ils segnapaginas dal navigatur"</string>
@@ -1251,8 +1275,8 @@
<skip />
<!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
<skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 69b111e..ad3d64d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"citire istoric şi marcaje în browser"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite aplicaţiei să citească toate adresele URL vizitate din browser şi toate marcajele din acesta."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"citire istoric şi marcaje în browser"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Dacă activaţi stocarea USB, unele aplicaţii pe care le utilizaţi în prezent se vor opri şi ar putea să nu fie disponibile până când dezactivaţi stocarea USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Operaţie USB nereuşită"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Conectat ca dispozitiv media"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Conectat ca aparat foto"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Conectat ca program de instalare"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Atingeţi pentru alte opţiuni USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formataţi stoc. USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formataţi cardul SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formataţi stocarea USB, ştergând toate fişierele stocate aici? Acţiunea nu poate fi anulată!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilitate"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Imagine de fundal"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Modificaţi imaginea de fundal"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN este activată."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Apăsaţi pentru a gestiona reţeaua."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Conectat la <xliff:g id="SESSION">%s</xliff:g>. Apăsaţi pentru a gestiona reţeaua."</string>
<string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Validitate:"</string>
<string name="issued_on" msgid="5895017404361397232">"Emis pe:"</string>
<string name="expires_on" msgid="3676242949915959821">"Expiră pe:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Număr de serie:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Amprente:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Amprentă SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Amprentă SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Afişaţi-le pe toate..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 95d4077..0bc2f44 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"считывать историю и закладки браузера"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Разрешает приложению считывать все URL, посещенные браузером, и все его закладки."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"записывать историю и закладки браузера"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"При включении USB-накопителя некоторые используемые приложения могут прекратить работу и оставаться недоступными до отключения USB-накопителя."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Сбой операции USB-подключения"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Подключен как устройство хранения данных"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Подключен как камера"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Подключен как установщик"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Нажмите, чтобы увидеть другие параметры USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Форматирование"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Очистить SD-карту"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Форматирование USB-накопителя безвозвратно удалит все файлы на нем! Продолжить?"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Спец. возможности"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"Сеть VPN активна."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Нажмите здесь, чтобы изменить настройки сети."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Подключено: \"<xliff:g id="SESSION">%s</xliff:g>\". Нажмите здесь, чтобы изменить настройки сети."</string>
<string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Срок действия:"</string>
<string name="issued_on" msgid="5895017404361397232">"Дата выпуска:"</string>
<string name="expires_on" msgid="3676242949915959821">"Срок действия:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Серийный номер:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Отпечатки:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Отпечаток SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Отпечаток SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Просмотреть все"</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e622cf1..d836312 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Čítanie histórie a záložiek prehliadača"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Umožňuje aplikácii čítať všetky adresy URL navštívené prehliadačom a záložky prehliadača."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Zapisovať históriu a záložky prehliadača"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Ak zapnete ukladací priestor USB, dôjde k zastaveniu niektorých používaných aplikácií. Tieto aplikácie pravdepodobne nebudú k dispozícii až do vypnutia ukladacieho priestoru USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Chyba operácie na rozhraní USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Pripojené ako mediálne zariadenie"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Pripojené ako fotoaparát"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Pripojené ako inštalátor"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Dotykom zobrazíte ďalšiu možnosť USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formát. ukl. priestor USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formátovať kartu SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Chcete ukladací priestor USB naformátovať a vymazať tak všetky súbory, ktoré sú v ňom uložené? Túto akciu nie je možné vrátiť späť."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Zjednodušenie"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmeniť tapetu"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"Sieť VPN je aktivovaná."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
<string name="vpn_text" msgid="1610714069627824309">"Kliknutím zobrazíte správu siete."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Pripojené k relácii <xliff:g id="SESSION">%s</xliff:g>. Po klepnutí môžete sieť spravovať."</string>
<string name="upload_file" msgid="2897957172366730416">"Zvoliť súbor"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Platnosť:"</string>
<string name="issued_on" msgid="5895017404361397232">"Dátum vydania:"</string>
<string name="expires_on" msgid="3676242949915959821">"Platnosť vyprší:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Sériové číslo:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Digitálne odtlačky:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Digitálny odtlačok SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Digitálny odtlačok SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Zobraziť všetko..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index d68a3a5..9c43047 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -492,7 +492,7 @@
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"upravljanje pravilnika o omrežju"</string>
<string name="permdesc_manageNetworkPolicy" msgid="3723795285132803958">"Programu omogoča upravljanje pravilnikov o omrežju in določanje pravil za program."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"spremeni obračunavanje uporabe omrežja"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="8702285686629184404">"Omogoča spreminjanje načina obračunavanja uporabe omrežja za posamezne programe. Ni za uporabo za pri navadnih programih."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="8702285686629184404">"Omogoča spreminjanje načina obračunavanja uporabe omrežja za posamezne programe. Ni za uporabo pri navadnih programih."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"branje zgodovine in zaznamkov brskalnika"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Programu dovoljuje branje vseh URL-jev, ki jih je brskalnik obiskal, in vseh brskalnikovih zaznamkov."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"pisanje zgodovine in zaznamkov brskalnika"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Če vklopite shrambo USB, bodo nekateri programi, ki jih uporabljate, ustavljeni in morda ne bodo na voljo, dokler je ne izklopite."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Operacija USB ni uspela"</string>
<string name="dlg_ok" msgid="7376953167039865701">"V redu"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Povezan kot predstavnostna naprava"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Povezan kot fotoaparat"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Povezan kot namestitveni program"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Dotaknite se, če želite izbrati druge možnosti za USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatiranje pomnilnika USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatiraj kartico SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Ali želite formatirati pomnilnik USB in izbrisati vse datoteke, shranjene na njem? Dejanje je dokončno."</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Pripomočki za osebe s posebnimi potrebami"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Ozadje"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN je aktiviran."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktiviral program <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Tapnite za upravljanje omrežja."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Povezan z mestom <xliff:g id="SESSION">%s</xliff:g>. Tapnite za upravljanje omrežja."</string>
<string name="upload_file" msgid="2897957172366730416">"Izberi datoteko"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Veljavnost:"</string>
<string name="issued_on" msgid="5895017404361397232">"Izdano:"</string>
<string name="expires_on" msgid="3676242949915959821">"Velja do:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serijska številka:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Prstni odtisi:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Prstni odtis SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Prstni odtis SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Prikaži vse ..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 1604a94..ec6470e 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"читање историје и обележивача у прегледачу"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Омогућава да апликација чита све URL адресе које су посећене у прегледачу, као и све обележиваче у њему."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"уписивање историје и обележивача из прегледача"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Ако укључите USB складиште, поједине апликације које користите престаће да раде и могу да постану недоступне док га поново не укључите."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Грешка са USB складиштем"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Потврди"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Повезан као медијски уређај"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Повезан као камера"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Повезан као инсталациони програм"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Додирните за друге USB опције"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Форматирање USB меморије"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Форматирање SD картице"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Желите да форматирате USB меморију и избришете све датотеке у њој? Ову радњу није могуће опозвати!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Приступачност"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Позадина"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN је активиран."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
<string name="vpn_text" msgid="1610714069627824309">"Додирните да бисте управљали мрежом."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Повезано са сесијом <xliff:g id="SESSION">%s</xliff:g>. Додирните да бисте управљали мрежом."</string>
<string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Важност:"</string>
<string name="issued_on" msgid="5895017404361397232">"Издато:"</string>
<string name="expires_on" msgid="3676242949915959821">"Истиче:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Серијски број:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Дигитални отисци:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 дигитални отисак:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 дигитални отисак:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Прикажи све..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d3e3848..d7bc859 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"läsa webbläsarhistorik och bokmärken"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Tillåter att program läser alla webbadresser som webbläsaren har öppnat och alla webbläsarens bokmärken."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"skriva webbläsarhistorik och bokmärken"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Om du aktiverar USB-lagring avbryts några av de appar som körs och de kanske inte blir tillgängliga igen förrän du inaktiverar USB-lagring."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-åtgärd misslyckades"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ansluten som en mediaenhet"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ansluten som en kamera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ansluten som installationsprogram"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Tryck för andra USB-alternativ"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatera USB-enhet"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Formatera SD-kort"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Formatera SD-kort och radera alla filer? Åtgärden kan inte ångras!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Tillgänglighet"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Bakgrund"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN är aktiverad."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Knacka lätt för att hantera nätverket."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Ansluten till <xliff:g id="SESSION">%s</xliff:g>. Knacka lätt för att hantera nätverket."</string>
<string name="upload_file" msgid="2897957172366730416">"Välj fil"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Giltighet:"</string>
<string name="issued_on" msgid="5895017404361397232">"Utfärdat den:"</string>
<string name="expires_on" msgid="3676242949915959821">"Upphör att gälla:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serienummer:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Fingeravtryck:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256-fingeravtryck"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1-fingeravtryck:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Visa alla..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0bf9ddf..6d7de63 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -931,6 +931,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"soma historia na alamisho za Kivinjari"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Huruhusu programu kusoma URL zote ambazo Kivinjari imetembelea, na alamisho zile zingine zote za Kivinjari."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"andika historia ya Kivinjari na alamisho"</string>
@@ -1437,8 +1461,8 @@
<skip />
<!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
<skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 9ffe6b1..17bf561 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -44,5 +44,7 @@
<!-- Size of status line font in LockScreen. -->
<dimen name="keyguard_pattern_unlock_status_line_font_size">14sp</dimen>
+ <!-- Preference activity, vertical padding for the header list -->
+ <dimen name="reference_screen_header_vertical_padding">16dp</dimen>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2d5b249..a75929f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"อ่านประวัติและบุ๊กมาร์กของเบราว์เซอร์"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"อนุญาตให้แอปพลิเคชันอ่าน URL ทั้งหมดที่เบราว์เซอร์เคยเข้าชมและบุ๊กมาร์กของเบราว์เซอร์ทั้งหมด"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"เขียนประวัติและบุ๊กมาร์กของเบราว์เซอร์"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"หากคุณเปิดที่จัดเก็บข้อมูล USB แอปพลิเคชันบางอย่างที่คุณใช้อยู่จะหยุดและอาจใช้งานไม่ได้จนกว่าคุณจะปิดที่จัดเก็บข้อมูล USB"</string>
<string name="dlg_error_title" msgid="8048999973837339174">"การปฏิบัติงานของ USB ล้มเหลว"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ตกลง"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"เชื่อมต่อเป็นอุปกรณ์สื่อ"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"เชื่อมต่อเป็นกล้องถ่ายรูป"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"เชื่อมต่อเป็นตัวติดตั้ง"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"แตะสำหรับตัวเลือก USB อื่นๆ"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"ฟอร์แมตที่เก็บข้อมูล USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"ฟอร์แมตการ์ด SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"ฟอร์แมตที่เก็บข้อมูล USB โดยลบไฟล์ทั้งหมดที่จัดเก็บอยู่ในนั้นหรือไม่ การทำงานนี้ไม่สามารถย้อนกลับได้"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"การเข้าถึง"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"วอลเปเปอร์"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN เปิดใช้งานแล้ว"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"แตะเพื่อจัดการเครือข่าย"</string>
<string name="vpn_text_long" msgid="4907843483284977618">"เชื่อมต่อกับ <xliff:g id="SESSION">%s</xliff:g> แตะเพื่อจัดการเครือข่าย"</string>
<string name="upload_file" msgid="2897957172366730416">"เลือกไฟล์"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"อายุการใช้งาน:"</string>
<string name="issued_on" msgid="5895017404361397232">"ออกเมื่อ:"</string>
<string name="expires_on" msgid="3676242949915959821">"หมดอายุวันที่:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"หมายเลขซีเรียล:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"ลายนิ้วมือ"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"ลายนิ้วมือ SHA-256"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"ลายนิ้วมือ SHA-1"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"ดูทั้งหมด..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 5b3eed0..55209f4 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"basahin ang kasaysayan at mga bookmark ng Browser"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Pinapayagan ang application na basahin ang lahat ng URL na binisita ng Browser, at lahat ng bookmark ng Browser."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"isulat ang kasaysayan ng Browser at mga bookmark"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Kung io-on mo ang USB storage, titigil ang ilang application na ginagamit mo at maaaring maging hindi available hanggang sa i-off mo ang USB storage."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Nabigo ang pagpapatakbo ng USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Nakakonekta bilang isang media device"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Nakakonekta bilang isang camera"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Nakakonekta bilang isang installer"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"I-touch para sa mga ibang pagpipilian sa USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"I-format USB storage"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"I-format ang SD card"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"I-format ang imbakan na USB, na binubura ang lahat ng mga file na nakaimbak doon? Hindi maaaring maibalik ang pagkilos!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Kakayahang Ma-access"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Wallpaper"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"Isinaaktibo ang VPN."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Tapikin upang pamahalaan ang network."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Nakakonekta sa <xliff:g id="SESSION">%s</xliff:g>. Tapikin upang pamahalaan ang network."</string>
<string name="upload_file" msgid="2897957172366730416">"Pumili ng file"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Pagkabisa:"</string>
<string name="issued_on" msgid="5895017404361397232">"Ibinigay noong:"</string>
<string name="expires_on" msgid="3676242949915959821">"Mag-e-expire sa:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Serial number:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Mga fingerprint:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 na fingerprint:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 na fingerprint:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Tingnan lahat..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8aea16d..b4a6922 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Tarayıcı geçmişini ve favorileri oku"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Uygulamaya Tarayıcının ziyaret etmiş olduğu tüm URL\'leri ve Tarayıcının tüm favorilerini okuma izni verir."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Tarayıcı geçmişini ve favorileri yaz"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"USB depolama birimini açarsanız, kullanmakta olduğunuz bazı uygulamalar durur ve USB depolama birimi kapatılıncaya kadar kullanılamayabilir."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB işlemi başarısız oldu"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Tamam"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Medya cihazı olarak bağlandı"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Kamera olarak bağlandı"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Yükleyici olarak bağlandı"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Diğer USB seçenekleri için dokunun"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB\'yi biçimlendir"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD kartı biçimlendir"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"USB depolama birimi biçimlendirilsin mi? Depolama biriminde saklanan tüm dosyalar silinir. İşlem geri alınamaz!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Erişebilirlik"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Duvar Kağıdı"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN etkinleştirildi."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
<string name="vpn_text" msgid="1610714069627824309">"Ağı yönetmek için hafifçe vurun."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"<xliff:g id="SESSION">%s</xliff:g> oturumuna bağlı. Ağı yönetmek için hafifçe vurun."</string>
<string name="upload_file" msgid="2897957172366730416">"Dosya seç"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Geçerlilik:"</string>
<string name="issued_on" msgid="5895017404361397232">"Yayınlanma tarihi:"</string>
<string name="expires_on" msgid="3676242949915959821">"Sona erme tarihi:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Seri numara:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Parmak izleri:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 parmak izi:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 parmak izi:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Tümünü göster..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 5f50208..e813b92 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -701,6 +701,18 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Провінція"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Поштовий код"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"Штат"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Поштовий індекс"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Округ"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Острів"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"Район"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Відділ"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Префектура"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Община"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Область"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Емірат"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"читати історію та закладки переглядача"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Дозволяє програмі зчитувати всі URL-адреси, на які заходив переглядач, і всі закладки переглядача."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"запис. історію та закладки переглядача"</string>
@@ -944,14 +956,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Якщо ввімкнути носій USB, деякі програми, які викор., припинять свою роботу та можуть бути недоступними до вимкнення носія USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Помилка операції з USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Під’єднано як носій"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Під’єднано як камеру"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Під’єднано як програму встановлення"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Торкніться, щоб побачити інші параметри USB"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Форматув. носій USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Формат. карти SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Форматувати носій USB, видаляючи всі збережені файли? Дію не можна скасувати!"</string>
@@ -1015,10 +1023,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Доступність"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновий мал."</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фон. мал."</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"Мережу VPN активовано."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="1610714069627824309">"Торкніться, щоб керувати мережею."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Під’єднано до <xliff:g id="SESSION">%s</xliff:g>. Торкніться, щоб керувати мережею."</string>
<string name="upload_file" msgid="2897957172366730416">"Виберіть файл"</string>
@@ -1095,18 +1101,13 @@
<string name="validity_period" msgid="8818886137545983110">"Чинність:"</string>
<string name="issued_on" msgid="5895017404361397232">"Дата видачі:"</string>
<string name="expires_on" msgid="3676242949915959821">"Діє до:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Серійний номер:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Відбитки:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Відбиток SHA-256"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Відбиток SHA-1"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Показати всі..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 38e33e3..dd2c19d 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"đọc lịch sử và dấu trang của Trình duyệt"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Cho phép ứng dụng đọc tất cả các URL mà Trình duyệt đã truy cập và tất cả các dấu trang của Trình duyệt."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"xem lịch sử và dấu trang của Trình duyệt"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Nếu bạn bật bộ lưu trữ USB, một số ứng dụng bạn đang sử dụng sẽ dừng và có thể không khả dụng cho tới khi bạn tắt bộ lưu trữ USB."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"Thao tác USB không thành công"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"Đã kết nối là thiết bị truyền thông"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"Đã kết nối như máy ảnh"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Được kết nối như trình cài đặt"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"Chạm để có các tùy chọn USB khác"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Định dạng b.nhớ USB"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"Định dạng thẻ SD"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"Định dạng bộ nhớ USB, xóa tất cả tệp được lưu trữ tại đây? Không thể hoàn tác tác vụ!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"Khả năng truy cập"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Hình nền"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN được kích hoạt."</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
<string name="vpn_text" msgid="1610714069627824309">"Chạm để quản lý mạng."</string>
<string name="vpn_text_long" msgid="4907843483284977618">"Đã kết nối với <xliff:g id="SESSION">%s</xliff:g>. Chạm để quản lý mạng."</string>
<string name="upload_file" msgid="2897957172366730416">"Chọn tệp"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"Tính hợp lệ:"</string>
<string name="issued_on" msgid="5895017404361397232">"Cấp vào:"</string>
<string name="expires_on" msgid="3676242949915959821">"Hết hạn vào:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"Số sê-ri:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Tệp tham chiếu:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"Tệp tham chiếu SHA-256:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"Tệp tham chiếu SHA-1:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"Xem tất cả..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 863e3fa..0fb0106 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"读取浏览器的历史记录和书签"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"允许应用程序读取用浏览器访问过的所有网址,以及浏览器的所有书签。"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"写入浏览器的历史记录和书签"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"如果您打开了 USB 存储设备,则您当前使用的某些应用程序会停止,而且在您关闭 USB 存储设备前可能都无法使用。"</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB 操作失败"</string>
<string name="dlg_ok" msgid="7376953167039865701">"确定"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"作为媒体设备连接"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"作为相机连接"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"作为安装程序连接"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"触摸可显示其他 USB 选项"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"格式化 USB 存储设备"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"格式化 SD 卡"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"确定要格式化 USB 存储设备,清除其中存储的全部文件吗?该操作将无法撤消!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"辅助功能"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN 已激活。"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
<string name="vpn_text" msgid="1610714069627824309">"点按即可管理网络。"</string>
<string name="vpn_text_long" msgid="4907843483284977618">"已连接到<xliff:g id="SESSION">%s</xliff:g>。点按即可管理网络。"</string>
<string name="upload_file" msgid="2897957172366730416">"选择文件"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"有效期:"</string>
<string name="issued_on" msgid="5895017404361397232">"颁发时间:"</string>
<string name="expires_on" msgid="3676242949915959821">"有效期至:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"序列号:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"指纹:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 指纹:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 指纹:"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"查看全部..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index a9a6e4e..bf33dbf 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -701,6 +701,30 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"讀取瀏覽器的記錄與書籤"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"允許應用程式讀取瀏覽器曾經造訪過的所有網址,以及瀏覽器的所有書籤。"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"寫入瀏覽器的記錄與書籤"</string>
@@ -944,14 +968,10 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"如果您開啟 USB 儲存裝置,則您正在使用的某些應用程式會停止運作,而且可能無法使用,待您將 USB 儲存裝置關閉才會恢復正常。"</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB 操作失敗"</string>
<string name="dlg_ok" msgid="7376953167039865701">"確定"</string>
- <!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
- <skip />
- <!-- no translation found for usb_ptp_notification_title (1960817192216064833) -->
- <skip />
- <!-- no translation found for usb_cd_installer_notification_title (6774712827892090754) -->
- <skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
- <skip />
+ <string name="usb_mtp_notification_title" msgid="3699913097391550394">"已視為媒體裝置連線"</string>
+ <string name="usb_ptp_notification_title" msgid="1960817192216064833">"已視為相機連線"</string>
+ <string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"已視為安裝程式連線"</string>
+ <string name="usb_notification_message" msgid="4447869605109736382">"輕觸即可顯示其他 USB 選項"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"格式化 USB 儲存空間"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"將 SD 卡格式化"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"格式化 USB 儲存裝置時,是否清除其中儲存的所有檔案?這項動作無法復原!"</string>
@@ -1015,10 +1035,8 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"協助工具"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"桌布"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
- <skip />
- <!-- no translation found for vpn_title_long (6400714798049252294) -->
- <skip />
+ <string name="vpn_title" msgid="8219003246858087489">"VPN 已啟用。"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="1610714069627824309">"輕按一下即可管理網路。"</string>
<string name="vpn_text_long" msgid="4907843483284977618">"已連線至 <xliff:g id="SESSION">%s</xliff:g>,輕按一下即可管理網路。"</string>
<string name="upload_file" msgid="2897957172366730416">"選擇檔案"</string>
@@ -1095,18 +1113,13 @@
<string name="validity_period" msgid="8818886137545983110">"有效期間:"</string>
<string name="issued_on" msgid="5895017404361397232">"發佈日期:"</string>
<string name="expires_on" msgid="3676242949915959821">"到期日:"</string>
- <!-- no translation found for serial_number (758814067660862493) -->
+ <string name="serial_number" msgid="758814067660862493">"序號:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"指紋"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 指紋"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 指紋"</string>
+ <string name="activity_chooser_view_see_all" msgid="180268188117163072">"查看所有活動..."</string>
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for fingerprints (4516019619850763049) -->
- <skip />
- <!-- no translation found for sha256_fingerprint (4391271286477279263) -->
- <skip />
- <!-- no translation found for sha1_fingerprint (7930330235269404581) -->
- <skip />
- <!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
- <skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
- <skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e712d7b..0e05ad5 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -298,7 +298,7 @@
<string name="permdesc_readSms" product="default" msgid="3002170087197294591">"Ivumela uhlelo lokusebena ukufunda imiyalezo ye-SMS egcinwe efonini yakho noma ekhadini le-SIM. Izinhlelo ezinonya zingase zifunde imiyalezo eyimfihlo."</string>
<!-- no translation found for permlab_writeSms (6881122575154940744) -->
<skip />
- <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Ivumela uhlelo lokusebenza ukubhala imiyalezo ye-SMS egcinwe kwithebhulethi yakho noma ekhadini le-SIM. Izinhlelo ezi-malicious zingase zisuse imiyalezo yakho."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5332124772918835437">"Ivumela uhlelo lokusebenza ukubhala imiyalezo ye-SMS egcinwe kwithebhulethi yakho noma ekhadini le-SIM. Izinhlelo ezinonya zingase zisuse imiyalezo yakho."</string>
<string name="permdesc_writeSms" product="default" msgid="6299398896177548095">"Ivumela uhlelo lokusebenza ukubhala imiyalezo ye-SMS egcinwe efonini yakho noma ekhadini le-SIM. Izinhlelo ezinonya zingase zisuse imiyalezo yakho."</string>
<!-- no translation found for permlab_receiveWapPush (8258226427716551388) -->
<skip />
@@ -341,7 +341,7 @@
<string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Igwema umsebenzisi ukuba ashintshele kolunye uhlelo lokusebenza."</string>
<!-- no translation found for permlab_runSetActivityWatcher (7811586187574696296) -->
<skip />
- <string name="permdesc_runSetActivityWatcher" msgid="2149363027173451218">"Ivumela uhlelo lokusebenza ukugada nokulawula indlela uhlelo oluqalisa ngayo imisebenzi. Izinhlelo ezi-malicious zingase zonakalise ngokuphelele uhlelo. Le mvume idingeka kuphela ekuthuthukiseni, hayi ekusebenziseni ifoni okuvamile."</string>
+ <string name="permdesc_runSetActivityWatcher" msgid="2149363027173451218">"Ivumela uhlelo lokusebenza ukugada nokulawula indlela uhlelo oluqalisa ngayo imisebenzi. Izinhlelo ezinonya zingase zonakalise ngokuphelele uhlelo. Le mvume idingeka kuphela ekuthuthukiseni, hayi ekusebenziseni ifoni okuvamile."</string>
<!-- no translation found for permlab_broadcastPackageRemoved (2576333434893532475) -->
<skip />
<string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Ivumela uhlelo lokusebenza ukusakaza isaziso sokuthi iphakheji yohlelo lokusebenza ikhishiwe. Izinhlelo ezinonya zingasebenzisa lokhu ukubulala olunye uhlelo lokusebenza olusebenzayo."</string>
@@ -369,7 +369,7 @@
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Ivumela ukwenziwa kwemawindi ehloselwe ukusebenziswa uxhumano lomsebenzisi wohlelo lwangaphakathi. Ayisebenziswa izinhlelo zokusebenza ezivamile"</string>
<!-- no translation found for permlab_systemAlertWindow (3372321942941168324) -->
<skip />
- <string name="permdesc_systemAlertWindow" msgid="2884149573672821318">"Ivumela uhlelo lokusebenza ukubonisa amawindi okuxwayisa ohlelo. Izinhlelo zokusebenza ezi-malicious zingase zithathe isikrini sonke."</string>
+ <string name="permdesc_systemAlertWindow" msgid="2884149573672821318">"Ivumela uhlelo lokusebenza ukubonisa amawindi okuxwayisa ohlelo. Izinhlelo zokusebenza ezinonya zingase zithathe isikrini sonke."</string>
<!-- no translation found for permlab_setAnimationScale (2805103241153907174) -->
<skip />
<string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ivumela uhlelo lokusebenza ukushintsha isivinini sokugqwayiza jikelele (ukugqwayiza okusheshayo noma okulengayo) nganoma isiphi isikhathi."</string>
@@ -378,7 +378,7 @@
<string name="permdesc_manageAppTokens" msgid="977127907524195988">"Ivumela izinhlelo zokusebenza ukwenza nokuphatha amathokhini awo, ngokudlula ukuhleleka kuka-Z. Akusoze kwadingeka ezinhlelweni ezivamile."</string>
<!-- no translation found for permlab_injectEvents (1378746584023586600) -->
<skip />
- <string name="permdesc_injectEvents" product="tablet" msgid="7200014808195664505">"Ivumela uhlelo lokusebenza ukuthumela izenzakalo zawo zokufakwayo (ukucindezela ukhiye, nokunye) kwezinye izihlelo zokusebenza. Izinhlelo ezi-malicious zingasebenzisa lokhu ukuthatha ithebhulethi."</string>
+ <string name="permdesc_injectEvents" product="tablet" msgid="7200014808195664505">"Ivumela uhlelo lokusebenza ukuthumela izenzakalo zawo zokufakwayo (ukucindezela ukhiye, nokunye) kwezinye izihlelo zokusebenza. Izinhlelo ezinonya zingasebenzisa lokhu ukuthatha ithebhulethi."</string>
<string name="permdesc_injectEvents" product="default" msgid="3946098050410874715">"Ivumela uhlelo lokusebenza ukuthumela izenzakalo zawo zokufakwayo (ukucindezela ukhiye, nokunye) kwezinye izihlelo zokusebeza. Izinhlelo ezinonya zingasebenzisa lokhu ukuthatha ifoni."</string>
<!-- no translation found for permlab_readInputState (469428900041249234) -->
<skip />
@@ -434,8 +434,8 @@
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Ivumela uhlolo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonle, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
<!-- no translation found for permlab_changeComponentState (79425198834329406) -->
<skip />
- <string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Ivumela uhlelo lokusebenza ukushintsha ukuba ingabe ingxenye yolunye uhlelo lokusebenza ivuliwe noma cha. Izinhlelo ezi-malicious zingase zisebenzise lokhu ukuvimbela amakhono abalulekile ethebhulethi. Ukunakekela kumele kusetshenziswe ngemvume, njengoba kungenzeka ukuthola izingxenye zohlelo lokusebenza kusimo esingasebenziseki, esingefani, noma esingahlaliseki."</string>
- <string name="permdesc_changeComponentState" product="default" msgid="3443473726140080761">"Ivumela uhlelo lokusebenza ukushintsha ukuba ingabe ingxenye yolunye uhlelo lokusebenza ivuliwe noma cha. Izinhlelo ezi-malicious zingase zisebenzise lokhu ukuvimbela amakhono abalulekile ethebhulethi. Ukunakekela kumele kusetshenziswe ngemvume, njengoba kungenzeka ukuthola izingxenye zohlelo lokusebenza kusimo esingasebenziseki, esingefani, noma esingahlaliseki."</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="4647419365510068321">"Ivumela uhlelo lokusebenza ukushintsha ukuba ingabe ingxenye yolunye uhlelo lokusebenza ivuliwe noma cha. Izinhlelo ezinonya zingase zisebenzise lokhu ukuvimbela amakhono abalulekile ethebhulethi. Ukunakekela kumele kusetshenziswe ngemvume, njengoba kungenzeka ukuthola izingxenye zohlelo lokusebenza kusimo esingasebenziseki, esingefani, noma esingahlaliseki."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="3443473726140080761">"Ivumela uhlelo lokusebenza ukushintsha ukuba ingabe ingxenye yolunye uhlelo lokusebenza ivuliwe noma cha. Izinhlelo ezinonya zingase zisebenzise lokhu ukuvimbela amakhono abalulekile ethebhulethi. Ukunakekela kumele kusetshenziswe ngemvume, njengoba kungenzeka ukuthola izingxenye zohlelo lokusebenza kusimo esingasebenziseki, esingefani, noma esingahlaliseki."</string>
<!-- no translation found for permlab_setPreferredApplications (3393305202145172005) -->
<skip />
<string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Ivumela uhlelo lokusebenza ukuguqula izinhlelo zakho ezikhethwayo. Lokhu kungavumela izinhlelo ezinonya ukushintsha ngokuthulile izinhlelo zokusebenza ezisebenziswayo, ukushintsha izinhlelo zakho zokusebenza ezikhona kakade ukuqoqa idatha yangasese kuwe."</string>
@@ -453,15 +453,15 @@
<string name="permdesc_receiveBootCompleted" product="default" msgid="698336728415008796">"Ivumela uhlelo lokusebenza ukuba luziqalele ngokushesha nje emva kokuba uhlelo luqede ukuqala. Lokhu kungenza kuthathe isikhathi ukuqalisa ifoni futhi kuvumele uhlelo lokusebenza ukwehlisa ifoni yonke ngokusebenza njalo."</string>
<!-- no translation found for permlab_broadcastSticky (7919126372606881614) -->
<skip />
- <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Ivumela uhlelo lokusebenza ukuthumela imisakazo enamathelayo, esala emva kokuba ukusakaza kuphelile. Izinhlelo zokusebenza ezi-malicious zingenza ithebhulethii ingasheshi futhi ingahlaliseki ngokuyibangela ukuba isebenzise inkumbulo eningi kakhulu."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="6322249605930062595">"Ivumela uhlelo lokusebenza ukuthumela imisakazo enamathelayo, esala emva kokuba ukusakaza kuphelile. Izinhlelo zokusebenza ezinonya zingenza ithebhulethii ingasheshi futhi ingahlaliseki ngokuyibangela ukuba isebenzise inkumbulo eningi kakhulu."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="1920045289234052219">"Ivumela uhlelo lokusebenza ukuthumela imisakazo enamathelayo, esala emva kokuba ukusakaza kuphelile. Izinhlelo zokusebenza ezinonya zingenza ifoni ingasheshi futhi ingahlaliseki ngokuyibangela ukuba isebenzise inkumbulo eningi kakhulu."</string>
<!-- no translation found for permlab_readContacts (6219652189510218240) -->
<skip />
- <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Ivumela uhlelo lokusebenza ukufunda yonke idatha yothintana naye (ikheli) egcinwe kwithebhulethi yakho. Izinhlelo zokusebenza ezi-malicious zingase zisebenzise lokhu ukuthumela idatha yakho kwabanye abantu."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="7596158687301157686">"Ivumela uhlelo lokusebenza ukufunda yonke idatha yothintana naye (ikheli) egcinwe kwithebhulethi yakho. Izinhlelo zokusebenza ezinonya zingase zisebenzise lokhu ukuthumela idatha yakho kwabanye abantu."</string>
<string name="permdesc_readContacts" product="default" msgid="3371591512896545975">"Ivumela uhlelo lokusebenza ukufunda yonke idatha yothintana naye (ikheli) egcinwe efonini yakho. Izinhlelo zokusebenza zonya zingase zisebenzise lokhu ukuthumela idatha yakho kwabanye abantu."</string>
<!-- no translation found for permlab_writeContacts (644616215860933284) -->
<skip />
- <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Ivumela uhlelo lokusebenza ukuguqula idatha yothintana naye (ikheli) egcinwe kwithebhulethi yakho. Izinhlelo ezi-malicious zingase zisebenzise lokhu ukusula noma ukuguqula idatha yakho yothintana naye."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="7782689510038568495">"Ivumela uhlelo lokusebenza ukuguqula idatha yothintana naye (ikheli) egcinwe kwithebhulethi yakho. Izinhlelo ezinonya zingase zisebenzise lokhu ukusula noma ukuguqula idatha yakho yothintana naye."</string>
<string name="permdesc_writeContacts" product="default" msgid="3924383579108183601">"Ivumela uhlelo lokusebenza ukuguqula idatha yothintana naye (ikheli) egcinwe efonini yakho. Izinhlelo ezinonya zingase zisebenzise lokhu ukusula noma ukuguqula idatha yakho yothintana naye."</string>
<!-- no translation found for permlab_readProfile (2211941946684590103) -->
<skip />
@@ -472,7 +472,7 @@
<!-- no translation found for permdesc_writeProfile (8040643023682531996) -->
<skip />
<string name="permlab_readCalendar" msgid="6898987798303840534">"funda izenzakalo zekhalenda"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Ivumela uhlelo lokusebenza ukufunda zonke izenzakalo zekhalenda ezigcinwe kwithebhulethi yakho. Izinhlelo zokusebenza ezi-malicious zingase zisebenzise lokhu ukuthumela izenzakalo zakho zekhalenda kwabanye abantu."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="5905870265734599678">"Ivumela uhlelo lokusebenza ukufunda zonke izenzakalo zekhalenda ezigcinwe kwithebhulethi yakho. Izinhlelo zokusebenza ezinonya zingase zisebenzise lokhu ukuthumela izenzakalo zakho zekhalenda kwabanye abantu."</string>
<string name="permdesc_readCalendar" product="default" msgid="5533029139652095734">"Ivumela uhlelo lokusebenza ukufunda zonke izenzakalo zekhalenda ezigcinwe efonini yakho. Izinhlelo zokusebenza ezinonya zingase zisebenzise lokhu ukuthumela izenzakalo zakho zekhalenda kwabanye abantu."</string>
<string name="permlab_writeCalendar" msgid="3894879352594904361">"Yengeza noma guqula izenzakalo zekhalenda bese uthumelela izivakashi i-imeyli"</string>
<string name="permdesc_writeCalendar" msgid="2988871373544154221">"Ivumela uhlelo lokusebenza ukufaka noma ukushintsha izenzakalo ekhalendeni yakho, okungase kuthumele i-imeyli kubavakashi. Izinhlelo ezinonya zingase zisebenzise lokhu ukusula noma ukuguqula izenzakalo zekhalenda noma ukuthumela abavakashi i-imeyli."</string>
@@ -486,11 +486,11 @@
<string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Yenza imithombo yokudlala ukuhlola. Izinhlelo ezinonya zingase zisebenzise lokhu ukukhipha indawo futhi/noma isimo esibuyiswe imithombo yendawo yangempela njenge-GPS noma abahlinzeki Benethiwekhi noma zigade futhi zibike indawo yakho njengomthombo wangaphandle."</string>
<!-- no translation found for permlab_accessFineLocation (8116127007541369477) -->
<skip />
- <string name="permdesc_accessFineLocation" product="tablet" msgid="243973693233359681">"Finyelela kwimithombo ecocekile Njegesistimu Yokumisa Jikelele kwithebhulethi, lapho itholakala. Izinhlelo ezi-malicious zingasebenzisa lokhu ukuthola ukuthi ukuphi, futhi ingadonsa amandla angeziwe ebhetri."</string>
+ <string name="permdesc_accessFineLocation" product="tablet" msgid="243973693233359681">"Finyelela kwimithombo ecocekile Njegesistimu Yokumisa Jikelele kwithebhulethi, lapho itholakala. Izinhlelo ezinonya zingasebenzisa lokhu ukuthola ukuthi ukuphi, futhi ingadonsa amandla angeziwe ebhetri."</string>
<string name="permdesc_accessFineLocation" product="default" msgid="7411213317434337331">"Finyelela kumithombo ecocekile Njegesistimu Yokumisa Jikelele efonini, lapho itholakala. Izinhlelo ezinonya zingasebenzisa lokhu ukuthola ukuthi ukuphi, futhi ingadonsa amandla angeziwe ebhetri."</string>
<!-- no translation found for permlab_accessCoarseLocation (4642255009181975828) -->
<skip />
- <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Finyelela indawo yamaholohola njengesizinda semininingwane somakhalekhukhwini ukuthola endaweni elungile yethebhulethi, lapho itholakala khona. Izinhlelo zokusebenza ezi-malicious zingasebenzisa lokhu ukuthola ukuthi ukuphi."</string>
+ <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3704633168985466045">"Finyelela indawo yamaholohola njengesizinda semininingwane somakhalekhukhwini ukuthola endaweni elungile yethebhulethi, lapho itholakala khona. Izinhlelo zokusebenza ezinonya zingasebenzisa lokhu ukuthola ukuthi ukuphi."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="8235655958070862293">"Finyelela kundawo yamaholohola njengesizinda semininingwane somakhalekhukhwini ukuthola indawo elungile yefoni, lapho itholakala khona. Izinhlelo zokusebenza ezinonya zingasebenzisa lokhu ukuthola ukuthi ukuphi."</string>
<!-- no translation found for permlab_accessSurfaceFlinger (2363969641792388947) -->
<skip />
@@ -580,7 +580,7 @@
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Sebenzise njengokuhlola komkhiqizi wezinga eliphansi, uvumela ukufinyelela okugcwele ihadiwe yefoni. Itholakala kuphela lapho ifoni isebenza kwimodi yokuhlola yomkhiqizi."</string>
<!-- no translation found for permlab_setWallpaper (6627192333373465143) -->
<skip />
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ivumela uhlelo lokusebenza ukuhlela iphephadonga lohlelo."</string>
+ <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ivumela uhlelo lokusebenza ukuhlela iphephadonga lesistimu."</string>
<!-- no translation found for permlab_setWallpaperHints (3600721069353106851) -->
<skip />
<string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ivumela uhlelo lokusebenza ukuhlela izihlawumbisela zosayizi wephephadonga lohlelo."</string>
@@ -915,7 +915,7 @@
<string name="hour_cap_ampm" msgid="1829009197680861107">"<xliff:g id="HOUR">%-l</xliff:g><xliff:g id="AMPM">%p</xliff:g>"</string>
<!-- no translation found for factorytest_failed (5410270329114212041) -->
<skip />
- <string name="factorytest_not_system" msgid="4435201656767276723">"Isenzo SOKUHLOLA KWASEMBONINI sisekelwa kuphela amaphakheji afakwi kwisistimu/uhlelo."</string>
+ <string name="factorytest_not_system" msgid="4435201656767276723">"Isenzo SOKUHLOLA_KWASEMBONINI sisekelwa kuphela amaphakheji afakwe kwisistimu/uhlelokusebenza."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Ayikho iphakheji etholakele enikeze isenzo SOKUHLOLA KWASEMBONINI."</string>
<!-- no translation found for factorytest_reboot (6320168203050791643) -->
<skip />
@@ -931,10 +931,34 @@
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <!-- no translation found for autofill_province (2231806553863422300) -->
+ <skip />
+ <!-- no translation found for autofill_postal_code (4696430407689377108) -->
+ <skip />
+ <!-- no translation found for autofill_state (6988894195520044613) -->
+ <skip />
+ <!-- no translation found for autofill_zip_code (8697544592627322946) -->
+ <skip />
+ <!-- no translation found for autofill_county (237073771020362891) -->
+ <skip />
+ <!-- no translation found for autofill_island (4020100875984667025) -->
+ <skip />
+ <!-- no translation found for autofill_district (8400735073392267672) -->
+ <skip />
+ <!-- no translation found for autofill_department (5343279462564453309) -->
+ <skip />
+ <!-- no translation found for autofill_prefecture (2028499485065800419) -->
+ <skip />
+ <!-- no translation found for autofill_parish (8202206105468820057) -->
+ <skip />
+ <!-- no translation found for autofill_area (3547409050889952423) -->
+ <skip />
+ <!-- no translation found for autofill_emirate (2893880978835698818) -->
+ <skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"funda umlando Wesiphequluli namabhukimakhi"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ivumela uhlelo lokusebenza ukufunda wonke ama-URL lawo Isiphequluli esiwavakashele, ngisho nawo wonke amabhukimakhi Esiphequluli."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"bhala umlando Wesiphequluli namabhukhimaki"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Ivumela izinhlelo zokusebenza ukuguqula umlando Wesiphequluli noma amabhukimakhi agcinwe kwithebhulethi yakho. Izinhlelo zokusebenza ezi-malicious zingase zisebenzise lokhu ukwesula noma ukuguqula idatha yakho Yesiphequluli."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="7193514090469945307">"Ivumela izinhlelo zokusebenza ukuguqula umlando Wesiphequluli noma amabhukimakhi agcinwe kwithebhulethi yakho. Izinhlelo zokusebenza ezinonya zingase zisebenzise lokhu ukwesula noma ukuguqula idatha yakho Yesiphequluli."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="945571990357114950">"Ivumela izinhlelo zokusebenza ukuguqula umlando Wesiphequluli noma amabhukimakhi agcinwe efonini yakho. Izinhlelo zokusebenza ezinonya zingase zisebenzise lokhu ukwesula noma ukuguqula idatha yakho Yesiphequluli."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"misa i-alamu ewashini le-alamu"</string>
<string name="permdesc_setAlarm" msgid="5966966598149875082">"Ivumela uhlelo lokusebenza ukumisa i-alamu kuhlelo lokusebenza lewashi le-alawmu elifakiwe. Ezinye izinhlelo zokusebenza zewashi le-alamu zingase zingasebenzisi lesi sici."</string>
@@ -1437,8 +1461,8 @@
<skip />
<!-- no translation found for activity_chooser_view_see_all (180268188117163072) -->
<skip />
- <!-- no translation found for activity_chooser_view_no_activities (1306964627596326933) -->
+ <!-- no translation found for activity_chooser_view_dialog_title_default (3325054276356556835) -->
<skip />
- <!-- no translation found for activity_chooser_view_select_default (5450262016073956587) -->
+ <!-- no translation found for share_action_provider_share_with (1791316789651185229) -->
<skip />
</resources>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 0f04a67..bcf1991 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,6 +22,15 @@
<!-- Do not translate. These are all of the drawable resources that should be preloaded by
the zygote process before it starts forking application processes. -->
<array name="preloaded_drawables">
+ <item>@drawable/spinner_black_16</item>
+ <item>@drawable/spinner_black_20</item>
+ <item>@drawable/spinner_black_48</item>
+ <item>@drawable/spinner_black_76</item>
+ <item>@drawable/spinner_white_16</item>
+ <item>@drawable/spinner_white_48</item>
+ <item>@drawable/spinner_white_76</item>
+ <item>@drawable/toast_frame</item>
+ <item>@drawable/toast_frame_holo</item>
<item>@drawable/btn_check_on_selected</item>
<item>@drawable/btn_check_on_pressed_holo_light</item>
<item>@drawable/btn_check_on_pressed_holo_dark</item>
@@ -109,6 +118,11 @@
<item>@drawable/btn_default_disabled_holo_dark</item>
<item>@drawable/btn_default_disabled_focused_holo_light</item>
<item>@drawable/btn_default_disabled_focused_holo_dark</item>
+ <item>@drawable/btn_dropdown_disabled</item>
+ <item>@drawable/btn_dropdown_disabled_focused</item>
+ <item>@drawable/btn_dropdown_normal</item>
+ <item>@drawable/btn_dropdown_pressed</item>
+ <item>@drawable/btn_dropdown_selected</item>
<item>@drawable/btn_toggle_on_pressed_holo_light</item>
<item>@drawable/btn_toggle_on_pressed_holo_dark</item>
<item>@drawable/btn_toggle_on_normal_holo_light</item>
@@ -141,6 +155,10 @@
<item>@drawable/edit_text_holo_light</item>
<item>@drawable/edit_text_holo_dark</item>
<item>@drawable/edit_text</item>
+ <item>@drawable/expander_close_holo_dark</item>
+ <item>@drawable/expander_close_holo_light</item>
+ <item>@drawable/expander_ic_maximized</item>
+ <item>@drawable/expander_ic_minimized</item>
<item>@drawable/expander_group</item>
<item>@drawable/expander_group_holo_dark</item>
<item>@drawable/expander_group_holo_light</item>
@@ -157,6 +175,8 @@
<item>@drawable/menu_background_fill_parent_width</item>
<item>@drawable/menu_submenu_background</item>
<item>@drawable/menu_selector</item>
+ <item>@drawable/overscroll_edge</item>
+ <item>@drawable/overscroll_glow</item>
<item>@drawable/panel_background</item>
<item>@drawable/popup_bottom_bright</item>
<item>@drawable/popup_bottom_dark</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 9c2133f..d0361ca 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2302,6 +2302,8 @@
<!-- Flag whether the accessibility service wants to be able to retrieve the
active window content. This setting cannot be changed at runtime. -->
<attr name="canRetrieveWindowContent" format="boolean" />
+ <!-- Short description of the accessibility serivce purpose or behavior.-->
+ <attr name="description" />
</declare-styleable>
<!-- =============================== -->
@@ -3015,6 +3017,10 @@
<attr name="drawableLeft" format="reference|color" />
<!-- The drawable to be drawn to the right of the text. -->
<attr name="drawableRight" format="reference|color" />
+ <!-- The drawable to be drawn to the start of the text. -->
+ <attr name="drawableStart" format="reference|color" />
+ <!-- The drawable to be drawn to the end of the text. -->
+ <attr name="drawableEnd" format="reference|color" />
<!-- The padding between the drawables and the text. -->
<attr name="drawablePadding" format="dimension" />
<!-- Extra spacing between lines of text. -->
@@ -3345,7 +3351,7 @@
<!-- The row span: the difference between the bottom and top
boundaries delimiting the group of cells occupied by this view.
The default is one.
- See {@link android.widget.GridLayout.Group}. -->
+ See {@link android.widget.GridLayout.Spec}. -->
<attr name="layout_rowSpan" format="integer" min="1" />
<!-- The column boundary delimiting the left of the group of cells
occupied by this view. -->
@@ -3353,23 +3359,21 @@
<!-- The column span: the difference between the right and left
boundaries delimiting the group of cells occupied by this view.
The default is one.
- See {@link android.widget.GridLayout.Group}. -->
+ See {@link android.widget.GridLayout.Spec}. -->
<attr name="layout_columnSpan" format="integer" min="1" />
<!-- Gravity specifies how a component should be placed in its group of cells.
The default is LEFT | BASELINE.
See {@link android.widget.GridLayout.LayoutParams#setGravity(int)}. -->
<attr name="layout_gravity" />
<!-- A value specifying how much deficit or excess width this component can accomodate.
- The default is FIXED.
- See {@link android.widget.GridLayout.Group#flexibility}.-->
+ The default is FIXED. -->
<attr name="layout_columnFlexibility" >
<!-- If possible, width should be greater than or equal to the specified width.
See {@link android.widget.GridLayout#CAN_STRETCH}. -->
<enum name="canStretch" value="2" />
</attr>
<!-- A value specifying how much deficit or excess height this component can accomodate.
- The default is FIXED.
- See {@link android.widget.GridLayout.Group#flexibility}.-->
+ The default is FIXED. -->
<attr name="layout_rowFlexibility" >
<!-- If possible, height should be greater than or equal to the specified height.
See {@link android.widget.GridLayout#CAN_STRETCH}. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1f2b7fb..215700c 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -665,4 +665,7 @@
<!-- Timeout to wait for NTP server response. -->
<integer name="config_ntpTimeout">20000</integer>
+ <!-- Default network policy warning threshold, in megabytes. -->
+ <integer name="config_networkPolicyDefaultWarning">2048</integer>
+
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a5e5f70..73f636f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -96,6 +96,8 @@
is along the major axis (that is the screen is landscape). This may
be either a fraction or a dimension. -->
<item type="dimen" name="dialog_min_width_major">65%</item>
+ <!-- Preference activity, vertical padding for the header list -->
+ <dimen name="preference_screen_header_vertical_padding">0dp</dimen>
<!-- The platform's desired minimum size for a dialog's width when it
is along the minor axis (that is the screen is portrait). This may
@@ -133,4 +135,10 @@
<!-- Size of right margin on Unsecure unlock LockScreen -->
<dimen name="keyguard_lockscreen_status_line_font_right_margin">45dip</dimen>
+ <!-- Minimum popup width for selecting an activity in ActivityChooserDialog/ActivityChooserView. -->
+ <dimen name="activity_chooser_popup_min_width">200dip</dimen>
+
+ <!-- The default gap between components in a layout. -->
+ <dimen name="default_gap">16dip</dimen>
+
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index d05685c..547a192 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -74,4 +74,9 @@
<item type="id" name="rowTypeId" />
<item type="id" name="up" />
<item type="id" name="action_menu_divider" />
+ <item type="id" name="icon_menu_presenter" />
+ <item type="id" name="list_menu_presenter" />
+ <item type="id" name="action_menu_presenter" />
+ <item type="id" name="overflow_menu_presenter" />
+ <item type="id" name="popup_submenu_presenter" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f7701f2..6dedc83 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1826,4 +1826,7 @@
<public type="color" name="holo_purple" />
<public type="color" name="holo_blue_bright" />
+ <public type="attr" name="drawableStart" />
+ <public type="attr" name="drawableEnd" />
+
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 97a8c0b..d0e3f14 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2038,13 +2038,13 @@
<string name="autofill_phone_re">phone<!-- de-DE -->|telefonnummer<!-- es -->|telefono|teléfono<!-- fr-FR -->|telfixe<!-- ja-JP -->|電話<!-- pt-BR, pt-PT -->|telefone|telemovel<!-- ru -->|телефон<!-- zh-CN -->|电话</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_area_code_re">area code</string>
+ <string name="autofill_area_code_re">area.*code|acode|area</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_phone_prefix_re">^-$|\\)$|prefix<!-- fr-FR -->|preselection<!-- pt-BR, pt-PT -->|ddd</string>
+ <string name="autofill_phone_prefix_re">prefix<!-- fr-FR -->|preselection<!-- pt-BR, pt-PT -->|ddd</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_phone_suffix_re">^-$|suffix</string>
+ <string name="autofill_phone_suffix_re">suffix</string>
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_phone_extension_re">ext<!-- pt-BR, pt-PT -->|ramal</string>
@@ -2077,17 +2077,49 @@
<string name="autofill_country_code_re">country.*code|ccode|_cc</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_area_code_notext_re">^\($</string>
+ <string name="autofill_area_code_notext_re">^\\($</string>
<!-- Do not translate. Regex used by AutoFill. -->
- <string name="autofill_phone_prefix_separator_re">^-$|^\)$</string>
+ <string name="autofill_phone_prefix_separator_re">^-$|^\\)$</string>
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_phone_suffix_separator_re">^-$</string>
- <!-- Do not translate. Regex used by AutoFill. -->
- <!-- Ex: ************1234 -->
- <string name="credit_card_number_preview_format">$1</string>
+ <!-- Label in a web form for "Province" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_province">Province</string>
+
+ <!-- Label in a web form for "Postal code" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_postal_code">Postal code</string>
+
+ <!-- Label in a web form for "State" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_state">State</string>
+
+ <!-- Label in a web form for "ZIP code" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_zip_code">ZIP code</string>
+
+ <!-- Label in a web form for "County" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_county">County</string>
+
+ <!-- Label in a web form for "Island" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_island">Island</string>
+
+ <!-- Label in a web form for "District" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_district">District</string>
+
+ <!-- Label in a web form for "Department" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_department">Department</string>
+
+ <!-- Label in a web form for "Prefecture" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_prefecture">Prefecture</string>
+
+ <!-- Label in a web form for "Parish" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_parish">Parish</string>
+
+ <!-- Label in a web form for "Area" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_area">Area</string>
+
+ <!-- Label in a web form for "Emirate" [CHAR-LIMIT=NONE] -->
+ <string name="autofill_emirate">Emirate</string>
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
@@ -3004,9 +3036,10 @@
<!-- Title for a button to expand the list of activities in ActivityChooserView [CHAR LIMIT=25] -->
<string name="activity_chooser_view_see_all">See all...</string>
- <!-- Title for a message that there are no activities in ActivityChooserView [CHAR LIMIT=25] -->
- <string name="activity_chooser_view_no_activities">No activities</string>
- <!-- Title for a message that prompts selection of a default share handler in ActivityChooserView [CHAR LIMIT=25] -->
- <string name="activity_chooser_view_select_default">Select default</string>
+ <!-- Title default for a dialog showing possible activities in ActivityChooserView [CHAR LIMIT=25] -->
+ <string name="activity_chooser_view_dialog_title_default">Select activity</string>
+
+ <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] -->
+ <string name="share_action_provider_share_with">Share with...</string>
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index a5cd6e3..5b5e7c3 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -713,6 +713,16 @@
<item name="android:quickContactWindowSize">modeLarge</item>
</style>
+ <style name="Widget.ActivityChooserViewButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ <item name="android:adjustViewBounds">true</item>
+ <item name="android:scaleType">fitCenter</item>
+ <item name="android:padding">@android:dimen/action_bar_icon_vertical_padding</item>
+ </style>
+
<!-- Text Appearances -->
<eat-comment />
@@ -1672,6 +1682,7 @@
<style name="Widget.Holo.ProgressBar.Small" parent="Widget.ProgressBar.Small">
<item name="android:indeterminateDrawable">@android:drawable/progress_small_holo</item>
+ <item name="android:animationResolution">33</item>
</style>
<style name="Widget.Holo.ProgressBar.Small.Title">
@@ -1679,6 +1690,7 @@
<style name="Widget.Holo.ProgressBar.Large" parent="Widget.ProgressBar.Large">
<item name="android:indeterminateDrawable">@android:drawable/progress_large_holo</item>
+ <item name="android:animationResolution">33</item>
</style>
<style name="Widget.Holo.ProgressBar.Inverse">
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 00f47fa..b2ebb08 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -12,7 +12,7 @@
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver
+LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver guava
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 40fa552..146466f 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1242,6 +1242,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.animation.BasicAnimatorActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/core/tests/coretests/res/layout/animator_basic.xml b/core/tests/coretests/res/layout/animator_basic.xml
new file mode 100644
index 0000000..7b8ef11
--- /dev/null
+++ b/core/tests/coretests/res/layout/animator_basic.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/animatingButton"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
new file mode 100644
index 0000000..65f2b8e
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/AnimatorSetEventsTest.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.animation;
+
+import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
+/**
+ * Listener tests for AnimatorSet.
+ */
+public class AnimatorSetEventsTest extends EventsTest {
+
+ @Override
+ public void setUp() throws Exception {
+ final BasicAnimatorActivity activity = getActivity();
+ Button button = (Button) activity.findViewById(R.id.animatingButton);
+
+ ObjectAnimator xAnim = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
+ ObjectAnimator yAnim = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
+ mAnimator = new AnimatorSet();
+ ((AnimatorSet)mAnimator).playSequentially(xAnim, yAnim);
+
+ super.setUp();
+ }
+
+}
diff --git a/services/jni/com_android_server_InputWindow.h b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
similarity index 62%
rename from services/jni/com_android_server_InputWindow.h
rename to core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
index eaf7bde..93808d9 100644
--- a/services/jni/com_android_server_InputWindow.h
+++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java
@@ -13,20 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.animation;
-#ifndef _ANDROID_SERVER_INPUT_WINDOW_H
-#define _ANDROID_SERVER_INPUT_WINDOW_H
+import com.android.frameworks.coretests.R;
-#include <input/InputWindow.h>
+import android.app.Activity;
+import android.os.Bundle;
-#include "JNIHelp.h"
-#include "jni.h"
-
-namespace android {
-
-extern void android_server_InputWindow_toNative(
- JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow);
-
-} // namespace android
-
-#endif // _ANDROID_SERVER_INPUT_WINDOW_H
+public class BasicAnimatorActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.animator_basic);
+ }
+}
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
new file mode 100644
index 0000000..f970ffc
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+import android.os.Handler;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for the various lifecycle events of Animators. This abstract class is subclassed by
+ * concrete implementations that provide the actual Animator objects being tested. All of the
+ * testing mechanisms are in this class; the subclasses are only responsible for providing
+ * the mAnimator object.
+ *
+ * This test is more complicated than a typical synchronous test because much of the functionality
+ * must happen on the UI thread. Some tests do this by using the UiThreadTest annotation to
+ * automatically run the whole test on that thread. Other tests must run on the UI thread and also
+ * wait for some later event to occur before ending. These tests use a combination of an
+ * AbstractFuture mechanism and a delayed action to release that Future later.
+ */
+public abstract class EventsTest
+ extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+
+ private static final int ANIM_DURATION = 400;
+ private static final int ANIM_DELAY = 100;
+ private static final int ANIM_MID_DURATION = ANIM_DURATION / 2;
+ private static final int ANIM_MID_DELAY = ANIM_DELAY / 2;
+
+ private boolean mRunning; // tracks whether we've started the animator
+ private boolean mCanceled; // trackes whether we've canceled the animator
+ private Animator.AnimatorListener mFutureListener; // mechanism for delaying the end of the test
+ private FutureWaiter mFuture; // Mechanism for waiting for the UI test to complete
+ private Animator.AnimatorListener mListener; // Listener that handles/tests the events
+
+ protected Animator mAnimator; // The animator used in the tests. Must be set in subclass
+ // setup() method prior to calling the superclass setup()
+
+ /**
+ * Cancels the given animator. Used to delay cancelation until some later time (after the
+ * animator has started playing).
+ */
+ static class Canceler implements Runnable {
+ Animator mAnim;
+ public Canceler(Animator anim) {
+ mAnim = anim;
+ }
+ @Override
+ public void run() {
+ mAnim.cancel();
+ }
+ };
+
+ /**
+ * Releases the given Future object when the listener's end() event is called. Specifically,
+ * it releases it after some further delay, to give the test time to do other things right
+ * after an animation ends.
+ */
+ static class FutureReleaseListener extends AnimatorListenerAdapter {
+ FutureWaiter mFuture;
+
+ public FutureReleaseListener(FutureWaiter future) {
+ mFuture = future;
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ Handler handler = new Handler();
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mFuture.release();
+ }
+ }, ANIM_MID_DURATION);
+ }
+ };
+
+ public EventsTest() {
+ super(BasicAnimatorActivity.class);
+ }
+
+
+ /**
+ * Sets up the fields used by each test. Subclasses must override this method to create
+ * the protected mAnimator object used in all tests. Overrides must create that animator
+ * and then call super.setup(), where further properties are set on that animator.
+ * @throws Exception
+ */
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // mListener is the main testing mechanism of this file. The asserts of each test
+ // are embedded in the listener callbacks that it implements.
+ mListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ // This should only be called on an animation that has been started and not
+ // yet canceled or ended
+ assertFalse(mCanceled);
+ assertTrue(mRunning);
+ mCanceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // This should only be called on an animation that has been started and not
+ // yet ended
+ assertTrue(mRunning);
+ mRunning = false;
+ super.onAnimationEnd(animation);
+ }
+ };
+
+ mAnimator.addListener(mListener);
+ mAnimator.setDuration(ANIM_DURATION);
+
+ mFuture = new FutureWaiter();
+
+ mRunning = false;
+ mCanceled = false;
+ }
+
+ /**
+ * Verify that calling cancel on an unstarted animator does nothing.
+ */
+ @UiThreadTest
+ @SmallTest
+ public void testCancel() throws Exception {
+ mAnimator.cancel();
+ }
+
+ /**
+ * Verify that calling cancel on a started animator does the right thing.
+ */
+ @UiThreadTest
+ @SmallTest
+ public void testStartCancel() throws Exception {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ }
+
+ /**
+ * Same as testStartCancel, but with a startDelayed animator
+ */
+ @UiThreadTest
+ @SmallTest
+ public void testStartDelayedCancel() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ }
+
+ /**
+ * Verify that canceling an animator that is playing does the right thing.
+ */
+ @MediumTest
+ public void testPlayingCancel() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Handler handler = new Handler();
+ mAnimator.addListener(mFutureListener);
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+ /**
+ * Same as testPlayingCancel, but with a startDelayed animator
+ */
+ @MediumTest
+ public void testPlayingDelayedCancel() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Handler handler = new Handler();
+ mAnimator.addListener(mFutureListener);
+ mRunning = true;
+ mAnimator.start();
+ handler.postDelayed(new Canceler(mAnimator), ANIM_MID_DURATION);
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+ /**
+ * Verifies that canceling a started animation after it has already been canceled
+ * does nothing.
+ */
+ @MediumTest
+ public void testStartDoubleCancel() throws Exception {
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ mAnimator.cancel();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+ /**
+ * Same as testStartDoubleCancel, but with a startDelayed animator
+ */
+ @MediumTest
+ public void testStartDelayedDoubleCancel() throws Exception {
+ mAnimator.setStartDelay(ANIM_DELAY);
+ mFutureListener = new FutureReleaseListener(mFuture);
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mRunning = true;
+ mAnimator.start();
+ mAnimator.cancel();
+ mAnimator.cancel();
+ mFuture.release();
+ } catch (junit.framework.AssertionFailedError e) {
+ mFuture.setException(new RuntimeException(e));
+ }
+ }
+ });
+ mFuture.get();
+ }
+
+
+}
diff --git a/core/tests/coretests/src/android/animation/FutureWaiter.java b/core/tests/coretests/src/android/animation/FutureWaiter.java
new file mode 100644
index 0000000..320a1c2
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/FutureWaiter.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+import com.google.common.util.concurrent.AbstractFuture;
+
+/**
+ * Simple extension of {@link com.google.common.util.concurrent.AbstractFuture} which exposes a new
+ * release() method which calls the protected
+ * {@link com.google.common.util.concurrent.AbstractFuture#set(Object)} method internally. It
+ * also exposes the protected {@link AbstractFuture#setException(Throwable)} method.
+ */
+public class FutureWaiter extends AbstractFuture<Void> {
+
+ /**
+ * Release the Future currently waiting on
+ * {@link com.google.common.util.concurrent.AbstractFuture#get()}.
+ */
+ public void release() {
+ super.set(null);
+ }
+
+ @Override
+ public boolean setException(Throwable throwable) {
+ return super.setException(throwable);
+ }
+}
diff --git a/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
new file mode 100644
index 0000000..606a939
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/ObjectAnimatorEventsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.animation;
+
+import android.widget.Button;
+import com.android.frameworks.coretests.R;
+
+/**
+ * Listener tests for ObjectAnimator.
+ */
+public class ObjectAnimatorEventsTest extends EventsTest {
+
+ @Override
+ public void setUp() throws Exception {
+ final BasicAnimatorActivity activity = getActivity();
+ Button button = (Button) activity.findViewById(R.id.animatingButton);
+
+ mAnimator = ObjectAnimator.ofFloat(button, "translationX", 0, 100);
+ super.setUp();
+ }
+
+}
diff --git a/services/jni/com_android_server_InputWindow.h b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
similarity index 62%
copy from services/jni/com_android_server_InputWindow.h
copy to core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
index eaf7bde..c25d050 100644
--- a/services/jni/com_android_server_InputWindow.h
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorEventsTest.java
@@ -13,20 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package android.animation;
-#ifndef _ANDROID_SERVER_INPUT_WINDOW_H
-#define _ANDROID_SERVER_INPUT_WINDOW_H
+/**
+ * Listener tests for ValueAnimator.
+ */
+public class ValueAnimatorEventsTest extends EventsTest {
-#include <input/InputWindow.h>
+ @Override
+ public void setUp() throws Exception {
+ mAnimator = ValueAnimator.ofFloat(0, 1);
+ super.setUp();
+ }
-#include "JNIHelp.h"
-#include "jni.h"
-
-namespace android {
-
-extern void android_server_InputWindow_toNative(
- JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow);
-
-} // namespace android
-
-#endif // _ANDROID_SERVER_INPUT_WINDOW_H
+}
diff --git a/core/tests/coretests/src/android/content/ObserverNodeTest.java b/core/tests/coretests/src/android/content/ObserverNodeTest.java
index 736c759..95b8465 100644
--- a/core/tests/coretests/src/android/content/ObserverNodeTest.java
+++ b/core/tests/coretests/src/android/content/ObserverNodeTest.java
@@ -48,9 +48,9 @@
int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};
// special case
- root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root);
+ root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root, 0, 0);
for(int i = 1; i < uris.length; i++) {
- root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root);
+ root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root, 0, 0);
}
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
@@ -77,7 +77,7 @@
int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};
for(int i = 0; i < uris.length; i++) {
- root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root);
+ root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root, 0, 0);
}
ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
index 0b72c3c..9403d95 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java
@@ -54,8 +54,8 @@
// record data into narrow window to get single bucket
stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L);
- assertEquals(1, stats.bucketCount);
- assertBucket(stats, 0, 1024L, 2048L);
+ assertEquals(1, stats.size());
+ assertValues(stats, 0, 1024L, 2048L);
}
public void testRecordEqualBuckets() throws Exception {
@@ -66,9 +66,9 @@
final long recordStart = TEST_START + (bucketDuration / 2);
stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L);
- assertEquals(2, stats.bucketCount);
- assertBucket(stats, 0, 512L, 64L);
- assertBucket(stats, 1, 512L, 64L);
+ assertEquals(2, stats.size());
+ assertValues(stats, 0, 512L, 64L);
+ assertValues(stats, 1, 512L, 64L);
}
public void testRecordTouchingBuckets() throws Exception {
@@ -81,13 +81,13 @@
final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4);
stats.recordData(recordStart, recordEnd, 1000L, 5000L);
- assertEquals(3, stats.bucketCount);
+ assertEquals(3, stats.size());
// first bucket should have (1/20 of value)
- assertBucket(stats, 0, 50L, 250L);
+ assertValues(stats, 0, 50L, 250L);
// second bucket should have (15/20 of value)
- assertBucket(stats, 1, 750L, 3750L);
+ assertValues(stats, 1, 750L, 3750L);
// final bucket should have (4/20 of value)
- assertBucket(stats, 2, 200L, 1000L);
+ assertValues(stats, 2, 200L, 1000L);
}
public void testRecordGapBuckets() throws Exception {
@@ -101,9 +101,9 @@
stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, 64L, 512L);
// we should have two buckets, far apart from each other
- assertEquals(2, stats.bucketCount);
- assertBucket(stats, 0, 128L, 256L);
- assertBucket(stats, 1, 64L, 512L);
+ assertEquals(2, stats.size());
+ assertValues(stats, 0, 128L, 256L);
+ assertValues(stats, 1, 64L, 512L);
// now record something in middle, spread across two buckets
final long middleStart = TEST_START + DAY_IN_MILLIS;
@@ -111,11 +111,11 @@
stats.recordData(middleStart, middleEnd, 2048L, 2048L);
// now should have four buckets, with new record in middle two buckets
- assertEquals(4, stats.bucketCount);
- assertBucket(stats, 0, 128L, 256L);
- assertBucket(stats, 1, 1024L, 1024L);
- assertBucket(stats, 2, 1024L, 1024L);
- assertBucket(stats, 3, 64L, 512L);
+ assertEquals(4, stats.size());
+ assertValues(stats, 0, 128L, 256L);
+ assertValues(stats, 1, 1024L, 1024L);
+ assertValues(stats, 2, 1024L, 1024L);
+ assertValues(stats, 3, 64L, 512L);
}
public void testRecordOverlapBuckets() throws Exception {
@@ -128,14 +128,12 @@
stats.recordData(midStart, midStart + HOUR_IN_MILLIS, 1024L, 1024L);
// should have two buckets, with some data mixed together
- assertEquals(2, stats.bucketCount);
- assertBucket(stats, 0, 768L, 768L);
- assertBucket(stats, 1, 512L, 512L);
+ assertEquals(2, stats.size());
+ assertValues(stats, 0, 768L, 768L);
+ assertValues(stats, 1, 512L, 512L);
}
public void testRecordEntireGapIdentical() throws Exception {
- final long[] total = new long[2];
-
// first, create two separate histories far apart
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L);
@@ -150,19 +148,16 @@
stats.recordEntireHistory(stats2);
// first verify that totals match up
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 3000L, 1500L);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L);
// now inspect internal buckets
- assertBucket(stats, 0, 1000L, 500L);
- assertBucket(stats, 1, 1000L, 500L);
- assertBucket(stats, 2, 500L, 250L);
- assertBucket(stats, 3, 500L, 250L);
+ assertValues(stats, 0, 1000L, 500L);
+ assertValues(stats, 1, 1000L, 500L);
+ assertValues(stats, 2, 500L, 250L);
+ assertValues(stats, 3, 500L, 250L);
}
public void testRecordEntireOverlapVaryingBuckets() throws Exception {
- final long[] total = new long[2];
-
// create history just over hour bucket boundary
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L);
@@ -177,17 +172,16 @@
stats.recordEntireHistory(stats2);
// first verify that totals match up
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 650L, 650L);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
// now inspect internal buckets
- assertBucket(stats, 0, 10L, 10L);
- assertBucket(stats, 1, 20L, 20L);
- assertBucket(stats, 2, 20L, 20L);
- assertBucket(stats, 3, 20L, 20L);
- assertBucket(stats, 4, 20L, 20L);
- assertBucket(stats, 5, 20L, 20L);
- assertBucket(stats, 6, 10L, 10L);
+ assertValues(stats, 0, 10L, 10L);
+ assertValues(stats, 1, 20L, 20L);
+ assertValues(stats, 2, 20L, 20L);
+ assertValues(stats, 3, 20L, 20L);
+ assertValues(stats, 4, 20L, 20L);
+ assertValues(stats, 5, 20L, 20L);
+ assertValues(stats, 6, 10L, 10L);
// now combine using 15min buckets
stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4);
@@ -195,14 +189,13 @@
stats.recordEntireHistory(stats2);
// first verify that totals match up
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 650L, 650L);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L);
// and inspect buckets
- assertBucket(stats, 0, 200L, 200L);
- assertBucket(stats, 1, 150L, 150L);
- assertBucket(stats, 2, 150L, 150L);
- assertBucket(stats, 3, 150L, 150L);
+ assertValues(stats, 0, 200L, 200L);
+ assertValues(stats, 1, 150L, 150L);
+ assertValues(stats, 2, 150L, 150L);
+ assertValues(stats, 3, 150L, 150L);
}
public void testRemove() throws Exception {
@@ -210,28 +203,28 @@
// record some data across 24 buckets
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L);
- assertEquals(24, stats.bucketCount);
+ assertEquals(24, stats.size());
// try removing far before buckets; should be no change
stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS);
- assertEquals(24, stats.bucketCount);
+ assertEquals(24, stats.size());
// try removing just moments into first bucket; should be no change
// since that bucket contains data beyond the cutoff
stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS);
- assertEquals(24, stats.bucketCount);
+ assertEquals(24, stats.size());
// try removing single bucket
stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS);
- assertEquals(23, stats.bucketCount);
+ assertEquals(23, stats.size());
// try removing multiple buckets
stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS));
- assertEquals(20, stats.bucketCount);
+ assertEquals(20, stats.size());
// try removing all buckets
stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS);
- assertEquals(0, stats.bucketCount);
+ assertEquals(0, stats.size());
}
public void testTotalData() throws Exception {
@@ -241,27 +234,20 @@
// record uniform data across day
stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L);
- final long[] total = new long[2];
-
// verify that total outside range is 0
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, total);
- assertTotalEquals(total, 0, 0);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L);
// verify total in first hour
- stats.getTotalData(TEST_START, TEST_START + HOUR_IN_MILLIS, total);
- assertTotalEquals(total, 100, 200);
+ assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L);
// verify total across 1.5 hours
- stats.getTotalData(TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), total);
- assertTotalEquals(total, 150, 300);
+ assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L);
// verify total beyond end
- stats.getTotalData(TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 100, 200);
+ assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L);
// verify everything total
- stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total);
- assertTotalEquals(total, 2400, 4800);
+ assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L);
}
@@ -293,19 +279,27 @@
private static void assertConsistent(NetworkStatsHistory stats) {
// verify timestamps are monotonic
- for (int i = 1; i < stats.bucketCount; i++) {
- assertTrue(stats.bucketStart[i - 1] < stats.bucketStart[i]);
+ long lastStart = Long.MIN_VALUE;
+ NetworkStatsHistory.Entry entry = null;
+ for (int i = 0; i < stats.size(); i++) {
+ entry = stats.getValues(i, entry);
+ assertTrue(lastStart < entry.bucketStart);
+ lastStart = entry.bucketStart;
}
}
- private static void assertTotalEquals(long[] total, long rx, long tx) {
- assertEquals("unexpected rx", rx, total[0]);
- assertEquals("unexpected tx", tx, total[1]);
+ private static void assertValues(
+ NetworkStatsHistory stats, int index, long rxBytes, long txBytes) {
+ final NetworkStatsHistory.Entry entry = stats.getValues(index, null);
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
- private static void assertBucket(NetworkStatsHistory stats, int index, long rx, long tx) {
- assertEquals("unexpected rx", rx, stats.rx[index]);
- assertEquals("unexpected tx", tx, stats.tx[index]);
+ private static void assertValues(
+ NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
+ final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
}
diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java
index 3cb64c7..2434e9f 100644
--- a/core/tests/coretests/src/android/net/NetworkStatsTest.java
+++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java
@@ -31,9 +31,9 @@
public void testFindIndex() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 3)
- .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
- .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L)
- .addEntry(TEST_IFACE, 102, TAG_NONE, 1024L, 1024L);
+ .addValues(TEST_IFACE, 100, TAG_NONE, 1024L, 8L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, TAG_NONE, 0L, 0L, 1024L, 8L)
+ .addValues(TEST_IFACE, 102, TAG_NONE, 1024L, 8L, 1024L, 8L);
assertEquals(2, stats.findIndex(TEST_IFACE, 102, TAG_NONE));
assertEquals(2, stats.findIndex(TEST_IFACE, 102, TAG_NONE));
@@ -44,110 +44,106 @@
public void testAddEntryGrow() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 2);
- assertEquals(0, stats.size);
- assertEquals(2, stats.iface.length);
+ assertEquals(0, stats.size());
+ assertEquals(2, stats.internalSize());
- stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 1L, 2L);
- stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 2L, 2L);
+ stats.addValues(TEST_IFACE, TEST_UID, TAG_NONE, 1L, 1L, 2L, 2L);
+ stats.addValues(TEST_IFACE, TEST_UID, TAG_NONE, 2L, 2L, 2L, 2L);
- assertEquals(2, stats.size);
- assertEquals(2, stats.iface.length);
+ assertEquals(2, stats.size());
+ assertEquals(2, stats.internalSize());
- stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 3L, 4L);
- stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 4L, 4L);
- stats.addEntry(TEST_IFACE, TEST_UID, TAG_NONE, 5L, 5L);
+ stats.addValues(TEST_IFACE, TEST_UID, TAG_NONE, 3L, 30L, 4L, 40L);
+ stats.addValues(TEST_IFACE, TEST_UID, TAG_NONE, 4L, 40L, 4L, 40L);
+ stats.addValues(TEST_IFACE, TEST_UID, TAG_NONE, 5L, 50L, 5L, 50L);
- assertEquals(5, stats.size);
- assertTrue(stats.iface.length >= 5);
+ assertEquals(5, stats.size());
+ assertTrue(stats.internalSize() >= 5);
- assertEquals(1L, stats.rx[0]);
- assertEquals(2L, stats.rx[1]);
- assertEquals(3L, stats.rx[2]);
- assertEquals(4L, stats.rx[3]);
- assertEquals(5L, stats.rx[4]);
+ assertEntry(stats, 0, TEST_IFACE, TEST_UID, TAG_NONE, 1L, 1L, 2L, 2L);
+ assertEntry(stats, 1, TEST_IFACE, TEST_UID, TAG_NONE, 2L, 2L, 2L, 2L);
+ assertEntry(stats, 2, TEST_IFACE, TEST_UID, TAG_NONE, 3L, 30L, 4L, 40L);
+ assertEntry(stats, 3, TEST_IFACE, TEST_UID, TAG_NONE, 4L, 40L, 4L, 40L);
+ assertEntry(stats, 4, TEST_IFACE, TEST_UID, TAG_NONE, 5L, 50L, 5L, 50L);
}
public void testCombineExisting() throws Exception {
final NetworkStats stats = new NetworkStats(TEST_START, 10);
- stats.addEntry(TEST_IFACE, 1001, TAG_NONE, 512L, 256L);
- stats.addEntry(TEST_IFACE, 1001, 0xff, 128L, 128L);
- stats.combineEntry(TEST_IFACE, 1001, TAG_NONE, -128L, -128L);
+ stats.addValues(TEST_IFACE, 1001, TAG_NONE, 512L, 4L, 256L, 2L);
+ stats.addValues(TEST_IFACE, 1001, 0xff, 128L, 1L, 128L, 1L);
+ stats.combineValues(TEST_IFACE, 1001, TAG_NONE, -128L, -1L, -128L, -1L);
- assertStatsEntry(stats, 0, TEST_IFACE, 1001, TAG_NONE, 384L, 128L);
- assertStatsEntry(stats, 1, TEST_IFACE, 1001, 0xff, 128L, 128L);
+ assertEntry(stats, 0, TEST_IFACE, 1001, TAG_NONE, 384L, 3L, 128L, 1L);
+ assertEntry(stats, 1, TEST_IFACE, 1001, 0xff, 128L, 1L, 128L, 1L);
// now try combining that should create row
- stats.combineEntry(TEST_IFACE, 5005, TAG_NONE, 128L, 128L);
- assertStatsEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 128L, 128L);
- stats.combineEntry(TEST_IFACE, 5005, TAG_NONE, 128L, 128L);
- assertStatsEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 256L, 256L);
+ stats.combineValues(TEST_IFACE, 5005, TAG_NONE, 128L, 1L, 128L, 1L);
+ assertEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 128L, 1L, 128L, 1L);
+ stats.combineValues(TEST_IFACE, 5005, TAG_NONE, 128L, 1L, 128L, 1L);
+ assertEntry(stats, 2, TEST_IFACE, 5005, TAG_NONE, 256L, 2L, 256L, 2L);
}
public void testSubtractIdenticalData() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
- .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
+ .addValues(TEST_IFACE, 100, TAG_NONE, 1024L, 8L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, TAG_NONE, 0L, 0L, 1024L, 8L);
final NetworkStats after = new NetworkStats(TEST_START, 2)
- .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
- .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
+ .addValues(TEST_IFACE, 100, TAG_NONE, 1024L, 8L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, TAG_NONE, 0L, 0L, 1024L, 8L);
final NetworkStats result = after.subtract(before);
// identical data should result in zero delta
- assertEquals(0, result.rx[0]);
- assertEquals(0, result.tx[0]);
- assertEquals(0, result.rx[1]);
- assertEquals(0, result.tx[1]);
+ assertEntry(result, 0, TEST_IFACE, 100, TAG_NONE, 0L, 0L, 0L, 0L);
+ assertEntry(result, 1, TEST_IFACE, 101, TAG_NONE, 0L, 0L, 0L, 0L);
}
public void testSubtractIdenticalRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
- .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
+ .addValues(TEST_IFACE, 100, TAG_NONE, 1024L, 8L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, TAG_NONE, 0L, 0L, 1024L, 8L);
final NetworkStats after = new NetworkStats(TEST_START, 2)
- .addEntry(TEST_IFACE, 100, TAG_NONE, 1025L, 2L)
- .addEntry(TEST_IFACE, 101, TAG_NONE, 3L, 1028L);
+ .addValues(TEST_IFACE, 100, TAG_NONE, 1025L, 9L, 2L, 1L)
+ .addValues(TEST_IFACE, 101, TAG_NONE, 3L, 1L, 1028L, 9L);
final NetworkStats result = after.subtract(before);
// expect delta between measurements
- assertEquals(1, result.rx[0]);
- assertEquals(2, result.tx[0]);
- assertEquals(3, result.rx[1]);
- assertEquals(4, result.tx[1]);
+ assertEntry(result, 0, TEST_IFACE, 100, TAG_NONE, 1L, 1L, 2L, 1L);
+ assertEntry(result, 1, TEST_IFACE, 101, TAG_NONE, 3L, 1L, 4L, 1L);
}
public void testSubtractNewRows() throws Exception {
final NetworkStats before = new NetworkStats(TEST_START, 2)
- .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
- .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L);
+ .addValues(TEST_IFACE, 100, TAG_NONE, 1024L, 8L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, TAG_NONE, 0L, 0L, 1024L, 8L);
final NetworkStats after = new NetworkStats(TEST_START, 3)
- .addEntry(TEST_IFACE, 100, TAG_NONE, 1024L, 0L)
- .addEntry(TEST_IFACE, 101, TAG_NONE, 0L, 1024L)
- .addEntry(TEST_IFACE, 102, TAG_NONE, 1024L, 1024L);
+ .addValues(TEST_IFACE, 100, TAG_NONE, 1024L, 8L, 0L, 0L)
+ .addValues(TEST_IFACE, 101, TAG_NONE, 0L, 0L, 1024L, 8L)
+ .addValues(TEST_IFACE, 102, TAG_NONE, 1024L, 8L, 1024L, 8L);
final NetworkStats result = after.subtract(before);
// its okay to have new rows
- assertEquals(0, result.rx[0]);
- assertEquals(0, result.tx[0]);
- assertEquals(0, result.rx[1]);
- assertEquals(0, result.tx[1]);
- assertEquals(1024, result.rx[2]);
- assertEquals(1024, result.tx[2]);
+ assertEntry(result, 0, TEST_IFACE, 100, TAG_NONE, 0L, 0L, 0L, 0L);
+ assertEntry(result, 1, TEST_IFACE, 101, TAG_NONE, 0L, 0L, 0L, 0L);
+ assertEntry(result, 2, TEST_IFACE, 102, TAG_NONE, 1024L, 8L, 1024L, 8L);
}
- private static void assertStatsEntry(
- NetworkStats stats, int i, String iface, int uid, int tag, long rx, long tx) {
- assertEquals(iface, stats.iface[i]);
- assertEquals(uid, stats.uid[i]);
- assertEquals(tag, stats.tag[i]);
- assertEquals(rx, stats.rx[i]);
- assertEquals(tx, stats.tx[i]);
+ private static void assertEntry(NetworkStats stats, int index, String iface, int uid, int tag,
+ long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ final NetworkStats.Entry entry = stats.getValues(index, null);
+ assertEquals(iface, entry.iface);
+ assertEquals(uid, entry.uid);
+ assertEquals(tag, entry.tag);
+ assertEquals(rxBytes, entry.rxBytes);
+ assertEquals(rxPackets, entry.rxPackets);
+ assertEquals(txBytes, entry.txBytes);
+ assertEquals(txPackets, entry.txPackets);
}
}
diff --git a/core/tests/coretests/src/android/util/JsonReaderTest.java b/core/tests/coretests/src/android/util/JsonReaderTest.java
index b5c2c27..440aeb5 100644
--- a/core/tests/coretests/src/android/util/JsonReaderTest.java
+++ b/core/tests/coretests/src/android/util/JsonReaderTest.java
@@ -856,4 +856,33 @@
} catch (IOException expected) {
}
}
+
+ public void testFailWithPosition() throws IOException {
+ testFailWithPosition("Expected literal value at line 6 column 3",
+ "[\n\n\n\n\n0,}]");
+ }
+
+ public void testFailWithPositionGreaterThanBufferSize() throws IOException {
+ String spaces = repeat(' ', 8192);
+ testFailWithPosition("Expected literal value at line 6 column 3",
+ "[\n\n" + spaces + "\n\n\n0,}]");
+ }
+
+ private void testFailWithPosition(String message, String json) throws IOException {
+ JsonReader reader = new JsonReader(new StringReader(json));
+ reader.beginArray();
+ reader.nextInt();
+ try {
+ reader.peek();
+ fail();
+ } catch (IOException expected) {
+ assertEquals(message, expected.getMessage());
+ }
+ }
+
+ private String repeat(char c, int count) {
+ char[] array = new char[count];
+ Arrays.fill(array, c);
+ return new String(array);
+ }
}
diff --git a/core/tests/coretests/src/android/util/JsonWriterTest.java b/core/tests/coretests/src/android/util/JsonWriterTest.java
index b29e2fd..1239a3c 100644
--- a/core/tests/coretests/src/android/util/JsonWriterTest.java
+++ b/core/tests/coretests/src/android/util/JsonWriterTest.java
@@ -289,6 +289,15 @@
+ "\"\\u0019\"]", stringWriter.toString());
}
+ public void testUnicodeLineBreaksEscaped() throws IOException {
+ StringWriter stringWriter = new StringWriter();
+ JsonWriter jsonWriter = new JsonWriter(stringWriter);
+ jsonWriter.beginArray();
+ jsonWriter.value("\u2028 \u2029");
+ jsonWriter.endArray();
+ assertEquals("[\"\\u2028 \\u2029\"]", stringWriter.toString());
+ }
+
public void testEmptyArray() throws IOException {
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(stringWriter);
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index c54e4a1..7dc95db 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -16,13 +16,13 @@
package android.widget;
-import com.android.frameworks.coretests.R;
-
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.GetChars;
import android.view.View;
+import com.android.frameworks.coretests.R;
+
/**
* TextViewTest tests {@link TextView}.
*/
@@ -240,12 +240,12 @@
getActivity().runOnUiThread(new Runnable() {
public void run() {
- tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
+ ll.setTextDirection(View.TEXT_DIRECTION_RTL);
+ tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
assertEquals(View.TEXT_DIRECTION_RTL, tv.getResolvedTextDirection());
- assertEquals(true, tv.isResolvedTextDirection());
ll.removeView(tv);
- assertEquals(false, tv.isResolvedTextDirection());
+ assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getResolvedTextDirection());
}
});
}
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
new file mode 100644
index 0000000..c0d9153
--- /dev/null
+++ b/data/fonts/fallback_fonts.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Fallback Fonts
+
+ This file specifies the fonts, and the priority order, that will be searched for any
+ glyphs not handled by the default fonts specified in /system/etc/system_fonts.xml.
+ Each entry consists of a family tag and a list of files (file names) which support that
+ family. The fonts for each family are listed in the order of the styles that they
+ handle (the order is: regular, bold, italic, and bold-italic). The order in which the
+ families are listed in this file represents the order in which these fallback fonts
+ will be searched for glyphs that are not supported by the default system fonts (which are
+ found in /system/etc/system_fonts.xml).
+
+ Note that there is not nameset for fallback fonts, unlike the fonts specified in
+ system_fonts.xml. The ability to support specific names in fallback fonts may be supported
+ in the future. For now, the lack of files entries here is an indicator to the system that
+ these are fallback fonts, instead of default named system fonts.
+
+ There is another optional file in /vendor/etc/fallback_fonts.xml. That file can be used to
+ provide references to other font families that should be used in addition to the default
+ fallback fonts. That file can also specify the order in which the fallback fonts should be
+ searched, to ensure that a vendor-provided font will be used before another fallback font
+ which happens to handle the same glyph.
+-->
+<familyset>
+ <family>
+ <fileset>
+ <file>DroidSansArabic.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>DroidSansHebrew-Regular.ttf</file>
+ <file>DroidSansHebrew-Bold.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>DroidSansThai.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>DroidSansFallback.ttf</file>
+ </fileset>
+ </family>
+</familyset>
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index d222c0b..57a1bab 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -30,4 +30,6 @@
frameworks/base/data/fonts/DroidSansFallback.ttf:system/fonts/DroidSansFallback.ttf \
frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
- frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf
+ frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \
+ frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \
+ frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml
diff --git a/data/fonts/system_fonts.xml b/data/fonts/system_fonts.xml
new file mode 100644
index 0000000..8d8d020
--- /dev/null
+++ b/data/fonts/system_fonts.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ System Fonts
+
+ This file lists the font families that will be used by default for all supported glyphs.
+ Each entry consists of a family, various names that are supported by that family, and
+ up to four font files. The font files are listed in the order of the styles which they
+ support: regular, bold, italic and bold-italic. If less than four styles are listed, then
+ the styles with no associated font file will be supported by the other font files listed.
+
+ The first family is also the default font, which handles font request that have not specified
+ specific font names.
+
+ Any glyph that is not handled by the system fonts will cause a search of the fallback fonts.
+ The default fallback fonts are specified in the file /system/etc/fallback_fonts.xml, and there
+ is an optional file which may be supplied by vendors to specify other fallback fonts to use
+ in /vendor/etc/fallback_fonts.xml.
+-->
+<familyset>
+
+ <family>
+ <nameset>
+ <name>sans-serif</name>
+ <name>arial</name>
+ <name>helvetica</name>
+ <name>tahoma</name>
+ <name>verdana</name>
+ </nameset>
+ <fileset>
+ <file>DroidSans.ttf</file>
+ <file>DroidSans-Bold.ttf</file>
+ </fileset>
+ </family>
+
+ <family>
+ <nameset>
+ <name>serif</name>
+ <name>times</name>
+ <name>times new roman</name>
+ <name>palatino</name>
+ <name>georgia</name>
+ <name>baskerville</name>
+ <name>goudy</name>
+ <name>fantasy</name>
+ <name>cursive</name>
+ <name>ITC Stone Serif</name>
+ </nameset>
+ <fileset>
+ <file>DroidSerif-Regular.ttf</file>
+ <file>DroidSerif-Bold.ttf</file>
+ <file>DroidSerif-Italic.ttf</file>
+ <file>DroidSerif-BoldItalic.ttf</file>
+ </fileset>
+ </family>
+
+ <family>
+ <nameset>
+ <name>monospace</name>
+ <name>courier</name>
+ <name>courier new</name>
+ <name>monaco</name>
+ </nameset>
+ <fileset>
+ <file>DroidSansMono.ttf</file>
+ </fileset>
+ </family>
+
+</familyset>
diff --git a/data/fonts/vendor_fonts.xml b/data/fonts/vendor_fonts.xml
new file mode 100644
index 0000000..fe51fd2
--- /dev/null
+++ b/data/fonts/vendor_fonts.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Vendor-provided fallback fonts
+
+ This file can be edited to add references to fonts that are not installed or referenced in the
+ default system. The file should then be placed in /vendor/etc/fallback_fonts.xml.
+
+ For example, vendors might want to build configurations for locales that are
+ better served by fonts which either handle glyphs not supported in the default fonts or which
+ handle these glyphs differently than the default fallback fonts.
+ Each entry in this list is a "family", which consists of a list of "files"
+ (the filenames for that family). The files objects are
+ provided in the order of the styles supported for that family: regular, bold, italic, and
+ bold-italic. Only providing one font means that all styles will be rendered with that font.
+ Providing two means that these two fonts will render regular and bold fonts (italics will
+ be mapped to these two fonts).
+
+ There is also an optional "order" attribute on the Family tag. This specifies the index at
+ which that family of fonts should be inserted in the fallback font list, where the
+ default fallback fonts on the system (in /system/etc/fallback_fonts.xml) start at index 0.
+ If no 'order' attribute is supplied, that family will be inserted either at the end of the
+ current fallback list (if no order was supplied for any previous family in this file) or
+ after the previous family (if there was an order specified previously). Typically, vendors
+ may want to supply an order for the first family that puts this set of fonts at the appropriate
+ place in the overall fallback fonts. The order of this list determines which fallback font
+ will be used to support any glyphs that are not handled by the default system fonts.
+
+ The sample configuration below is an example of how one might provide two families of fonts
+ that get inserted at the first and second (0 and 1) position in the overall fallback fonts.
+
+ See /system/etc/system_fonts.xml and /system/etc/fallback_fonts.xml for more information
+ and to understand the order in which the default system fonts are loaded and structured for
+ lookup.
+-->
+
+<!-- Sample fallback font additions to the default fallback list. These fonts will be added
+ to the top two positions of the fallback list, since the first has an order of 0. -->
+<!--
+<familyset>
+ <family order="0">
+ <fileset>
+ <file>MyFont.ttf</file>
+ </fileset>
+ </family>
+ <family>
+ <fileset>
+ <file>MyOtherFont.ttf</file>
+ </fileset>
+ </family>
+</familyset>
+-->
\ No newline at end of file
diff --git a/data/sounds/effects/ogg/Dock.ogg b/data/sounds/effects/ogg/Dock.ogg
old mode 100644
new mode 100755
index 626d695..a1c1f2c
--- a/data/sounds/effects/ogg/Dock.ogg
+++ b/data/sounds/effects/ogg/Dock.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressDelete.ogg b/data/sounds/effects/ogg/KeypressDelete.ogg
old mode 100644
new mode 100755
index 5e724f4..38c3244
--- a/data/sounds/effects/ogg/KeypressDelete.ogg
+++ b/data/sounds/effects/ogg/KeypressDelete.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressReturn.ogg b/data/sounds/effects/ogg/KeypressReturn.ogg
old mode 100644
new mode 100755
index a1200b2..1bd5b73
--- a/data/sounds/effects/ogg/KeypressReturn.ogg
+++ b/data/sounds/effects/ogg/KeypressReturn.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressSpacebar.ogg b/data/sounds/effects/ogg/KeypressSpacebar.ogg
old mode 100644
new mode 100755
index 0d0fbf1..3a83594
--- a/data/sounds/effects/ogg/KeypressSpacebar.ogg
+++ b/data/sounds/effects/ogg/KeypressSpacebar.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/KeypressStandard.ogg b/data/sounds/effects/ogg/KeypressStandard.ogg
old mode 100644
new mode 100755
index 5878135..4b8d128
--- a/data/sounds/effects/ogg/KeypressStandard.ogg
+++ b/data/sounds/effects/ogg/KeypressStandard.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Lock.ogg b/data/sounds/effects/ogg/Lock.ogg
old mode 100644
new mode 100755
index a25513f..deeba68
--- a/data/sounds/effects/ogg/Lock.ogg
+++ b/data/sounds/effects/ogg/Lock.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/LowBattery.ogg b/data/sounds/effects/ogg/LowBattery.ogg
old mode 100644
new mode 100755
index c21218c..370c86c
--- a/data/sounds/effects/ogg/LowBattery.ogg
+++ b/data/sounds/effects/ogg/LowBattery.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Undock.ogg b/data/sounds/effects/ogg/Undock.ogg
old mode 100644
new mode 100755
index dd132c4..91e410e
--- a/data/sounds/effects/ogg/Undock.ogg
+++ b/data/sounds/effects/ogg/Undock.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/Unlock.ogg b/data/sounds/effects/ogg/Unlock.ogg
old mode 100644
new mode 100755
index 490f98e..ac50288
--- a/data/sounds/effects/ogg/Unlock.ogg
+++ b/data/sounds/effects/ogg/Unlock.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/camera_click.ogg b/data/sounds/effects/ogg/camera_click.ogg
old mode 100644
new mode 100755
index eee590f..bfb2a68
--- a/data/sounds/effects/ogg/camera_click.ogg
+++ b/data/sounds/effects/ogg/camera_click.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Argon.ogg b/data/sounds/notifications/ogg/Argon.ogg
old mode 100644
new mode 100755
index f160562..e58b3b6
--- a/data/sounds/notifications/ogg/Argon.ogg
+++ b/data/sounds/notifications/ogg/Argon.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Beryllium.ogg b/data/sounds/notifications/ogg/Beryllium.ogg
old mode 100644
new mode 100755
index 5f7bd3c..2c5b4fe
--- a/data/sounds/notifications/ogg/Beryllium.ogg
+++ b/data/sounds/notifications/ogg/Beryllium.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Cobalt.ogg b/data/sounds/notifications/ogg/Cobalt.ogg
old mode 100644
new mode 100755
index a9adeb8..b6e253a
--- a/data/sounds/notifications/ogg/Cobalt.ogg
+++ b/data/sounds/notifications/ogg/Cobalt.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Fluorine.ogg b/data/sounds/notifications/ogg/Fluorine.ogg
old mode 100644
new mode 100755
index 6340cf3..fd884f5
--- a/data/sounds/notifications/ogg/Fluorine.ogg
+++ b/data/sounds/notifications/ogg/Fluorine.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Gallium.ogg b/data/sounds/notifications/ogg/Gallium.ogg
old mode 100644
new mode 100755
index b0446b2..3c7e1156
--- a/data/sounds/notifications/ogg/Gallium.ogg
+++ b/data/sounds/notifications/ogg/Gallium.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Radon.ogg b/data/sounds/notifications/ogg/Radon.ogg
old mode 100644
new mode 100755
index 1d70c11..550cddd
--- a/data/sounds/notifications/ogg/Radon.ogg
+++ b/data/sounds/notifications/ogg/Radon.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Selenium.ogg b/data/sounds/notifications/ogg/Selenium.ogg
old mode 100644
new mode 100755
index 7624eff..9d60917
--- a/data/sounds/notifications/ogg/Selenium.ogg
+++ b/data/sounds/notifications/ogg/Selenium.ogg
Binary files differ
diff --git a/data/sounds/notifications/ogg/Zirconium.ogg b/data/sounds/notifications/ogg/Zirconium.ogg
old mode 100644
new mode 100755
index 31e40c1..d84b59e
--- a/data/sounds/notifications/ogg/Zirconium.ogg
+++ b/data/sounds/notifications/ogg/Zirconium.ogg
Binary files differ
diff --git a/docs/html/guide/developing/tools/adb.jd b/docs/html/guide/developing/tools/adb.jd
index a109dc8..78d12ef 100644
--- a/docs/html/guide/developing/tools/adb.jd
+++ b/docs/html/guide/developing/tools/adb.jd
@@ -503,7 +503,7 @@
<ul>
<li><code>V</code> — Verbose (lowest priority)</li>
<li><code>D</code> — Debug</li>
- <li><code>I</code> — Info</li>
+ <li><code>I</code> — Info (default priority)</li>
<li><code>W</code> — Warning</li>
<li><code>E</code> — Error</li>
<li><code>F</code> — Fatal</li>
@@ -520,7 +520,7 @@
<p>To reduce the log output to a manageable level, you can restrict log output using <em>filter expressions</em>. Filter expressions let you indicate to the system the tags-priority combinations that you are interested in — the system suppresses other messages for the specified tags. </p>
-<p>A filter expression follows this format <code>tag:priority ...</code>, where <code>tag</code> indicates the tag of interest and <code>priority</code> indicates the <em>minimum</em> level of priority to report for that tag. Messages for that tag at or above the specified priority are written to the log. You can supply any number of <code>tag:priority</code> specifications in a single filter expression. The series of specifications is whitespace-delimited. </p>
+<p>A filter expression follows this format <code>tag:priority ...</code>, where <code>tag</code> indicates the tag of interest and <code>priority</code> indicates the <em>minimum</em> level of priority to report for that tag. Messages for that tag at or above the specified priority are written to the log. You can supply any number of <code>tag:priority</code> specifications in a single filter expression. The series of specifications is whitespace-delimited. The default output is to show all log messages with the Info priority (*:I).</p>
<p>Here's an example of a filter expression that suppresses all log messages except those with the tag "ActivityManager", at priority "Info" or above, and all log messages with tag "MyApp", with priority "Debug" or above:</p>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 3ec174e..f7dbe30 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -256,8 +256,7 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/topics/renderscript/index.html">
<span class="en">RenderScript</span>
- </a>
- <span class="new">new!</span></div>
+ </a></div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/renderscript/graphics.html">
<span class="en">3D Graphics</span>
@@ -304,11 +303,9 @@
<!--<li><a style="color:gray;">Localization</a></li> -->
<li><a href="<?cs var:toroot ?>guide/topics/appwidgets/index.html">
<span class="en">App Widgets</span></a>
- <span class="new">updated</span>
</li>
<li><a href="<?cs var:toroot?>guide/topics/wireless/bluetooth.html">
<span class="en">Bluetooth</span></a>
- <span class="new">updated</span>
</li>
<li><a href="<?cs var:toroot?>guide/topics/nfc/index.html">
<span class="en">Near Field Communication</span>
@@ -316,7 +313,6 @@
<li class="toggle-list">
<div><a href="<?cs var:toroot?>guide/topics/usb/index.html">
<span class="en">USB</span></a>
- <span class="new">new!</span>
</div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/usb/accessory.html">Accessory</a></li>
@@ -341,7 +337,6 @@
</li>
<li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
<span class="en">Device Administration</span></a>
- <span class="new">updated</span>
</li>
<li class="toggle-list">
<div>
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 3fcfa89..362ee16 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -74,6 +74,6 @@
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on May 6, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on July 1, 2011</em></p>
</div>
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index e980ca5..97df84f 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,16 +1,16 @@
ndk=true
-ndk.win_download=android-ndk-r5c-windows.zip
-ndk.win_bytes=61627716
-ndk.win_checksum=2c7423842fa0f46871eab118495d4b45
+ndk.win_download=android-ndk-r6-windows.zip
+ndk.win_bytes=67642809
+ndk.win_checksum=9c7d5ccc02151a3e5e950c70dc05ac6d
-ndk.mac_download=android-ndk-r5c-darwin-x86.tar.bz2
-ndk.mac_bytes=50714712
-ndk.mac_checksum=183bfbbd85cf8e4c0bd7531e8803e75d
+ndk.mac_download=android-ndk-r6-darwin-x86.tar.bz2
+ndk.mac_bytes=52682746
+ndk.mac_checksum=a154905e49a6246abd823b75b6eda738
-ndk.linux_download=android-ndk-r5c-linux-x86.tar.bz2
-ndk.linux_bytes=44539890
-ndk.linux_checksum=7659dfdc97026ed1d913e224d0531f61
+ndk.linux_download=android-ndk-r6-linux-x86.tar.bz2
+ndk.linux_bytes=46425290
+ndk.linux_checksum=ff0a43085fe206696d5cdcef3f4f4637
page.title=Android NDK
@jd:body
@@ -62,6 +62,58 @@
<div class="toggleable open">
<a href="#" onclick="return toggleDiv(this)"><img src=
"{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px">
+ Android NDK, Revision 6</a> <em>(July 2011)</em>
+
+ <div class="toggleme">
+ <p>This release of the NDK includes support for the x86 ABI and other minor changes.
+ For detailed information describing the changes in this release, read the
+ <code>CHANGES.HTML</code> document included in the NDK package.
+ </p>
+ <dl>
+ <dt>General notes:</dt>
+ <dd>
+ <ul>
+ <li>Adds support for the x86 ABI, which allows you to generate machine code
+ that runs on compatible x86-based Android devices. Major features for x86
+ include x86-specific toolchains, system headers, libraries and
+ debugging support. For all of the details regarding x86 support,
+ see <code>docs/CPU-X86.html</code> in the NDK package.
+
+ <p>By default, code is generated for ARM-based devices, but you can add x86 to your
+ <code>APP_ABI</code> definition in your <code>Application.mk</code> file to build
+ for x86 platforms. For example, the following line instructs <code>ndk-build</code>
+ to build your code for three distinct ABIs:</p>
+
+ <pre>APP_ABI := armeabi armeabi-v7a x86</pre>
+
+ <p>Unless you rely on ARM-based assembly sources, you shouldn't need to touch
+ your <code>Android.mk</code> files to build x86 machine code.</p>
+
+ </li>
+
+ <li>You can build a standalone x86 toolchain using the <code>--toolchain=x86-4.4.3</code>
+ option when calling <code>make-standalone-toolchain.sh</code>. See
+ <code>docs/STANDALONE-TOOLCHAIN.html</code> for more details.
+ </li>
+ <li>The new <code>ndk-stack</code> tool lets you translate stack traces in
+ <code>logcat</code> that are generated by native code. The tool translates
+ instruction addresses into a readable format that contains things such
+ as the function, source file, and line number corresponding to each stack frame.
+ For more information and a usage example, see <code>docs/NDK-STACK.html</code>.
+ </li>
+ </ul>
+ </dd>
+ <dt>Other changes:</dt>
+ <dd><code>arm-eabi-4.4.0</code>, which had been deprecated since NDK r5, has been
+ removed from the NDK distribution.</dd>
+
+ </dl>
+ </div>
+ </div>
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)"><img src=
+ "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px">
Android NDK, Revision 5c</a> <em>(June 2011)</em>
<div class="toggleme">
diff --git a/docs/html/sdk/ndk/overview.jd b/docs/html/sdk/ndk/overview.jd
index 2562a25..93c664d 100644
--- a/docs/html/sdk/ndk/overview.jd
+++ b/docs/html/sdk/ndk/overview.jd
@@ -53,11 +53,7 @@
<li>ARMv7-A (including Thumb-2 and VFPv3-D16 instructions, with optional support for
NEON/VFPv3-D32 instructions)</li>
- </ul>
- <p>Future releases of the NDK will also support:</p>
-
- <ul>
<li>x86 instructions (see CPU-ARCH-ABIS.HTML for more information)</li>
</ul>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 0607aad..0539adb 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -77,7 +77,7 @@
<ul>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>sdk/android-3.1.html">
- <span class="en">Android 3.1 Platform</span></a> <span class="new">new!</span></div>
+ <span class="en">Android 3.1 Platform</span></a></div>
<ul>
<li><a href="<?cs var:toroot ?>sdk/android-3.1-highlights.html">Platform Highlights</a></li>
<li><a href="<?cs var:toroot ?>sdk/api_diff/12/changes.html">API Differences Report »</a></li>
@@ -91,7 +91,7 @@
<li><a href="<?cs var:toroot ?>sdk/api_diff/11/changes.html">API Differences Report »</a></li>
</ul>
</li>
- <li><a href="<?cs var:toroot ?>sdk/android-2.3.4.html">Android 2.3.4 Platform</span></a> <span class="new">new!</span></li>
+ <li><a href="<?cs var:toroot ?>sdk/android-2.3.4.html">Android 2.3.4 Platform</span></a></li>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>sdk/android-2.3.3.html">
<span class="en">Android 2.3.3 Platform</span></a></div>
@@ -137,8 +137,8 @@
<li><a href="<?cs var:toroot ?>sdk/tools-notes.html">SDK Tools, r12</a> <span
class="new">new!</span></li>
<li><a href="<?cs var:toroot ?>sdk/win-usb.html">Google USB Driver, r4</a></li>
- <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Compatibility Library, r2</a> <span
-class="new">new!</span></li>
+ <li><a href="<?cs var:toroot ?>sdk/compatibility-library.html">Compatibility Library,
+r2</a></li>
</ul>
</li>
<li>
@@ -175,7 +175,7 @@
<span style="display:none" class="zh-TW"></span>
</h2>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r5c <span
+ <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6 <span
class="new">new!</span></a>
</li>
<li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
diff --git a/drm/drmserver/Android.mk b/drm/drmserver/Android.mk
index e3cd44f..fd417cb 100644
--- a/drm/drmserver/Android.mk
+++ b/drm/drmserver/Android.mk
@@ -24,13 +24,8 @@
LOCAL_SHARED_LIBRARIES := \
libmedia \
libutils \
- libbinder
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
+ libbinder \
+ libdl
LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk
index 69bb48d..4a55fc0 100644
--- a/drm/jni/Android.mk
+++ b/drm/jni/Android.mk
@@ -26,13 +26,8 @@
libutils \
libandroid_runtime \
libnativehelper \
- libbinder
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
+ libbinder \
+ libdl
LOCAL_STATIC_LIBRARIES :=
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
index f1526a4..c534402 100644
--- a/drm/libdrmframework/Android.mk
+++ b/drm/libdrmframework/Android.mk
@@ -25,13 +25,8 @@
LOCAL_SHARED_LIBRARIES := \
libutils \
- libbinder
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
+ libbinder \
+ libdl
LOCAL_STATIC_LIBRARIES := \
libdrmframeworkcommon
diff --git a/drm/libdrmframework/plugins/passthru/Android.mk b/drm/libdrmframework/plugins/passthru/Android.mk
index be18b64..d0d1439 100644
--- a/drm/libdrmframework/plugins/passthru/Android.mk
+++ b/drm/libdrmframework/plugins/passthru/Android.mk
@@ -24,14 +24,8 @@
LOCAL_STATIC_LIBRARIES := libdrmframeworkcommon
LOCAL_SHARED_LIBRARIES := \
- libutils
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
-
+ libutils \
+ libdl
LOCAL_C_INCLUDES += \
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5b50f8f..35ed4d2 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1414,77 +1414,13 @@
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
- native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
+ native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint);
TemporaryBuffer.recycle(buf);
}
}
/**
- * Draw the text, with origin at (x,y), using the specified paint. The
- * origin is interpreted based on the Align setting in the paint.
- *
- * @param text The text to be drawn
- * @param x The x-coordinate of the origin of the text being drawn
- * @param y The y-coordinate of the origin of the text being drawn
- * @param paint The paint used for the text (e.g. color, size, style)
- *
- * @hide
- *
- * Used only for BiDi / RTL Tests
- */
- public void drawTextWithGlyphs(char[] text, int index, int count, float x, float y,
- Paint paint) {
- if ((index | count | (index + count) |
- (text.length - index - count)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- native_drawTextWithGlyphs(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
- paint.mNativePaint);
- }
-
- /**
- * Draw the text, with origin at (x,y), using the specified paint. The
- * origin is interpreted based on the Align setting in the paint.
- *
- * @param text The text to be drawn
- * @param x The x-coordinate of the origin of the text being drawn
- * @param y The y-coordinate of the origin of the text being drawn
- * @param paint The paint used for the text (e.g. color, size, style)
- *
- * @hide
- *
- * Used only for BiDi / RTL Tests
- */
- public void drawTextWithGlyphs(String text, float x, float y, Paint paint) {
- native_drawTextWithGlyphs(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
- paint.mNativePaint);
- }
-
- /**
- * Draw the glyphs, with origin at (x,y), using the specified paint. The
- * origin is interpreted based on the Align setting in the paint.
- *
- * @param glyphs The glyphs to be drawn
- * @param x The x-coordinate of the origin of the text being drawn
- * @param y The y-coordinate of the origin of the text being drawn
- * @param paint The paint used for the text (e.g. color, size, style)
- *
- * @hide
- *
- * Used only for BiDi / RTL Tests
- */
- public void drawGlyphs(char[] glyphs, int index, int count, float x, float y,
- Paint paint) {
- if ((index | count | (index + count) |
- (glyphs.length - index - count)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- native_drawGlyphs(mNativeCanvas, glyphs, index, count, x, y, paint.mBidiFlags,
- paint.mNativePaint);
- }
-
- /**
* Render a run of all LTR or all RTL text, with shaping. This does not run
* bidi on the provided text, but renders it as a uniform right-to-left or
* left-to-right run, as indicated by dir. Alignment of the text is as
@@ -1813,16 +1749,6 @@
int start, int end, float x,
float y, int flags, int paint);
- private static native void native_drawTextWithGlyphs(int nativeCanvas, char[] text,
- int index, int count, float x,
- float y, int flags, int paint);
- private static native void native_drawTextWithGlyphs(int nativeCanvas, String text,
- int start, int end, float x,
- float y, int flags, int paint);
- private static native void native_drawGlyphs(int nativeCanvas, char[] glyphs,
- int index, int count, float x,
- float y, int flags, int paint);
-
private static native void native_drawTextRun(int nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, int flags, int paint);
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 6254192..12e5ada 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -155,6 +155,14 @@
}
}
+
+ private int getIDSafe() {
+ if (mAdaptedAllocation != null) {
+ return mAdaptedAllocation.getID();
+ }
+ return getID();
+ }
+
private void updateCacheInfo(Type t) {
mCurrentDimX = t.getX();
mCurrentDimY = t.getY();
@@ -262,7 +270,7 @@
throw new RSIllegalArgumentException("Source must be exactly one usage type.");
}
mRS.validate();
- mRS.nAllocationSyncAll(getID(), srcLocation);
+ mRS.nAllocationSyncAll(getIDSafe(), srcLocation);
}
public void copyFrom(BaseObj[] d) {
@@ -480,7 +488,7 @@
" does not match component size " + eSize + ".");
}
- mRS.nAllocationElementData1D(getID(), xoff, mSelectedLOD,
+ mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
component_number, data, data.length);
}
@@ -527,7 +535,7 @@
public void copy1DRangeFromUnchecked(int off, int count, int[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
* Copy part of an allocation from an array. This variant is
@@ -541,7 +549,7 @@
public void copy1DRangeFromUnchecked(int off, int count, short[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 2, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
* Copy part of an allocation from an array. This variant is
@@ -555,7 +563,7 @@
public void copy1DRangeFromUnchecked(int off, int count, byte[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
* Copy part of an allocation from an array. This variant is
@@ -569,7 +577,7 @@
public void copy1DRangeFromUnchecked(int off, int count, float[] d) {
int dataSize = mType.mElement.getSizeBytes() * count;
data1DChecks(off, count, d.length * 4, dataSize);
- mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize);
+ mRS.nAllocationData1D(getIDSafe(), off, mSelectedLOD, count, d, dataSize);
}
/**
@@ -638,7 +646,7 @@
* be copied.
*/
public void copy1DRangeFrom(int off, int count, Allocation data, int dataOff) {
- mRS.nAllocationData2D(getID(), off, 0,
+ mRS.nAllocationData2D(getIDSafe(), off, 0,
mSelectedLOD, mSelectedFace.mID,
count, 1, data.getID(), dataOff, 0,
data.mSelectedLOD, data.mSelectedFace.mID);
@@ -674,28 +682,28 @@
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length * 2);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length * 4);
}
public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID,
w, h, data, data.length * 4);
}
@@ -715,7 +723,7 @@
Allocation data, int dataXoff, int dataYoff) {
mRS.validate();
validate2DRange(xoff, yoff, w, h);
- mRS.nAllocationData2D(getID(), xoff, yoff,
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff,
mSelectedLOD, mSelectedFace.mID,
w, h, data.getID(), dataXoff, dataYoff,
data.mSelectedLOD, data.mSelectedFace.mID);
@@ -734,10 +742,16 @@
mRS.validate();
validateBitmapFormat(data);
validate2DRange(xoff, yoff, data.getWidth(), data.getHeight());
- mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
+ mRS.nAllocationData2D(getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, data);
}
+ /**
+ * Copy from the Allocation into a Bitmap. The bitmap must
+ * match the dimensions of the Allocation.
+ *
+ * @param b The bitmap to be set from the Allocation.
+ */
public void copyTo(Bitmap b) {
mRS.validate();
validateBitmapFormat(b);
@@ -745,24 +759,52 @@
mRS.nAllocationCopyToBitmap(getID(), b);
}
+ /**
+ * Copy from the Allocation into a byte array. The array must
+ * be at least as large as the Allocation. The allocation must
+ * be of an 8 bit elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(byte[] d) {
validateIsInt8();
mRS.validate();
mRS.nAllocationRead(getID(), d);
}
+ /**
+ * Copy from the Allocation into a short array. The array must
+ * be at least as large as the Allocation. The allocation must
+ * be of an 16 bit elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(short[] d) {
validateIsInt16();
mRS.validate();
mRS.nAllocationRead(getID(), d);
}
+ /**
+ * Copy from the Allocation into a int array. The array must be
+ * at least as large as the Allocation. The allocation must be
+ * of an 32 bit elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(int[] d) {
validateIsInt32();
mRS.validate();
mRS.nAllocationRead(getID(), d);
}
+ /**
+ * Copy from the Allocation into a float array. The array must
+ * be at least as large as the Allocation. The allocation must
+ * be of an 32 bit float elemental type.
+ *
+ * @param d The array to be set from the Allocation.
+ */
public void copyTo(float[] d) {
validateIsFloat32();
mRS.validate();
diff --git a/graphics/java/android/renderscript/AllocationAdapter.java b/graphics/java/android/renderscript/AllocationAdapter.java
index ca5246a..d38f2df 100644
--- a/graphics/java/android/renderscript/AllocationAdapter.java
+++ b/graphics/java/android/renderscript/AllocationAdapter.java
@@ -31,7 +31,8 @@
}
int getID() {
- return mAdaptedAllocation.getID();
+ throw new RSInvalidStateException(
+ "This operation is not supported with adapters at this time.");
}
/**
diff --git a/graphics/java/com/android/internal/graphics/NativeUtils.java b/graphics/java/com/android/internal/graphics/NativeUtils.java
deleted file mode 100644
index c91b7d9..0000000
--- a/graphics/java/com/android/internal/graphics/NativeUtils.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.graphics;
-
-import android.graphics.Canvas;
-import android.graphics.Rect;
-
-public final class NativeUtils {
- /**
- * This class is uninstantiable.
- */
- private NativeUtils() {
- // This space intentionally left blank.
- }
-
- /**
- * Scroll a rectangular portion of a canvas.
- *
- * @param canvas the canvas to manipulate
- * @param src the source rectangle
- * @param dx horizontal offset
- * @param dy vertical offset
- */
- public static native boolean nativeScrollRect(Canvas canvas, Rect src,
- int dx, int dy);
-}
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
index 084f54a..652189f 100644
--- a/graphics/jni/Android.mk
+++ b/graphics/jni/Android.mk
@@ -1,10 +1,3 @@
-
-# libRS needs libacc, which isn't 64-bit clean, and so can't be built
-# for the simulator on gHardy, and therefore libRS needs to be excluded
-# from the simulator as well, and so in turn librs_jni needs to be
-# excluded.
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -41,5 +34,3 @@
LOCAL_REQUIRED_MODULES := libRS
include $(BUILD_SHARED_LIBRARY)
-
-endif #simulator
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index feeb3c3..9725822 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -39,8 +39,6 @@
public:
static sp<ProcessState> self();
- static void setSingleProcess(bool singleProcess);
-
void setContextObject(const sp<IBinder>& object);
sp<IBinder> getContextObject(const sp<IBinder>& caller);
@@ -48,8 +46,6 @@
const String16& name);
sp<IBinder> getContextObject(const String16& name,
const sp<IBinder>& caller);
-
- bool supportsProcesses() const;
void startThreadPool();
diff --git a/include/cpustats/CentralTendencyStatistics.h b/include/cpustats/CentralTendencyStatistics.h
new file mode 100644
index 0000000..21b6981
--- /dev/null
+++ b/include/cpustats/CentralTendencyStatistics.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef _CENTRAL_TENDENCY_STATISTICS_H
+#define _CENTRAL_TENDENCY_STATISTICS_H
+
+#include <math.h>
+
+// Not multithread safe
+class CentralTendencyStatistics {
+
+public:
+
+ CentralTendencyStatistics() :
+ mMean(NAN), mMedian(NAN), mMinimum(INFINITY), mMaximum(-INFINITY), mN(0), mM2(0),
+ mVariance(NAN), mVarianceKnownForN(0), mStddev(NAN), mStddevKnownForN(0) { }
+
+ ~CentralTendencyStatistics() { }
+
+ // add x to the set of samples
+ void sample(double x);
+
+ // return the arithmetic mean of all samples so far
+ double mean() const { return mMean; }
+
+ // return the minimum of all samples so far
+ double minimum() const { return mMinimum; }
+
+ // return the maximum of all samples so far
+ double maximum() const { return mMaximum; }
+
+ // return the variance of all samples so far
+ double variance() const;
+
+ // return the standard deviation of all samples so far
+ double stddev() const;
+
+ // return the number of samples added so far
+ unsigned n() const { return mN; }
+
+ // reset the set of samples to be empty
+ void reset();
+
+private:
+ double mMean;
+ double mMedian;
+ double mMinimum;
+ double mMaximum;
+ unsigned mN; // number of samples so far
+ double mM2;
+
+ // cached variance, and n at time of caching
+ mutable double mVariance;
+ mutable unsigned mVarianceKnownForN;
+
+ // cached standard deviation, and n at time of caching
+ mutable double mStddev;
+ mutable unsigned mStddevKnownForN;
+
+};
+
+#endif // _CENTRAL_TENDENCY_STATISTICS_H
diff --git a/include/cpustats/README.txt b/include/cpustats/README.txt
new file mode 100644
index 0000000..14439f0
--- /dev/null
+++ b/include/cpustats/README.txt
@@ -0,0 +1,6 @@
+This is a static library of CPU usage statistics, originally written
+for audio but most are not actually specific to audio.
+
+Requirements to be here:
+ * should be related to CPU usage statistics
+ * should be portable to host; avoid Android OS dependencies without a conditional
diff --git a/include/cpustats/ThreadCpuUsage.h b/include/cpustats/ThreadCpuUsage.h
new file mode 100644
index 0000000..24012a4
--- /dev/null
+++ b/include/cpustats/ThreadCpuUsage.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef _THREAD_CPU_USAGE_H
+#define _THREAD_CPU_USAGE_H
+
+#include <cpustats/CentralTendencyStatistics.h>
+
+// Track CPU usage for the current thread, and maintain statistics on
+// the CPU usage. Units are in per-thread CPU ns, as reported by
+// clock_gettime(CLOCK_THREAD_CPUTIME_ID). Simple usage: for cyclic
+// threads where you want to measure the execution time of the whole
+// cycle, just call sampleAndEnable() at the start of each cycle.
+// Then call statistics() to get the results, and resetStatistics()
+// to start a new set of measurements.
+// For acyclic threads, or for cyclic threads where you want to measure
+// only part of each cycle, call enable(), disable(), and/or setEnabled()
+// to demarcate the region(s) of interest, and then call sample() periodically.
+// This class is not thread-safe for concurrent calls from multiple threads;
+// the methods of this class may only be called by the current thread
+// which constructed the object.
+
+class ThreadCpuUsage
+{
+
+public:
+ ThreadCpuUsage() :
+ mIsEnabled(false),
+ mWasEverEnabled(false),
+ mAccumulator(0),
+ // mPreviousTs
+ // mMonotonicTs
+ mMonotonicKnown(false)
+ // mStatistics
+ { }
+
+ ~ThreadCpuUsage() { }
+
+ // Return whether currently tracking CPU usage by current thread
+ bool isEnabled() { return mIsEnabled; }
+
+ // Enable tracking of CPU usage by current thread;
+ // any CPU used from this point forward will be tracked.
+ // Returns the previous enabled status.
+ bool enable() { return setEnabled(true); }
+
+ // Disable tracking of CPU usage by current thread;
+ // any CPU used from this point forward will be ignored.
+ // Returns the previous enabled status.
+ bool disable() { return setEnabled(false); }
+
+ // Set the enabled status and return the previous enabled status.
+ // This method is intended to be used for safe nested enable/disabling.
+ bool setEnabled(bool isEnabled);
+
+ // Add a sample point for central tendency statistics, and also
+ // enable tracking if needed. If tracking has never been enabled, then
+ // enables tracking but does not add a sample (it is not possible to add
+ // a sample the first time because no previous). Otherwise if tracking is
+ // enabled, then adds a sample for tracked CPU ns since the previous
+ // sample, or since the first call to sampleAndEnable(), enable(), or
+ // setEnabled(true). If there was a previous sample but tracking is
+ // now disabled, then adds a sample for the tracked CPU ns accumulated
+ // up until the most recent disable(), resets this accumulator, and then
+ // enables tracking. Calling this method rather than enable() followed
+ // by sample() avoids a race condition for the first sample.
+ void sampleAndEnable();
+
+ // Add a sample point for central tendency statistics, but do not
+ // change the tracking enabled status. If tracking has either never been
+ // enabled, or has never been enabled since the last sample, then log a warning
+ // and don't add sample. Otherwise, adds a sample for tracked CPU ns since
+ // the previous sample or since the first call to sampleAndEnable(),
+ // enable(), or setEnabled(true) if no previous sample.
+ void sample();
+
+ // Return the elapsed delta wall clock ns since initial enable or statistics reset,
+ // as reported by clock_gettime(CLOCK_MONOTONIC).
+ long long elapsed() const;
+
+ // Reset statistics and elapsed. Has no effect on tracking or accumulator.
+ void resetStatistics();
+
+ // Return a const reference to the central tendency statistics.
+ // Note that only the const methods can be called on this object.
+ const CentralTendencyStatistics& statistics() const {
+ return mStatistics;
+ }
+
+private:
+ bool mIsEnabled; // whether tracking is currently enabled
+ bool mWasEverEnabled; // whether tracking was ever enabled
+ long long mAccumulator; // accumulated thread CPU time since last sample, in ns
+ struct timespec mPreviousTs; // most recent thread CPU time, valid only if mIsEnabled is true
+ struct timespec mMonotonicTs; // most recent monotonic time
+ bool mMonotonicKnown; // whether mMonotonicTs has been set
+ CentralTendencyStatistics mStatistics;
+};
+
+#endif // _THREAD_CPU_USAGE_H
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 83482ea..cfe2aa1 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -21,6 +21,7 @@
#include <gui/SurfaceTexture.h>
#include <ui/egl/android_natives.h>
+#include <ui/Region.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -37,57 +38,67 @@
sp<ISurfaceTexture> getISurfaceTexture() const;
-private:
- friend class Surface;
+protected:
+ SurfaceTextureClient();
+ void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
+private:
// can't be copied
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
SurfaceTextureClient(const SurfaceTextureClient& rhs);
+ void init();
// ANativeWindow hooks
- static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int perform(ANativeWindow* window, int operation, ...);
- static int query(const ANativeWindow* window, int what, int* value);
- static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int setSwapInterval(ANativeWindow* window, int interval);
-
- int cancelBuffer(ANativeWindowBuffer* buffer);
- int dequeueBuffer(ANativeWindowBuffer** buffer);
- int lockBuffer(ANativeWindowBuffer* buffer);
- int perform(int operation, va_list args);
- int query(int what, int* value) const;
- int queueBuffer(ANativeWindowBuffer* buffer);
- int setSwapInterval(int interval);
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+ static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_perform(ANativeWindow* window, int operation, ...);
+ static int hook_query(const ANativeWindow* window, int what, int* value);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_setSwapInterval(ANativeWindow* window, int interval);
int dispatchConnect(va_list args);
int dispatchDisconnect(va_list args);
int dispatchSetBufferCount(va_list args);
int dispatchSetBuffersGeometry(va_list args);
+ int dispatchSetBuffersDimensions(va_list args);
+ int dispatchSetBuffersFormat(va_list args);
int dispatchSetBuffersTransform(va_list args);
int dispatchSetBuffersTimestamp(va_list args);
int dispatchSetCrop(va_list args);
int dispatchSetUsage(va_list args);
+ int dispatchLock(va_list args);
+ int dispatchUnlockAndPost(va_list args);
- int connect(int api);
- int disconnect(int api);
- int setBufferCount(int bufferCount);
- int setBuffersGeometry(int w, int h, int format);
- int setBuffersTransform(int transform);
- int setBuffersTimestamp(int64_t timestamp);
- int setCrop(Rect const* rect);
- int setUsage(uint32_t reqUsage);
+protected:
+ virtual int cancelBuffer(ANativeWindowBuffer* buffer);
+ virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
+ virtual int lockBuffer(ANativeWindowBuffer* buffer);
+ virtual int perform(int operation, va_list args);
+ virtual int query(int what, int* value) const;
+ virtual int queueBuffer(ANativeWindowBuffer* buffer);
+ virtual int setSwapInterval(int interval);
- void freeAllBuffers();
- int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
-
- int getConnectedApi() const;
+ virtual int connect(int api);
+ virtual int disconnect(int api);
+ virtual int setBufferCount(int bufferCount);
+ virtual int setBuffersDimensions(int w, int h);
+ virtual int setBuffersFormat(int format);
+ virtual int setBuffersTransform(int transform);
+ virtual int setBuffersTimestamp(int64_t timestamp);
+ virtual int setCrop(Rect const* rect);
+ virtual int setUsage(uint32_t reqUsage);
+ virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
+ virtual int unlockAndPost();
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+private:
+ void freeAllBuffers();
+ int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
// mSurfaceTexture is the interface to the surface texture server. All
// operations on the surface texture client ultimately translate into
// interactions with the server using this interface.
@@ -142,6 +153,12 @@
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
mutable Mutex mMutex;
+
+ // must be used from the lock/unlock thread
+ sp<GraphicBuffer> mLockedBuffer;
+ sp<GraphicBuffer> mPostedBuffer;
+ mutable Region mOldDirtyRegion;
+ bool mConnectedToCpu;
};
}; // namespace android
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 3c65147..02ad703 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -184,6 +184,11 @@
uint32_t flags = 0);
};
+struct CodecProfileLevel {
+ OMX_U32 mProfile;
+ OMX_U32 mLevel;
+};
+
} // namespace android
#endif // ANDROID_IOMX_H_
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index d310cee..cc63356 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -51,6 +51,17 @@
// will be suppressed until media time reaches this timestamp.
static const char *const kKeyResumeAtPTS;
+ // When signalling a discontinuity you can optionally
+ // signal that this is a "hard" discontinuity, i.e. the format
+ // or configuration of subsequent stream data differs from that
+ // currently active. To do so, include a non-zero int32_t value
+ // under the key "kKeyFormatChange" when issuing the DISCONTINUITY
+ // command.
+ // The new logical stream must start with proper codec initialization
+ // information for playback to continue, i.e. SPS and PPS in the case
+ // of AVC video etc.
+ static const char *const kKeyFormatChange;
+
virtual void issueCommand(
Command cmd, bool synchronous, const sp<AMessage> &msg = NULL) = 0;
};
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 80b7c1c..8c1c593 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -197,6 +197,12 @@
status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId, Size videoSize, int32_t frameRate,
bool storeMetaDataInVideoBuffers);
+
+ status_t initWithCameraAccess(
+ const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId, Size videoSize, int32_t frameRate,
+ bool storeMetaDataInVideoBuffers);
+
status_t isCameraAvailable(const sp<ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId);
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 904ce2a..77166ed 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -71,7 +71,8 @@
bool mUse32BitOffset;
bool mIsFileSizeLimitExplicitlyRequested;
bool mPaused;
- bool mStarted;
+ bool mStarted; // Writer thread + track threads started successfully
+ bool mWriterThreadStarted; // Only writer thread started successfully
off64_t mOffset;
off_t mMdatOffset;
uint8_t *mMoovBoxBuffer;
@@ -182,6 +183,7 @@
void writeLatitude(int degreex10000);
void writeLongitude(int degreex10000);
void sendSessionSummary();
+ void release();
MPEG4Writer(const MPEG4Writer &);
MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/include/media/stagefright/MetadataBufferType.h b/include/media/stagefright/MetadataBufferType.h
index 275c19f..52a3257 100644
--- a/include/media/stagefright/MetadataBufferType.h
+++ b/include/media/stagefright/MetadataBufferType.h
@@ -17,7 +17,11 @@
#ifndef METADATA_BUFFER_TYPE_H
#define METADATA_BUFFER_TYPE_H
+#ifdef __cplusplus
+extern "C" {
namespace android {
+#endif
+
/*
* MetadataBufferType defines the type of the metadata buffers that
* can be passed to video encoder component for encoding, via Stagefright
@@ -72,6 +76,9 @@
} MetadataBufferType;
+#ifdef __cplusplus
} // namespace android
+}
+#endif
#endif // METADATA_BUFFER_TYPE_H
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7f3c497..20fcde5 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -336,11 +336,6 @@
OMXCodec &operator=(const OMXCodec &);
};
-struct CodecProfileLevel {
- OMX_U32 mProfile;
- OMX_U32 mLevel;
-};
-
struct CodecCapabilities {
String8 mComponentName;
Vector<CodecProfileLevel> mProfileLevels;
@@ -360,7 +355,7 @@
status_t QueryCodecs(
const sp<IOMX> &omx,
- const char *mimeType, bool queryDecoders,
+ const char *mimeType, bool queryDecoders, bool hwCodecOnly,
Vector<CodecCapabilities> *results);
} // namespace android
diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h
deleted file mode 100644
index bc67156..0000000
--- a/include/media/stagefright/ShoutcastSource.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef SHOUTCAST_SOURCE_H_
-
-#define SHOUTCAST_SOURCE_H_
-
-#include <sys/types.h>
-
-#include <media/stagefright/MediaSource.h>
-
-namespace android {
-
-class HTTPStream;
-class MediaBufferGroup;
-
-class ShoutcastSource : public MediaSource {
-public:
- // Assumes ownership of "http".
- ShoutcastSource(HTTPStream *http);
-
- virtual status_t start(MetaData *params = NULL);
- virtual status_t stop();
-
- virtual sp<MetaData> getFormat();
-
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options = NULL);
-
-protected:
- virtual ~ShoutcastSource();
-
-private:
- HTTPStream *mHttp;
- size_t mMetaDataOffset;
- size_t mBytesUntilMetaData;
-
- MediaBufferGroup *mGroup;
- bool mStarted;
-
- ShoutcastSource(const ShoutcastSource &);
- ShoutcastSource &operator= (const ShoutcastSource &);
-};
-
-} // namespace android
-
-#endif // SHOUTCAST_SOURCE_H_
-
diff --git a/include/private/binder/binder_module.h b/include/private/binder/binder_module.h
index fdf327e..a8dd64f 100644
--- a/include/private/binder/binder_module.h
+++ b/include/private/binder/binder_module.h
@@ -21,126 +21,11 @@
namespace android {
#endif
-#if defined(HAVE_ANDROID_OS)
-
/* obtain structures and constants from the kernel header */
#include <sys/ioctl.h>
#include <linux/binder.h>
-#else
-
-/* Some parts of the simulator need fake versions of this
- * stuff in order to compile. Really this should go away
- * entirely...
- */
-
-#define BINDER_CURRENT_PROTOCOL_VERSION 7
-
-#define BINDER_TYPE_BINDER 1
-#define BINDER_TYPE_WEAK_BINDER 2
-#define BINDER_TYPE_HANDLE 3
-#define BINDER_TYPE_WEAK_HANDLE 4
-#define BINDER_TYPE_FD 5
-
-struct flat_binder_object {
- unsigned long type;
- unsigned long flags;
- union {
- void *binder;
- signed long handle;
- };
- void *cookie;
-};
-
-struct binder_write_read {
- signed long write_size;
- signed long write_consumed;
- unsigned long write_buffer;
- signed long read_size;
- signed long read_consumed;
- unsigned long read_buffer;
-};
-
-struct binder_transaction_data {
- union {
- size_t handle;
- void *ptr;
- } target;
- void *cookie;
- unsigned int code;
-
- unsigned int flags;
- pid_t sender_pid;
- uid_t sender_euid;
- size_t data_size;
- size_t offsets_size;
-
- union {
- struct {
- const void *buffer;
- const void *offsets;
- } ptr;
- uint8_t buf[8];
- } data;
-};
-
-enum transaction_flags {
- TF_ONE_WAY = 0x01,
- TF_ROOT_OBJECT = 0x04,
- TF_STATUS_CODE = 0x08,
- TF_ACCEPT_FDS = 0x10,
-};
-
-
-enum {
- FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
- FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
-};
-
-enum BinderDriverReturnProtocol {
- BR_ERROR,
- BR_OK,
- BR_TRANSACTION,
- BR_REPLY,
- BR_ACQUIRE_RESULT,
- BR_DEAD_REPLY,
- BR_TRANSACTION_COMPLETE,
- BR_INCREFS,
- BR_ACQUIRE,
- BR_RELEASE,
- BR_DECREFS,
- BR_ATTEMPT_ACQUIRE,
- BR_NOOP,
- BR_SPAWN_LOOPER,
- BR_FINISHED,
- BR_DEAD_BINDER,
- BR_CLEAR_DEATH_NOTIFICATION_DONE,
- BR_FAILED_REPLY,
-};
-
-enum BinderDriverCommandProtocol {
- BC_TRANSACTION,
- BC_REPLY,
- BC_ACQUIRE_RESULT,
- BC_FREE_BUFFER,
- BC_INCREFS,
- BC_ACQUIRE,
- BC_RELEASE,
- BC_DECREFS,
- BC_INCREFS_DONE,
- BC_ACQUIRE_DONE,
- BC_ATTEMPT_ACQUIRE,
- BC_REGISTER_LOOPER,
- BC_ENTER_LOOPER,
- BC_EXIT_LOOPER,
- BC_REQUEST_DEATH_NOTIFICATION,
- BC_CLEAR_DEATH_NOTIFICATION,
- BC_DEAD_BINDER_DONE,
-};
-
-#endif
-
#ifdef __cplusplus
} // namespace android
#endif
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index dc2a845..c2a494d 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -28,6 +28,8 @@
#include <ui/Region.h>
#include <ui/egl/android_natives.h>
+#include <gui/SurfaceTextureClient.h>
+
#include <surfaceflinger/ISurface.h>
#include <surfaceflinger/ISurfaceComposerClient.h>
@@ -37,14 +39,9 @@
// ---------------------------------------------------------------------------
-class GraphicBuffer;
-class GraphicBufferMapper;
-class IOMX;
class ISurfaceTexture;
-class Rect;
class Surface;
class SurfaceComposerClient;
-class SurfaceTextureClient;
// ---------------------------------------------------------------------------
@@ -129,8 +126,7 @@
// ---------------------------------------------------------------------------
-class Surface
- : public EGLNativeBase<ANativeWindow, Surface, RefBase>
+class Surface : public SurfaceTextureClient
{
public:
struct SurfaceInfo {
@@ -158,32 +154,14 @@
sp<ISurfaceTexture> getSurfaceTexture();
// the lock/unlock APIs must be used from the same thread
- status_t lock(SurfaceInfo* info, bool blocking = true);
- status_t lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
+ status_t lock(SurfaceInfo* info, Region* dirty = NULL);
status_t unlockAndPost();
sp<IBinder> asBinder() const;
private:
- /*
- * Android frameworks friends
- * (eventually this should go away and be replaced by proper APIs)
- */
- // camera and camcorder need access to the ISurface binder interface for preview
- friend class CameraService;
- friend class MediaRecorder;
- // MediaPlayer needs access to ISurface for display
- friend class MediaPlayer;
- friend class IOMX;
- friend class SoftwareRenderer;
// this is just to be able to write some unit tests
friend class Test;
- // videoEditor preview classes
- friend class VideoEditorPreviewController;
- friend class PreviewRenderer;
-
-private:
- friend class SurfaceComposerClient;
friend class SurfaceControl;
// can't be copied
@@ -194,62 +172,27 @@
Surface(const Parcel& data, const sp<IBinder>& ref);
~Surface();
-
- /*
- * ANativeWindow hooks
- */
- static int setSwapInterval(ANativeWindow* window, int interval);
- static int dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int query(const ANativeWindow* window, int what, int* value);
- static int perform(ANativeWindow* window, int operation, ...);
-
- int setSwapInterval(int interval);
- int dequeueBuffer(ANativeWindowBuffer** buffer);
- int lockBuffer(ANativeWindowBuffer* buffer);
- int queueBuffer(ANativeWindowBuffer* buffer);
- int cancelBuffer(ANativeWindowBuffer* buffer);
- int query(int what, int* value) const;
- int perform(int operation, va_list args);
-
/*
* private stuff...
*/
void init();
status_t validate(bool inCancelBuffer = false) const;
- int getConnectedApi() const;
-
static void cleanCachedSurfacesLocked();
+ virtual int query(int what, int* value) const;
+
// constants
status_t mInitCheck;
sp<ISurface> mSurface;
- sp<SurfaceTextureClient> mSurfaceTextureClient;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;
-
- // protected by mSurfaceLock. These are also used from lock/unlock
- // but in that case, they must be called form the same thread.
- mutable Region mDirtyRegion;
-
- // must be used from the lock/unlock thread
- sp<GraphicBuffer> mLockedBuffer;
- sp<GraphicBuffer> mPostedBuffer;
- mutable Region mOldDirtyRegion;
- bool mReserved;
// query() must be called from dequeueBuffer() thread
uint32_t mWidth;
uint32_t mHeight;
- // Inherently thread-safe
- mutable Mutex mSurfaceLock;
- mutable Mutex mApiLock;
-
// A cache of Surface objects that have been deserialized into this process.
static Mutex sCachedSurfacesLock;
static DefaultKeyedVector<wp<IBinder>, wp<Surface> > sCachedSurfaces;
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 23ffd59..f38f6ce 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -23,8 +23,8 @@
*/
interface IKeyChainService {
// APIs used by KeyChain
- byte[] getPrivateKey(String alias, String authToken);
- byte[] getCertificate(String alias, String authToken);
+ byte[] getPrivateKey(String alias);
+ byte[] getCertificate(String alias);
// APIs used by CertInstaller
void installCaCertificate(in byte[] caCertificate);
@@ -32,4 +32,8 @@
// APIs used by Settings
boolean deleteCaCertificate(String alias);
boolean reset();
+
+ // APIs used by KeyChainActivity
+ void setGrant(int uid, String alias, boolean value);
+ boolean hasGrant(int uid, String alias);
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 6229331..db6388a 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -15,36 +15,25 @@
*/
package android.security;
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
import java.io.IOException;
-import java.security.KeyFactory;
import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
@@ -266,7 +255,7 @@
throw new NullPointerException("response == null");
}
Intent intent = new Intent(ACTION_CHOOSER);
- intent.putExtra(EXTRA_RESPONSE, new AliasResponse(activity, response));
+ intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response));
intent.putExtra(EXTRA_HOST, host);
intent.putExtra(EXTRA_PORT, port);
intent.putExtra(EXTRA_ALIAS, alias);
@@ -276,56 +265,12 @@
}
private static class AliasResponse extends IKeyChainAliasCallback.Stub {
- private final Activity activity;
private final KeyChainAliasCallback keyChainAliasResponse;
- private AliasResponse(Activity activity, KeyChainAliasCallback keyChainAliasResponse) {
- this.activity = activity;
+ private AliasResponse(KeyChainAliasCallback keyChainAliasResponse) {
this.keyChainAliasResponse = keyChainAliasResponse;
}
@Override public void alias(String alias) {
- if (alias == null) {
- keyChainAliasResponse.alias(null);
- return;
- }
- AccountManager accountManager = AccountManager.get(activity);
- accountManager.getAuthToken(getAccount(activity),
- alias,
- null,
- activity,
- new AliasAccountManagerCallback(keyChainAliasResponse,
- alias),
- null);
- }
- }
-
- private static class AliasAccountManagerCallback implements AccountManagerCallback<Bundle> {
- private final KeyChainAliasCallback keyChainAliasResponse;
- private final String alias;
- private AliasAccountManagerCallback(KeyChainAliasCallback keyChainAliasResponse,
- String alias) {
- this.keyChainAliasResponse = keyChainAliasResponse;
- this.alias = alias;
- }
- @Override public void run(AccountManagerFuture<Bundle> future) {
- Bundle bundle;
- try {
- bundle = future.getResult();
- } catch (OperationCanceledException e) {
- keyChainAliasResponse.alias(null);
- return;
- } catch (IOException e) {
- keyChainAliasResponse.alias(null);
- return;
- } catch (AuthenticatorException e) {
- keyChainAliasResponse.alias(null);
- return;
- }
- String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
- if (authToken != null) {
- keyChainAliasResponse.alias(alias);
- } else {
- keyChainAliasResponse.alias(null);
- }
+ keyChainAliasResponse.alias(alias);
}
}
@@ -347,12 +292,8 @@
}
KeyChainConnection keyChainConnection = bind(context);
try {
- String authToken = authToken(context, alias);
- if (authToken == null) {
- return null;
- }
IKeyChainService keyChainService = keyChainConnection.getService();
- byte[] privateKeyBytes = keyChainService.getPrivateKey(alias, authToken);
+ byte[] privateKeyBytes = keyChainService.getPrivateKey(alias);
return toPrivateKey(privateKeyBytes);
} catch (RemoteException e) {
throw new KeyChainException(e);
@@ -382,12 +323,8 @@
}
KeyChainConnection keyChainConnection = bind(context);
try {
- String authToken = authToken(context, alias);
- if (authToken == null) {
- return null;
- }
IKeyChainService keyChainService = keyChainConnection.getService();
- byte[] certificateBytes = keyChainService.getCertificate(alias, authToken);
+ byte[] certificateBytes = keyChainService.getCertificate(alias);
List<X509Certificate> chain = new ArrayList<X509Certificate>();
chain.add(toCertificate(certificateBytes));
TrustedCertificateStore store = new TrustedCertificateStore();
@@ -438,50 +375,6 @@
}
}
- private static String authToken(Context context, String alias) {
- AccountManager accountManager = AccountManager.get(context);
- AccountManagerFuture<Bundle> future = accountManager.getAuthToken(getAccount(context),
- alias,
- false,
- null,
- null);
- Bundle bundle;
- try {
- bundle = future.getResult();
- } catch (OperationCanceledException e) {
- throw new AssertionError(e);
- } catch (IOException e) {
- // KeyChainAccountAuthenticator doesn't do I/O
- throw new AssertionError(e);
- } catch (AuthenticatorException e) {
- throw new AssertionError(e);
- }
- Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
- if (intent != null) {
- return null;
- }
- String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
- if (authToken == null) {
- throw new AssertionError("Invalid authtoken");
- }
- return authToken;
- }
-
- private static Account getAccount(Context context) {
- AccountManager accountManager = AccountManager.get(context);
- Account[] accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
- if (accounts.length == 0) {
- try {
- // Account is created if necessary during binding of the IKeyChainService
- bind(context).close();
- } catch (InterruptedException e) {
- throw new AssertionError(e);
- }
- accounts = accountManager.getAccountsByType(ACCOUNT_TYPE);
- }
- return accounts[0];
- }
-
/**
* @hide for reuse by CertInstaller and Settings.
* @see KeyChain#bind
@@ -517,11 +410,15 @@
ensureNotOnMainThread(context);
final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1);
ServiceConnection keyChainServiceConnection = new ServiceConnection() {
+ volatile boolean mConnectedAtLeastOnce = false;
@Override public void onServiceConnected(ComponentName name, IBinder service) {
- try {
- q.put(IKeyChainService.Stub.asInterface(service));
- } catch (InterruptedException e) {
- throw new AssertionError(e);
+ if (!mConnectedAtLeastOnce) {
+ mConnectedAtLeastOnce = true;
+ try {
+ q.put(IKeyChainService.Stub.asInterface(service));
+ } catch (InterruptedException e) {
+ // will never happen, since the queue starts with one available slot
+ }
}
}
@Override public void onServiceDisconnected(ComponentName name) {}
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 2d4e10d..f5288c8 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -43,8 +43,6 @@
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
-static bool gSingleProcess = false;
-
// ---------------------------------------------------------------------------
@@ -82,12 +80,6 @@
return gProcess;
}
-void ProcessState::setSingleProcess(bool singleProcess)
-{
- gSingleProcess = singleProcess;
-}
-
-
void ProcessState::setContextObject(const sp<IBinder>& object)
{
setContextObject(object, String16("default"));
@@ -95,11 +87,7 @@
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
- if (supportsProcesses()) {
- return getStrongProxyForHandle(0);
- } else {
- return getContextObject(String16("default"), caller);
- }
+ return getStrongProxyForHandle(0);
}
void ProcessState::setContextObject(const sp<IBinder>& object, const String16& name)
@@ -144,11 +132,6 @@
return object;
}
-bool ProcessState::supportsProcesses() const
-{
- return mDriverFD >= 0;
-}
-
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
@@ -169,24 +152,15 @@
AutoMutex _l(mLock);
mBinderContextCheckFunc = checkFunc;
mBinderContextUserData = userData;
- if (mDriverFD >= 0) {
- int dummy = 0;
-#if defined(HAVE_ANDROID_OS)
- status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
-#else
- status_t result = INVALID_OPERATION;
-#endif
- if (result == 0) {
- mManagesContexts = true;
- } else if (result == -1) {
- mBinderContextCheckFunc = NULL;
- mBinderContextUserData = NULL;
- LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
- }
- } else {
- // If there is no driver, our only world is the local
- // process so we can always become the context manager there.
+
+ int dummy = 0;
+ status_t result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &dummy);
+ if (result == 0) {
mManagesContexts = true;
+ } else if (result == -1) {
+ mBinderContextCheckFunc = NULL;
+ mBinderContextUserData = NULL;
+ LOGE("Binder ioctl to become context manager failed: %s\n", strerror(errno));
}
}
return mManagesContexts;
@@ -322,20 +296,11 @@
static int open_driver()
{
- if (gSingleProcess) {
- return -1;
- }
-
int fd = open("/dev/binder", O_RDWR);
if (fd >= 0) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
int vers;
-#if defined(HAVE_ANDROID_OS)
status_t result = ioctl(fd, BINDER_VERSION, &vers);
-#else
- status_t result = -1;
- errno = EPERM;
-#endif
if (result == -1) {
LOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
@@ -346,14 +311,11 @@
close(fd);
fd = -1;
}
-#if defined(HAVE_ANDROID_OS)
size_t maxThreads = 15;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
LOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
-#endif
-
} else {
LOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
}
@@ -386,9 +348,8 @@
mDriverFD = -1;
#endif
}
- if (mDriverFD < 0) {
- // Need to run without the driver, starting our own thread pool.
- }
+
+ LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
ProcessState::~ProcessState()
diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk
index dc00957..7286f92 100644
--- a/libs/camera/Android.mk
+++ b/libs/camera/Android.mk
@@ -20,8 +20,4 @@
LOCAL_MODULE:= libcamera_client
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -lpthread
-endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/cpustats/Android.mk b/libs/cpustats/Android.mk
new file mode 100644
index 0000000..21bacbb
--- /dev/null
+++ b/libs/cpustats/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ CentralTendencyStatistics.cpp \
+ ThreadCpuUsage.cpp
+
+LOCAL_MODULE := libcpustats
+
+include $(BUILD_STATIC_LIBRARY)
+
+#include $(CLEAR_VARS)
+#
+#LOCAL_SRC_FILES := \
+# CentralTendencyStatistics.cpp \
+# ThreadCpuUsage.cpp
+#
+#LOCAL_MODULE := libcpustats
+#
+#include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libs/cpustats/CentralTendencyStatistics.cpp b/libs/cpustats/CentralTendencyStatistics.cpp
new file mode 100644
index 0000000..42ab62b
--- /dev/null
+++ b/libs/cpustats/CentralTendencyStatistics.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 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 <stdlib.h>
+
+#include <cpustats/CentralTendencyStatistics.h>
+
+void CentralTendencyStatistics::sample(double x)
+{
+ // update min and max
+ if (x < mMinimum)
+ mMinimum = x;
+ if (x > mMaximum)
+ mMaximum = x;
+ // Knuth
+ if (mN == 0) {
+ mMean = 0;
+ }
+ ++mN;
+ double delta = x - mMean;
+ mMean += delta / mN;
+ mM2 += delta * (x - mMean);
+}
+
+void CentralTendencyStatistics::reset()
+{
+ mMean = NAN;
+ mMedian = NAN;
+ mMinimum = INFINITY;
+ mMaximum = -INFINITY;
+ mN = 0;
+ mM2 = 0;
+ mVariance = NAN;
+ mVarianceKnownForN = 0;
+ mStddev = NAN;
+ mStddevKnownForN = 0;
+}
+
+double CentralTendencyStatistics::variance() const
+{
+ double variance;
+ if (mVarianceKnownForN != mN) {
+ if (mN > 1) {
+ // double variance_n = M2/n;
+ variance = mM2 / (mN - 1);
+ } else {
+ variance = NAN;
+ }
+ mVariance = variance;
+ mVarianceKnownForN = mN;
+ } else {
+ variance = mVariance;
+ }
+ return variance;
+}
+
+double CentralTendencyStatistics::stddev() const
+{
+ double stddev;
+ if (mStddevKnownForN != mN) {
+ stddev = sqrt(variance());
+ mStddev = stddev;
+ mStddevKnownForN = mN;
+ } else {
+ stddev = mStddev;
+ }
+ return stddev;
+}
diff --git a/libs/cpustats/ThreadCpuUsage.cpp b/libs/cpustats/ThreadCpuUsage.cpp
new file mode 100644
index 0000000..4bfbdf3
--- /dev/null
+++ b/libs/cpustats/ThreadCpuUsage.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2011 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 <errno.h>
+#include <time.h>
+
+#include <utils/Log.h>
+
+#include <cpustats/ThreadCpuUsage.h>
+
+bool ThreadCpuUsage::setEnabled(bool isEnabled)
+{
+ bool wasEnabled = mIsEnabled;
+ // only do something if there is a change
+ if (isEnabled != wasEnabled) {
+ int rc;
+ // enabling
+ if (isEnabled) {
+ rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mPreviousTs);
+ if (rc) {
+ LOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+ isEnabled = false;
+ } else {
+ mWasEverEnabled = true;
+ // record wall clock time at first enable
+ if (!mMonotonicKnown) {
+ rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
+ if (rc) {
+ LOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+ } else {
+ mMonotonicKnown = true;
+ }
+ }
+ }
+ // disabling
+ } else {
+ struct timespec ts;
+ rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+ if (rc) {
+ LOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+ } else {
+ long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
+ (ts.tv_nsec - mPreviousTs.tv_nsec);
+ mAccumulator += delta;
+#if 0
+ mPreviousTs = ts;
+#endif
+ }
+ }
+ mIsEnabled = isEnabled;
+ }
+ return wasEnabled;
+}
+
+void ThreadCpuUsage::sampleAndEnable()
+{
+ bool wasEverEnabled = mWasEverEnabled;
+ if (enable()) {
+ // already enabled, so add a new sample relative to previous
+ sample();
+ } else if (wasEverEnabled) {
+ // was disabled, but add sample for accumulated time while enabled
+ mStatistics.sample((double) mAccumulator);
+ mAccumulator = 0;
+ }
+}
+
+void ThreadCpuUsage::sample()
+{
+ if (mWasEverEnabled) {
+ if (mIsEnabled) {
+ struct timespec ts;
+ int rc;
+ rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+ if (rc) {
+ LOGE("clock_gettime(CLOCK_THREAD_CPUTIME_ID) errno=%d", errno);
+ } else {
+ long long delta = (ts.tv_sec - mPreviousTs.tv_sec) * 1000000000LL +
+ (ts.tv_nsec - mPreviousTs.tv_nsec);
+ mAccumulator += delta;
+ mPreviousTs = ts;
+ }
+ } else {
+ mWasEverEnabled = false;
+ }
+ mStatistics.sample((double) mAccumulator);
+ mAccumulator = 0;
+ } else {
+ LOGW("Can't add sample because measurements have never been enabled");
+ }
+}
+
+long long ThreadCpuUsage::elapsed() const
+{
+ long long elapsed;
+ if (mMonotonicKnown) {
+ struct timespec ts;
+ int rc;
+ rc = clock_gettime(CLOCK_MONOTONIC, &ts);
+ if (rc) {
+ LOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+ elapsed = 0;
+ } else {
+ // mMonotonicTs is updated only at first enable and resetStatistics
+ elapsed = (ts.tv_sec - mMonotonicTs.tv_sec) * 1000000000LL +
+ (ts.tv_nsec - mMonotonicTs.tv_nsec);
+ }
+ } else {
+ LOGW("Can't compute elapsed time because measurements have never been enabled");
+ elapsed = 0;
+ }
+ return elapsed;
+}
+
+void ThreadCpuUsage::resetStatistics()
+{
+ mStatistics.reset();
+ if (mMonotonicKnown) {
+ int rc;
+ rc = clock_gettime(CLOCK_MONOTONIC, &mMonotonicTs);
+ if (rc) {
+ LOGE("clock_gettime(CLOCK_MONOTONIC) errno=%d", errno);
+ mMonotonicKnown = false;
+ }
+ }
+}
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 4070eba..ed319f5 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -32,10 +32,6 @@
LOCAL_MODULE:= libgui
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -lpthread
-endif
-
include $(BUILD_SHARED_LIBRARY)
ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index ec06bc0..41434a4 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -276,7 +276,7 @@
case DISCONNECT: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int api = data.readInt32();
- status_t res = connect(api);
+ status_t res = disconnect(api);
reply->writeInt32(res);
return NO_ERROR;
} break;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9185e1e..dabe643f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -46,59 +46,6 @@
namespace android {
-// ----------------------------------------------------------------------
-
-static status_t copyBlt(
- const sp<GraphicBuffer>& dst,
- const sp<GraphicBuffer>& src,
- const Region& reg)
-{
- // src and dst with, height and format must be identical. no verification
- // is done here.
- status_t err;
- uint8_t const * src_bits = NULL;
- err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
- LOGE_IF(err, "error locking src buffer %s", strerror(-err));
-
- uint8_t* dst_bits = NULL;
- err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
- LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
-
- Region::const_iterator head(reg.begin());
- Region::const_iterator tail(reg.end());
- if (head != tail && src_bits && dst_bits) {
- const size_t bpp = bytesPerPixel(src->format);
- const size_t dbpr = dst->stride * bpp;
- const size_t sbpr = src->stride * bpp;
-
- while (head != tail) {
- const Rect& r(*head++);
- ssize_t h = r.height();
- if (h <= 0) continue;
- size_t size = r.width() * bpp;
- uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
- uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
-
- if (src_bits)
- src->unlock();
-
- if (dst_bits)
- dst->unlock();
-
- return err;
-}
-
// ============================================================================
// SurfaceControl
// ============================================================================
@@ -277,7 +224,8 @@
// ---------------------------------------------------------------------------
Surface::Surface(const sp<SurfaceControl>& surface)
- : mInitCheck(NO_INIT),
+ : SurfaceTextureClient(),
+ mInitCheck(NO_INIT),
mSurface(surface->mSurface),
mIdentity(surface->mIdentity),
mFormat(surface->mFormat), mFlags(surface->mFlags),
@@ -287,7 +235,8 @@
}
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
- : mInitCheck(NO_INIT)
+ : SurfaceTextureClient(),
+ mInitCheck(NO_INIT)
{
mSurface = interface_cast<ISurface>(ref);
mIdentity = parcel.readInt32();
@@ -363,36 +312,21 @@
void Surface::init()
{
- ANativeWindow::setSwapInterval = setSwapInterval;
- ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::cancelBuffer = cancelBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
- ANativeWindow::queueBuffer = queueBuffer;
- ANativeWindow::query = query;
- ANativeWindow::perform = perform;
-
if (mSurface != NULL) {
sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
if (surfaceTexture != NULL) {
- mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
- mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+ setISurfaceTexture(surfaceTexture);
+ setUsage(GraphicBuffer::USAGE_HW_RENDER);
}
DisplayInfo dinfo;
SurfaceComposerClient::getDisplayInfo(0, &dinfo);
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
-
- const_cast<int&>(ANativeWindow::minSwapInterval) =
- mSurfaceTextureClient->minSwapInterval;
-
- const_cast<int&>(ANativeWindow::maxSwapInterval) =
- mSurfaceTextureClient->maxSwapInterval;
-
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
- if (mSurfaceTextureClient != 0) {
+ if (surfaceTexture != NULL) {
mInitCheck = NO_ERROR;
}
}
@@ -402,7 +336,6 @@
{
// clear all references and trigger an IPC now, to make sure things
// happen without delay, since these resources are quite heavy.
- mSurfaceTextureClient.clear();
mSurface.clear();
IPCThreadState::self()->flushCommands();
}
@@ -431,77 +364,6 @@
// ----------------------------------------------------------------------------
-int Surface::setSwapInterval(ANativeWindow* window, int interval) {
- Surface* self = getSelf(window);
- return self->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- Surface* self = getSelf(window);
- return self->dequeueBuffer(buffer);
-}
-
-int Surface::cancelBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- Surface* self = getSelf(window);
- return self->queueBuffer(buffer);
-}
-
-int Surface::query(const ANativeWindow* window,
- int what, int* value) {
- const Surface* self = getSelf(window);
- return self->query(what, value);
-}
-
-int Surface::perform(ANativeWindow* window,
- int operation, ...) {
- va_list args;
- va_start(args, operation);
- Surface* self = getSelf(window);
- int res = self->perform(operation, args);
- va_end(args);
- return res;
-}
-
-// ----------------------------------------------------------------------------
-
-int Surface::setSwapInterval(int interval) {
- return mSurfaceTextureClient->setSwapInterval(interval);
-}
-
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
- status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
- if (err == NO_ERROR) {
- mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
- }
- return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->cancelBuffer(buffer);
-}
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->lockBuffer(buffer);
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
- return mSurfaceTextureClient->queueBuffer(buffer);
-}
-
int Surface::query(int what, int* value) const {
switch (what) {
case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
@@ -509,141 +371,39 @@
*value = 1;
return NO_ERROR;
case NATIVE_WINDOW_CONCRETE_TYPE:
- // TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE;
return NO_ERROR;
}
- return mSurfaceTextureClient->query(what, value);
-}
-
-int Surface::perform(int operation, va_list args) {
- return mSurfaceTextureClient->perform(operation, args);
+ return SurfaceTextureClient::query(what, value);
}
// ----------------------------------------------------------------------------
-int Surface::getConnectedApi() const {
- return mSurfaceTextureClient->getConnectedApi();
-}
+status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn) {
+ ANativeWindow_Buffer outBuffer;
-// ----------------------------------------------------------------------------
-
-status_t Surface::lock(SurfaceInfo* info, bool blocking) {
- return Surface::lock(info, NULL, blocking);
-}
-
-status_t Surface::lock(SurfaceInfo* other, Region* dirtyIn, bool blocking)
-{
- if (getConnectedApi()) {
- LOGE("Surface::lock(%p) failed. Already connected to another API",
- (ANativeWindow*)this);
- CallStack stack;
- stack.update();
- stack.dump("");
- return INVALID_OPERATION;
+ ARect temp;
+ ARect* inOutDirtyBounds = NULL;
+ if (dirtyIn) {
+ temp = dirtyIn->getBounds();
+ inOutDirtyBounds = &temp;
}
- if (mApiLock.tryLock() != NO_ERROR) {
- LOGE("calling Surface::lock from different threads!");
- CallStack stack;
- stack.update();
- stack.dump("");
- return WOULD_BLOCK;
- }
+ status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
- /* Here we're holding mApiLock */
-
- if (mLockedBuffer != 0) {
- LOGE("Surface::lock failed, already locked");
- mApiLock.unlock();
- return INVALID_OPERATION;
- }
-
- // we're intending to do software rendering from this point
- mSurfaceTextureClient->setUsage(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
- ANativeWindowBuffer* out;
- status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
- LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
- sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
- err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
- LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
- backBuffer->handle, strerror(-err));
- if (err == NO_ERROR) {
- const Rect bounds(backBuffer->width, backBuffer->height);
- const Region boundsRegion(bounds);
- Region scratch(boundsRegion);
- Region& newDirtyRegion(dirtyIn ? *dirtyIn : scratch);
- newDirtyRegion &= boundsRegion;
-
- // figure out if we can copy the frontbuffer back
- const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
- const bool canCopyBack = (frontBuffer != 0 &&
- backBuffer->width == frontBuffer->width &&
- backBuffer->height == frontBuffer->height &&
- backBuffer->format == frontBuffer->format &&
- !(mFlags & ISurfaceComposer::eDestroyBackbuffer));
-
- // the dirty region we report to surfaceflinger is the one
- // given by the user (as opposed to the one *we* return to the
- // user).
- mDirtyRegion = newDirtyRegion;
-
- if (canCopyBack) {
- // copy the area that is invalid and not repainted this round
- const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
- if (!copyback.isEmpty())
- copyBlt(backBuffer, frontBuffer, copyback);
- } else {
- // if we can't copy-back anything, modify the user's dirty
- // region to make sure they redraw the whole buffer
- newDirtyRegion = boundsRegion;
- }
-
- // keep track of the are of the buffer that is "clean"
- // (ie: that will be redrawn)
- mOldDirtyRegion = newDirtyRegion;
-
- void* vaddr;
- status_t res = backBuffer->lock(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- newDirtyRegion.bounds(), &vaddr);
-
- LOGW_IF(res, "failed locking buffer (handle = %p)",
- backBuffer->handle);
-
- mLockedBuffer = backBuffer;
- other->w = backBuffer->width;
- other->h = backBuffer->height;
- other->s = backBuffer->stride;
- other->usage = backBuffer->usage;
- other->format = backBuffer->format;
- other->bits = vaddr;
- }
+ other->w = uint32_t(outBuffer.width);
+ other->h = uint32_t(outBuffer.height);
+ other->s = uint32_t(outBuffer.stride);
+ other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+ other->format = uint32_t(outBuffer.format);
+ other->bits = outBuffer.bits;
}
- mApiLock.unlock();
return err;
}
-
-status_t Surface::unlockAndPost()
-{
- if (mLockedBuffer == 0) {
- LOGE("Surface::unlockAndPost failed, no locked buffer");
- return INVALID_OPERATION;
- }
- status_t err = mLockedBuffer->unlock();
- LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
-
- err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
- LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
- mLockedBuffer->handle, strerror(-err));
-
- mPostedBuffer = mLockedBuffer;
- mLockedBuffer = 0;
- return err;
+status_t Surface::unlockAndPost() {
+ return SurfaceTextureClient::unlockAndPost();
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 1410481..a12d40a 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -495,7 +495,7 @@
}
status_t SurfaceTexture::connect(int api) {
- LOGV("SurfaceTexture::connect");
+ LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
int err = NO_ERROR;
switch (api) {
@@ -504,6 +504,8 @@
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi != NO_CONNECTED_API) {
+ LOGE("connect: already connected (cur=%d, req=%d)",
+ mConnectedApi, api);
err = -EINVAL;
} else {
mConnectedApi = api;
@@ -517,7 +519,7 @@
}
status_t SurfaceTexture::disconnect(int api) {
- LOGV("SurfaceTexture::disconnect");
+ LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
int err = NO_ERROR;
switch (api) {
@@ -528,6 +530,8 @@
if (mConnectedApi == api) {
mConnectedApi = NO_CONNECTED_API;
} else {
+ LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+ mConnectedApi, api);
err = -EINVAL;
}
break;
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 281f2ed..d5b7c89 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -24,24 +24,45 @@
namespace android {
SurfaceTextureClient::SurfaceTextureClient(
- const sp<ISurfaceTexture>& surfaceTexture):
- mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
- mReqHeight(0), mReqFormat(0), mReqUsage(0),
- mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO),
- mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
- mMutex() {
+ const sp<ISurfaceTexture>& surfaceTexture)
+{
+ SurfaceTextureClient::init();
+ SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
+}
+
+SurfaceTextureClient::SurfaceTextureClient() {
+ SurfaceTextureClient::init();
+}
+
+void SurfaceTextureClient::init() {
// Initialize the ANativeWindow function pointers.
- ANativeWindow::setSwapInterval = setSwapInterval;
- ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::cancelBuffer = cancelBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
- ANativeWindow::queueBuffer = queueBuffer;
- ANativeWindow::query = query;
- ANativeWindow::perform = perform;
+ ANativeWindow::setSwapInterval = hook_setSwapInterval;
+ ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
+ ANativeWindow::cancelBuffer = hook_cancelBuffer;
+ ANativeWindow::lockBuffer = hook_lockBuffer;
+ ANativeWindow::queueBuffer = hook_queueBuffer;
+ ANativeWindow::query = hook_query;
+ ANativeWindow::perform = hook_perform;
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
+ mReqWidth = 0;
+ mReqHeight = 0;
+ mReqFormat = 0;
+ mReqUsage = 0;
+ mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+ mQueryWidth = 0;
+ mQueryHeight = 0;
+ mQueryFormat = 0;
+ mConnectedToCpu = false;
+}
+
+void SurfaceTextureClient::setISurfaceTexture(
+ const sp<ISurfaceTexture>& surfaceTexture)
+{
+ mSurfaceTexture = surfaceTexture;
+
// Get a reference to the allocator.
mAllocator = mSurfaceTexture->getAllocator();
}
@@ -50,42 +71,42 @@
return mSurfaceTexture;
}
-int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
+int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
SurfaceTextureClient* c = getSelf(window);
return c->setSwapInterval(interval);
}
-int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->dequeueBuffer(buffer);
}
-int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->cancelBuffer(buffer);
}
-int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->lockBuffer(buffer);
}
-int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
return c->queueBuffer(buffer);
}
-int SurfaceTextureClient::query(const ANativeWindow* window,
+int SurfaceTextureClient::hook_query(const ANativeWindow* window,
int what, int* value) {
const SurfaceTextureClient* c = getSelf(window);
return c->query(what, value);
}
-int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
+int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
SurfaceTextureClient* c = getSelf(window);
@@ -219,7 +240,6 @@
*value = 0;
return NO_ERROR;
case NATIVE_WINDOW_CONCRETE_TYPE:
- // TODO: this is not needed anymore
*value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
return NO_ERROR;
}
@@ -254,6 +274,18 @@
case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
res = dispatchSetBuffersTimestamp(args);
break;
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+ res = dispatchSetBuffersDimensions(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ res = dispatchSetBuffersFormat(args);
+ break;
+ case NATIVE_WINDOW_LOCK:
+ res = dispatchLock(args);
+ break;
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ res = dispatchUnlockAndPost(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -290,7 +322,22 @@
int w = va_arg(args, int);
int h = va_arg(args, int);
int f = va_arg(args, int);
- return setBuffersGeometry(w, h, f);
+ int err = setBuffersDimensions(w, h);
+ if (err != 0) {
+ return err;
+ }
+ return setBuffersFormat(f);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersDimensions(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ return setBuffersDimensions(w, h);
+}
+
+int SurfaceTextureClient::dispatchSetBuffersFormat(va_list args) {
+ int f = va_arg(args, int);
+ return setBuffersFormat(f);
}
int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
@@ -303,28 +350,37 @@
return setBuffersTimestamp(timestamp);
}
+int SurfaceTextureClient::dispatchLock(va_list args) {
+ ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+ ARect* inOutDirtyBounds = va_arg(args, ARect*);
+ return lock(outBuffer, inOutDirtyBounds);
+}
+
+int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
+ return unlockAndPost();
+}
+
+
int SurfaceTextureClient::connect(int api) {
LOGV("SurfaceTextureClient::connect");
Mutex::Autolock lock(mMutex);
- return mSurfaceTexture->connect(api);
+ int err = mSurfaceTexture->connect(api);
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = true;
+ }
+ return err;
}
int SurfaceTextureClient::disconnect(int api) {
LOGV("SurfaceTextureClient::disconnect");
Mutex::Autolock lock(mMutex);
- return mSurfaceTexture->disconnect(api);
+ int err = mSurfaceTexture->disconnect(api);
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = false;
+ }
+ return err;
}
-int SurfaceTextureClient::getConnectedApi() const
-{
- // XXX: This method will be going away shortly, and is currently bogus. It
- // always returns "nothing is connected". It will go away once Surface gets
- // updated to actually connect as the 'CPU' API when locking a buffer.
- Mutex::Autolock lock(mMutex);
- return 0;
-}
-
-
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
LOGV("SurfaceTextureClient::setUsage");
@@ -367,12 +423,12 @@
return err;
}
-int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format)
+int SurfaceTextureClient::setBuffersDimensions(int w, int h)
{
- LOGV("SurfaceTextureClient::setBuffersGeometry");
+ LOGV("SurfaceTextureClient::setBuffersDimensions");
Mutex::Autolock lock(mMutex);
- if (w<0 || h<0 || format<0)
+ if (w<0 || h<0)
return BAD_VALUE;
if ((w && !h) || (!w && h))
@@ -380,7 +436,6 @@
mReqWidth = w;
mReqHeight = h;
- mReqFormat = format;
status_t err = mSurfaceTexture->setCrop(Rect(0, 0));
LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
@@ -388,6 +443,19 @@
return err;
}
+int SurfaceTextureClient::setBuffersFormat(int format)
+{
+ LOGV("SurfaceTextureClient::setBuffersFormat");
+ Mutex::Autolock lock(mMutex);
+
+ if (format<0)
+ return BAD_VALUE;
+
+ mReqFormat = format;
+
+ return NO_ERROR;
+}
+
int SurfaceTextureClient::setBuffersTransform(int transform)
{
LOGV("SurfaceTextureClient::setBuffersTransform");
@@ -410,4 +478,160 @@
}
}
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
+
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& src,
+ const Region& reg)
+{
+ // src and dst with, height and format must be identical. no verification
+ // is done here.
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ LOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ LOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
+ }
+
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t SurfaceTextureClient::lock(
+ ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+ if (mLockedBuffer != 0) {
+ LOGE("Surface::lock failed, already locked");
+ return INVALID_OPERATION;
+ }
+
+ if (!mConnectedToCpu) {
+ int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
+ if (err) {
+ return err;
+ }
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ }
+
+ ANativeWindowBuffer* out;
+ status_t err = dequeueBuffer(&out);
+ LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
+ if (err == NO_ERROR) {
+ sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
+ err = lockBuffer(backBuffer.get());
+ LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+ backBuffer->handle, strerror(-err));
+ if (err == NO_ERROR) {
+ const Rect bounds(backBuffer->width, backBuffer->height);
+
+ Region newDirtyRegion;
+ if (inOutDirtyBounds) {
+ newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+ newDirtyRegion.andSelf(bounds);
+ } else {
+ newDirtyRegion.set(bounds);
+ }
+
+ // figure out if we can copy the frontbuffer back
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ const bool canCopyBack = (frontBuffer != 0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ backBuffer->format == frontBuffer->format);
+
+ if (canCopyBack) {
+ // copy the area that is invalid and not repainted this round
+ const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty())
+ copyBlt(backBuffer, frontBuffer, copyback);
+ } else {
+ // if we can't copy-back anything, modify the user's dirty
+ // region to make sure they redraw the whole buffer
+ newDirtyRegion.set(bounds);
+ }
+
+ // keep track of the are of the buffer that is "clean"
+ // (ie: that will be redrawn)
+ mOldDirtyRegion = newDirtyRegion;
+
+ if (inOutDirtyBounds) {
+ *inOutDirtyBounds = newDirtyRegion.getBounds();
+ }
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ LOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ mLockedBuffer = backBuffer;
+ outBuffer->width = backBuffer->width;
+ outBuffer->height = backBuffer->height;
+ outBuffer->stride = backBuffer->stride;
+ outBuffer->format = backBuffer->format;
+ outBuffer->bits = vaddr;
+ }
+ }
+ return err;
+}
+
+status_t SurfaceTextureClient::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ LOGE("Surface::unlockAndPost failed, no locked buffer");
+ return INVALID_OPERATION;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get());
+ LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+ mLockedBuffer->handle, strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
+}
+
}; // namespace android
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 8d3a9b5..0308af3 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -2,8 +2,6 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_MODULE := SurfaceTexture_test
LOCAL_MODULE_TAGS := tests
@@ -36,8 +34,6 @@
include $(BUILD_EXECUTABLE)
-endif
-
# Include subdirectory makefiles
# ============================================================
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 519b40e..2b8f204 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -613,4 +613,90 @@
}
}
+class MultiSurfaceTextureClientTest : public ::testing::Test {
+
+public:
+ MultiSurfaceTextureClientTest() :
+ mEglDisplay(EGL_NO_DISPLAY),
+ mEglContext(EGL_NO_CONTEXT) {
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ mEglSurfaces[i] = EGL_NO_CONTEXT;
+ }
+ }
+
+protected:
+
+ enum { NUM_SURFACE_TEXTURES = 32 };
+
+ virtual void SetUp() {
+ mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+
+ EGLint majorVersion, minorVersion;
+ EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ EGLConfig myConfig;
+ EGLint numConfigs = 0;
+ EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+ EXPECT_TRUE(eglChooseConfig(mEglDisplay, configAttribs, &myConfig, 1,
+ &numConfigs));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
+ 0);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
+
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ sp<SurfaceTexture> st(new SurfaceTexture(i));
+ sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+ mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
+ static_cast<ANativeWindow*>(stc.get()), NULL);
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
+ }
+ }
+
+ virtual void TearDown() {
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ if (mEglSurfaces[i] != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, mEglSurfaces[i]);
+ }
+ }
+
+ if (mEglContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEglDisplay, mEglContext);
+ }
+
+ if (mEglDisplay != EGL_NO_DISPLAY) {
+ eglTerminate(mEglDisplay);
+ }
+ }
+
+ EGLDisplay mEglDisplay;
+ EGLSurface mEglSurfaces[NUM_SURFACE_TEXTURES];
+ EGLContext mEglContext;
+};
+
+// XXX: This test is disabled because it causes a hang on some devices. See bug
+// 5015672.
+TEST_F(MultiSurfaceTextureClientTest, DISABLED_MakeCurrentBetweenSurfacesWorks) {
+ for (int iter = 0; iter < 8; iter++) {
+ for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
+ eglMakeCurrent(mEglDisplay, mEglSurfaces[i], mEglSurfaces[i],
+ mEglContext);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mEglSurfaces[i]);
+ }
+ }
+}
+
} // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 88433fb..9abe89d 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "SurfaceTexture_test"
//#define LOG_NDEBUG 0
#include <gtest/gtest.h>
@@ -379,6 +380,13 @@
ASSERT_NE(-1, mTexMatrixHandle);
}
+ virtual void TearDown() {
+ mANW.clear();
+ mSTC.clear();
+ mST.clear();
+ GLTest::TearDown();
+ }
+
// drawTexture draws the SurfaceTexture over the entire GL viewport.
void drawTexture() {
const GLfloat triangleVertices[] = {
@@ -1089,13 +1097,21 @@
// synchronously from SurfaceTexture::queueBuffer.
class FrameCondition : public SurfaceTexture::FrameAvailableListener {
public:
+ FrameCondition():
+ mFrameAvailable(false),
+ mFrameFinished(false) {
+ }
+
// waitForFrame waits for the next frame to arrive. This should be
// called from the consumer thread once for every frame expected by the
// test.
void waitForFrame() {
- LOGV("+waitForFrame");
Mutex::Autolock lock(mMutex);
- status_t result = mFrameAvailableCondition.wait(mMutex);
+ LOGV("+waitForFrame");
+ while (!mFrameAvailable) {
+ mFrameAvailableCondition.wait(mMutex);
+ }
+ mFrameAvailable = false;
LOGV("-waitForFrame");
}
@@ -1103,22 +1119,30 @@
// on to produce the next frame. This should be called by the consumer
// thread once for every frame expected by the test.
void finishFrame() {
- LOGV("+finishFrame");
Mutex::Autolock lock(mMutex);
+ LOGV("+finishFrame");
+ mFrameFinished = true;
mFrameFinishCondition.signal();
LOGV("-finishFrame");
}
// This should be called by SurfaceTexture on the producer thread.
virtual void onFrameAvailable() {
- LOGV("+onFrameAvailable");
Mutex::Autolock lock(mMutex);
+ LOGV("+onFrameAvailable");
+ mFrameAvailable = true;
mFrameAvailableCondition.signal();
- mFrameFinishCondition.wait(mMutex);
+ while (!mFrameFinished) {
+ mFrameFinishCondition.wait(mMutex);
+ }
+ mFrameFinished = false;
LOGV("-onFrameAvailable");
}
protected:
+ bool mFrameAvailable;
+ bool mFrameFinished;
+
Mutex mMutex;
Condition mFrameAvailableCondition;
Condition mFrameFinishCondition;
@@ -1164,6 +1188,7 @@
}
mProducerThread.clear();
mFC.clear();
+ SurfaceTextureGLTest::TearDown();
}
void runProducerThread(const sp<ProducerThread> producerThread) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 563d7e4..e232ddd 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -73,7 +73,6 @@
String8 stringLog;
dumpMemoryUsage(stringLog);
LOGD("%s", stringLog.string());
- delete stringLog;
}
void Caches::dumpMemoryUsage(String8 &log) {
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 7c10518..47049e2 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -43,7 +43,7 @@
kDebugDisabled = 0,
kDebugMemory = 1,
kDebugCaches = 2,
- kDebugMoreCaches = 3
+ kDebugMoreCaches = kDebugMemory | kDebugCaches
};
// These properties are defined in mega-bytes
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index d9cc6b6..a8aa0c7 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -77,11 +77,6 @@
LOCAL_GENERATED_SOURCES += $(GEN)
-# libRS needs libacc, which isn't 64-bit clean, and so can't be built
-# for the simulator on gHardy, and therefore libRS needs to be excluded
-# from the simulator as well.
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_SRC_FILES:= \
rsAdapter.cpp \
rsAllocation.cpp \
@@ -228,5 +223,3 @@
LOCAL_LDLIBS := -lpthread
include $(BUILD_HOST_STATIC_LIBRARY)
-
-endif #simulator
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 62eb24e..bbf2836 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -269,6 +269,7 @@
void rsdScriptInvokeForEach(const Context *rsc,
Script *s,
+ uint32_t slot,
const Allocation * ain,
Allocation * aout,
const void * usr,
diff --git a/libs/rs/driver/rsdBcc.h b/libs/rs/driver/rsdBcc.h
index 62b50f4..67929bc 100644
--- a/libs/rs/driver/rsdBcc.h
+++ b/libs/rs/driver/rsdBcc.h
@@ -32,6 +32,7 @@
void rsdScriptInvokeForEach(const android::renderscript::Context *rsc,
android::renderscript::Script *s,
+ uint32_t slot,
const android::renderscript::Allocation * ain,
android::renderscript::Allocation * aout,
const void * usr,
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 44e9d89..447a7ff 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -340,10 +340,6 @@
Context * Context::createContext(Device *dev, const RsSurfaceConfig *sc) {
Context * rsc = new Context();
- // Temporary to avoid breaking the tools
- if (!dev) {
- return rsc;
- }
if (!rsc->initContext(dev, sc)) {
delete rsc;
return NULL;
@@ -693,7 +689,9 @@
LOGV("rsContextCreateGL %p", vdev);
Device * dev = static_cast<Device *>(vdev);
Context *rsc = Context::createContext(dev, &sc);
- rsc->setDPI(dpi);
+ if (rsc) {
+ rsc->setDPI(dpi);
+ }
LOGV("rsContextCreateGL ret %p ", rsc);
return rsc;
}
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index 2b58e9e..b77b18a 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -263,10 +263,10 @@
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- p = &p[mFields[i].offsetBits >> 3];
+ const uint8_t *p2 = &p[mFields[i].offsetBits >> 3];
for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
- mFields[i].e->incRefs(p);
- p += mFields[i].e->getSizeBytes();
+ mFields[i].e->incRefs(p2);
+ p2 += mFields[i].e->getSizeBytes();
}
}
}
@@ -285,10 +285,10 @@
const uint8_t *p = static_cast<const uint8_t *>(ptr);
for (uint32_t i=0; i < mFieldCount; i++) {
if (mFields[i].e->mHasReference) {
- p = &p[mFields[i].offsetBits >> 3];
+ const uint8_t *p2 = &p[mFields[i].offsetBits >> 3];
for (uint32_t ct=0; ct < mFields[i].arraySize; ct++) {
- mFields[i].e->decRefs(p);
- p += mFields[i].e->getSizeBytes();
+ mFields[i].e->decRefs(p2);
+ p2 += mFields[i].e->getSizeBytes();
}
}
}
diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp
index 70b7278..7023a1f 100644
--- a/libs/rs/rsLocklessFifo.cpp
+++ b/libs/rs/rsLocklessFifo.cpp
@@ -21,14 +21,16 @@
using namespace android;
using namespace android::renderscript;
-LocklessCommandFifo::LocklessCommandFifo() {
+LocklessCommandFifo::LocklessCommandFifo() : mBuffer(0) {
}
LocklessCommandFifo::~LocklessCommandFifo() {
if (!mInShutdown) {
shutdown();
}
- free(mBuffer);
+ if (mBuffer) {
+ free(mBuffer);
+ }
}
void LocklessCommandFifo::shutdown() {
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b230bb5..e8b1014 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -121,7 +121,7 @@
setupGLState(rsc);
setupScript(rsc);
- rsc->mHal.funcs.script.invokeForEach(rsc, this, ain, aout, usr, usrBytes, sc);
+ rsc->mHal.funcs.script.invokeForEach(rsc, this, 0, ain, aout, usr, usrBytes, sc);
}
void ScriptC::Invoke(Context *rsc, uint32_t slot, const void *data, size_t len) {
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index ab164c3..1c8b89c 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -21,8 +21,7 @@
using namespace android;
using namespace android::renderscript;
-ThreadIO::ThreadIO() {
- mToCore.init(16 * 1024);
+ThreadIO::ThreadIO() : mUsingSocket(false) {
}
ThreadIO::~ThreadIO() {
@@ -30,6 +29,7 @@
void ThreadIO::init(bool useSocket) {
mUsingSocket = useSocket;
+ mToCore.init(16 * 1024);
if (mUsingSocket) {
mToClientSocket.init();
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 928dca5..6a4537b 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -70,6 +70,7 @@
int (*invokeRoot)(const Context *rsc, Script *s);
void (*invokeForEach)(const Context *rsc,
Script *s,
+ uint32_t slot,
const Allocation * ain,
Allocation * aout,
const void * usr,
diff --git a/libs/storage/Android.mk b/libs/storage/Android.mk
index 1e52fa4..b42c34f 100644
--- a/libs/storage/Android.mk
+++ b/libs/storage/Android.mk
@@ -13,8 +13,4 @@
LOCAL_MODULE:= libstorage
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -lpthread
-endif
-
include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/surfaceflinger_client/Android.mk b/libs/surfaceflinger_client/Android.mk
index 267e3edf..5fca1ce 100644
--- a/libs/surfaceflinger_client/Android.mk
+++ b/libs/surfaceflinger_client/Android.mk
@@ -7,8 +7,4 @@
LOCAL_MODULE:= libsurfaceflinger_client
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -lpthread
-endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 427bbba..fbabfc4 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -68,10 +68,6 @@
LOCAL_MODULE:= libui
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -lpthread
-endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 4393504..794747d 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -299,9 +299,14 @@
{
switch (operation) {
case NATIVE_WINDOW_SET_USAGE:
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
case NATIVE_WINDOW_CONNECT:
case NATIVE_WINDOW_DISCONNECT:
break;
+ case NATIVE_WINDOW_LOCK:
+ return INVALID_OPERATION;
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ return INVALID_OPERATION;
default:
return NAME_NOT_FOUND;
}
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index c46d6f4..1e602e9 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -83,7 +83,9 @@
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
status_t result;
- int serverAshmemFd = ashmem_create_region(name.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
+ String8 ashmemName("InputChannel ");
+ ashmemName.append(name);
+ int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
if (serverAshmemFd < 0) {
result = -errno;
LOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index e231971..693a32a 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -2,8 +2,6 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-ifneq ($(TARGET_SIMULATOR),true)
-
# Build the unit tests.
test_src_files := \
InputChannel_test.cpp \
@@ -48,5 +46,3 @@
# Build the manual test programs.
include $(call all-subdir-makefiles)
-
-endif
\ No newline at end of file
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 774e8c9..f633357 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -103,17 +103,14 @@
liblog \
libcutils
-ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86)
# This is needed on x86 to bring in dl_iterate_phdr for CallStack.cpp
LOCAL_SHARED_LIBRARIES += libdl
endif # linux-x86
-endif # sim
LOCAL_MODULE:= libutils
include $(BUILD_SHARED_LIBRARY)
-ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_OS),linux)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += external/zlib external/icu4c/common
@@ -122,7 +119,6 @@
LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
include $(BUILD_STATIC_LIBRARY)
endif
-endif
# Include subdirectory makefiles
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 87549fe..7ef30f9 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -481,6 +481,14 @@
return sprintf(buf, "%d %s=%s\n", len, key, value);
}
+// Wire format to the backup manager service is chunked: each chunk is prefixed by
+// a 4-byte count of its size. A chunk size of zero (four zero bytes) indicates EOD.
+void send_tarfile_chunk(BackupDataWriter* writer, const char* buffer, size_t size) {
+ uint32_t chunk_size_no = htonl(size);
+ writer->WriteEntityData(&chunk_size_no, 4);
+ if (size != 0) writer->WriteEntityData(buffer, size);
+}
+
int write_tarfile(const String8& packageName, const String8& domain,
const String8& rootpath, const String8& filepath, BackupDataWriter* writer)
{
@@ -660,16 +668,16 @@
// Checksum and write the pax block header
calc_tar_checksum(paxHeader);
- writer->WriteEntityData(paxHeader, 512);
+ send_tarfile_chunk(writer, paxHeader, 512);
// Now write the pax data itself
int paxblocks = (paxLen + 511) / 512;
- writer->WriteEntityData(paxData, 512 * paxblocks);
+ send_tarfile_chunk(writer, paxData, 512 * paxblocks);
}
// Checksum and write the 512-byte ustar file header block to the output
calc_tar_checksum(buf);
- writer->WriteEntityData(buf, 512);
+ send_tarfile_chunk(writer, buf, 512);
// Now write the file data itself, for real files. We honor tar's convention that
// only full 512-byte blocks are sent to write().
@@ -699,7 +707,7 @@
memset(buf + nRead, 0, remainder);
nRead += remainder;
}
- writer->WriteEntityData(buf, nRead);
+ send_tarfile_chunk(writer, buf, nRead);
toWrite -= nRead;
}
}
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 50312e7..d18c0a2 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -161,6 +161,7 @@
pthread_t thread;
int result = pthread_create(&thread, &attr,
(android_pthread_entry)entryFunction, userData);
+ pthread_attr_destroy(&attr);
if (result != 0) {
LOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, errno=%d)\n"
"(android threadPriority=%d)",
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 289c826..bfb37a6 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -252,13 +252,15 @@
"[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
void* item = editItemLocation(index);
- if (item == 0)
- return NO_MEMORY;
- _do_destroy(item, 1);
- if (prototype == 0) {
- _do_construct(item, 1);
- } else {
- _do_copy(item, prototype, 1);
+ if (item != prototype) {
+ if (item == 0)
+ return NO_MEMORY;
+ _do_destroy(item, 1);
+ if (prototype == 0) {
+ _do_construct(item, 1);
+ } else {
+ _do_copy(item, prototype, 1);
+ }
}
return ssize_t(index);
}
@@ -290,7 +292,7 @@
void* VectorImpl::editItemLocation(size_t index)
{
LOG_ASSERT(index<capacity(),
- "[%p] itemLocation: index=%d, capacity=%d, count=%d",
+ "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
this, (int)index, (int)capacity(), (int)mCount);
void* buffer = editArrayImpl();
@@ -302,7 +304,7 @@
const void* VectorImpl::itemLocation(size_t index) const
{
LOG_ASSERT(index<capacity(),
- "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
+ "[%p] itemLocation: index=%d, capacity=%d, count=%d",
this, (int)index, (int)capacity(), (int)mCount);
const void* buffer = arrayImpl();
@@ -347,9 +349,10 @@
// LOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
// this, (int)where, (int)amount, (int)mCount, (int)capacity());
- if (where > mCount)
- where = mCount;
-
+ LOG_ASSERT(where <= mCount,
+ "[%p] _grow: where=%d, amount=%d, count=%d",
+ this, (int)where, (int)amount, (int)mCount); // caller already checked
+
const size_t new_size = mCount + amount;
if (capacity() < new_size) {
const size_t new_capacity = max(kMinVectorCapacity, ((new_size*3)+1)/2);
@@ -366,10 +369,10 @@
SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
if (sb) {
void* array = sb->data();
- if (where>0) {
+ if (where != 0) {
_do_copy(array, mStorage, where);
}
- if (mCount>where) {
+ if (where != mCount) {
const void* from = reinterpret_cast<const uint8_t *>(mStorage) + where*mItemSize;
void* dest = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
_do_copy(dest, from, mCount-where);
@@ -379,15 +382,14 @@
}
}
} else {
- ssize_t s = mCount-where;
- if (s>0) {
- void* array = editArrayImpl();
- void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ if (where != mCount) {
+ void* array = editArrayImpl();
const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
- _do_move_forward(to, from, s);
+ void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
+ _do_move_forward(to, from, mCount - where);
}
}
- mCount += amount;
+ mCount = new_size;
void* free_space = const_cast<void*>(itemLocation(where));
return free_space;
}
@@ -400,14 +402,15 @@
// LOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
// this, (int)where, (int)amount, (int)mCount, (int)capacity());
- if (where >= mCount)
- where = mCount - amount;
+ LOG_ASSERT(where + amount <= mCount,
+ "[%p] _shrink: where=%d, amount=%d, count=%d",
+ this, (int)where, (int)amount, (int)mCount); // caller already checked
const size_t new_size = mCount - amount;
if (new_size*3 < capacity()) {
const size_t new_capacity = max(kMinVectorCapacity, new_size*2);
// LOGV("shrink vector %p, new_capacity=%d", this, (int)new_capacity);
- if ((where == mCount-amount) &&
+ if ((where == new_size) &&
(mFlags & HAS_TRIVIAL_COPY) &&
(mFlags & HAS_TRIVIAL_DTOR))
{
@@ -418,31 +421,28 @@
SharedBuffer* sb = SharedBuffer::alloc(new_capacity * mItemSize);
if (sb) {
void* array = sb->data();
- if (where>0) {
+ if (where != 0) {
_do_copy(array, mStorage, where);
}
- if (mCount > where+amount) {
+ if (where != new_size) {
const void* from = reinterpret_cast<const uint8_t *>(mStorage) + (where+amount)*mItemSize;
void* dest = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
- _do_copy(dest, from, mCount-(where+amount));
+ _do_copy(dest, from, new_size - where);
}
release_storage();
mStorage = const_cast<void*>(array);
}
}
} else {
- void* array = editArrayImpl();
+ void* array = editArrayImpl();
void* to = reinterpret_cast<uint8_t *>(array) + where*mItemSize;
_do_destroy(to, amount);
- ssize_t s = mCount-(where+amount);
- if (s>0) {
+ if (where != new_size) {
const void* from = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
- _do_move_backward(to, from, s);
+ _do_move_backward(to, from, new_size - where);
}
}
-
- // adjust the number of items...
- mCount -= amount;
+ mCount = new_size;
}
size_t VectorImpl::itemSize() const {
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 87ad98e..8726a53 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -2,8 +2,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-ifneq ($(TARGET_SIMULATOR),true)
-
# Build the unit tests.
test_src_files := \
BlobCache_test.cpp \
@@ -43,5 +41,3 @@
$(eval LOCAL_MODULE_TAGS := $(module_tags)) \
$(eval include $(BUILD_EXECUTABLE)) \
)
-
-endif
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b97c3c4..b20a6e9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -32,24 +32,25 @@
* It allows to stream PCM audio buffers to the audio hardware for playback. This is
* achieved by "pushing" the data to the AudioTrack object using one of the
* {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
- *
+ *
* <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
* In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
- * one of the write() methods. These are blocking and return when the data has been transferred
- * from the Java layer to the native layer and queued for playback. The streaming mode
- * is most useful when playing blocks of audio data that for instance are:
+ * one of the {@code write()} methods. These are blocking and return when the data has been
+ * transferred from the Java layer to the native layer and queued for playback. The streaming
+ * mode is most useful when playing blocks of audio data that for instance are:
+ *
* <ul>
* <li>too big to fit in memory because of the duration of the sound to play,</li>
* <li>too big to fit in memory because of the characteristics of the audio data
* (high sampling rate, bits per sample ...)</li>
* <li>received or generated while previously queued audio is playing.</li>
* </ul>
+ *
* The static mode is to be chosen when dealing with short sounds that fit in memory and
- * that need to be played with the smallest latency possible. AudioTrack instances in static mode
- * can play the sound without the need to transfer the audio data from Java to native layer
- * each time the sound is to be played. The static mode will therefore be preferred for UI and
- * game sounds that are played often, and with the smallest overhead possible.
- *
+ * that need to be played with the smallest latency possible. The static mode will
+ * therefore be preferred for UI and game sounds that are played often, and with the
+ * smallest overhead possible.
+ *
* <p>Upon creation, an AudioTrack object initializes its associated audio buffer.
* The size of this buffer, specified during the construction, determines how long an AudioTrack
* can play before running out of data.<br>
@@ -816,6 +817,7 @@
//--------------------
/**
* Starts playing an AudioTrack.
+ *
* @throws IllegalStateException
*/
public void play()
@@ -832,6 +834,7 @@
/**
* Stops playing the audio data.
+ *
* @throws IllegalStateException
*/
public void stop()
@@ -848,7 +851,10 @@
}
/**
- * Pauses the playback of the audio data.
+ * Pauses the playback of the audio data. Data that has not been played
+ * back will not be discarded. Subsequent calls to {@link #play} will play
+ * this data back.
+ *
* @throws IllegalStateException
*/
public void pause()
@@ -871,9 +877,9 @@
//--------------------
/**
- * Flushes the audio data currently queued for playback.
+ * Flushes the audio data currently queued for playback. Any data that has
+ * not been played back will be discarded.
*/
-
public void flush() {
if (mState == STATE_INITIALIZED) {
// flush the data in native layer
@@ -883,9 +889,14 @@
}
/**
- * Writes the audio data to the audio hardware for playback.
+ * Writes the audio data to the audio hardware for playback. Will block until
+ * all data has been written to the audio mixer.
+ * Note that the actual playback of this data might occur after this function
+ * returns. This function is thread safe with respect to {@link #stop} calls,
+ * in which case all of the specified data might not be written to the mixer.
+ *
* @param audioData the array that holds the data to play.
- * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
+ * @param offsetInBytes the offset expressed in bytes in audioData where the data to play
* starts.
* @param sizeInBytes the number of bytes to read in audioData after the offset.
* @return the number of bytes that were written or {@link #ERROR_INVALID_OPERATION}
@@ -914,7 +925,12 @@
/**
- * Writes the audio data to the audio hardware for playback.
+ * Writes the audio data to the audio hardware for playback. Will block until
+ * all data has been written to the audio mixer.
+ * Note that the actual playback of this data might occur after this function
+ * returns. This function is thread safe with respect to {@link #stop} calls,
+ * in which case all of the specified data might not be written to the mixer.
+ *
* @param audioData the array that holds the data to play.
* @param offsetInShorts the offset expressed in shorts in audioData where the data to play
* starts.
@@ -988,7 +1004,7 @@
/**
* Sets the send level of the audio track to the attached auxiliary effect
- * {@see #attachAuxEffect(int)}. The level value range is 0 to 1.0.
+ * {@link #attachAuxEffect(int)}. The level value range is 0 to 1.0.
* <p>By default the send level is 0, so even if an effect is attached to the player
* this method must be called for the effect to be applied.
* <p>Note that the passed level value is a raw scalar. UI controls should be scaled
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 18742ea..8c8569a 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -101,6 +101,8 @@
* Java MyMediaScanner handleStringTag.
* Once MediaScanner processFile returns, an entry is inserted in to the database.
*
+ * The MediaScanner class is not thread-safe, so it should only be used in a single threaded manner.
+ *
* {@hide}
*/
public class MediaScanner
@@ -705,7 +707,9 @@
map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
map.put(MediaStore.MediaColumns.IS_DRM, mIsDrm);
- if (!mNoMedia) {
+ if (mNoMedia) {
+ map.put(MediaStore.MediaColumns.NO_MEDIA, true);
+ } else {
if (MediaFile.isVideoFileType(mFileType)) {
map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0
? mArtist : MediaStore.UNKNOWN_STRING));
@@ -833,6 +837,9 @@
}
}
+ // For inserts we always use the file URI so we can insert in bulk.
+ // For updates we compute the URI based on the media type.
+ Uri tableUri = mFilesUri;
Uri result = null;
if (rowId == 0) {
if (mMtpObjectHandle != 0) {
@@ -848,7 +855,7 @@
if (mFileInserter != null) {
result = mFileInserter.insert(values);
} else {
- result = mMediaProvider.insert(mFilesUri, values);
+ result = mMediaProvider.insert(tableUri, values);
}
if (result != null) {
@@ -856,8 +863,18 @@
entry.mRowId = rowId;
}
} else {
+ if (!mNoMedia) {
+ if (MediaFile.isVideoFileType(mFileType)) {
+ tableUri = mVideoUri;
+ } else if (MediaFile.isImageFileType(mFileType)) {
+ tableUri = mImagesUri;
+ } else if (MediaFile.isAudioFileType(mFileType)) {
+ tableUri = mAudioUri;
+ }
+ }
+
// updated file
- result = ContentUris.withAppendedId(mFilesUri, rowId);
+ result = ContentUris.withAppendedId(tableUri, rowId);
// path should never change, and we want to avoid replacing mixed cased paths
// with squashed lower case paths
values.remove(MediaStore.MediaColumns.DATA);
@@ -907,19 +924,19 @@
if (notifications && !mDefaultNotificationSet) {
if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
- setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, mFilesUri, rowId);
+ setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
mDefaultNotificationSet = true;
}
} else if (ringtones && !mDefaultRingtoneSet) {
if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
- setSettingIfNotSet(Settings.System.RINGTONE, mFilesUri, rowId);
+ setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
mDefaultRingtoneSet = true;
}
} else if (alarms && !mDefaultAlarmSet) {
if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
- setSettingIfNotSet(Settings.System.ALARM_ALERT, mFilesUri, rowId);
+ setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
mDefaultAlarmSet = true;
}
}
@@ -1174,10 +1191,6 @@
mPlaylistsUri = Playlists.getContentUri(volumeName);
mCaseInsensitivePaths = true;
- if (!Process.supportsProcesses()) {
- // Simulator uses host file system, so it should be case sensitive.
- mCaseInsensitivePaths = false;
- }
}
}
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index 0133cf6..f561cc0 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -16,18 +16,13 @@
package android.mtp;
-import android.util.Log;
-
/**
* Java wrapper for MTP/PTP support as USB responder.
* {@hide}
*/
-public class MtpServer {
+public class MtpServer implements Runnable {
- private final Object mLock = new Object();
- private boolean mStarted;
-
- private static final String TAG = "MtpServer";
+ private int mNativeContext; // accessed by native methods
static {
System.loadLibrary("media_jni");
@@ -38,19 +33,14 @@
}
public void start() {
- synchronized (mLock) {
- native_start();
- mStarted = true;
- }
+ Thread thread = new Thread(this, "MtpServer");
+ thread.start();
}
- public void stop() {
- synchronized (mLock) {
- if (mStarted) {
- native_stop();
- mStarted = false;
- }
- }
+ @Override
+ public void run() {
+ native_run();
+ native_cleanup();
}
public void sendObjectAdded(int handle) {
@@ -70,8 +60,8 @@
}
private native final void native_setup(MtpDatabase database, boolean usePtp);
- private native final void native_start();
- private native final void native_stop();
+ private native final void native_run();
+ private native final void native_cleanup();
private native final void native_send_object_added(int handle);
private native final void native_send_object_removed(int handle);
private native final void native_add_storage(MtpStorage storage);
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 9151799..d0d2d1e 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -45,7 +45,6 @@
jfieldID context;
};
static fields_t fields;
-static Mutex sLock;
class MyMediaScannerClient : public MediaScannerClient
{
@@ -159,13 +158,11 @@
return ((JNIEnv *)env)->ExceptionCheck();
}
-// Call this method with sLock hold
static MediaScanner *getNativeScanner_l(JNIEnv* env, jobject thiz)
{
return (MediaScanner *) env->GetIntField(thiz, fields.context);
}
-// Call this method with sLock hold
static void setNativeScanner_l(JNIEnv* env, jobject thiz, MediaScanner *s)
{
env->SetIntField(thiz, fields.context, (int)s);
@@ -176,7 +173,6 @@
JNIEnv *env, jobject thiz, jstring path, jobject client)
{
LOGV("processDirectory");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == NULL) {
jniThrowException(env, kRunTimeException, "No scanner available");
@@ -243,7 +239,6 @@
JNIEnv *env, jobject thiz, jstring locale)
{
LOGV("setLocale");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == NULL) {
jniThrowException(env, kRunTimeException, "No scanner available");
@@ -268,7 +263,6 @@
JNIEnv *env, jobject thiz, jobject fileDescriptor)
{
LOGV("extractAlbumArt");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == NULL) {
jniThrowException(env, kRunTimeException, "No scanner available");
@@ -339,7 +333,6 @@
android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
{
LOGV("native_finalize");
- Mutex::Autolock l(sLock);
MediaScanner *mp = getNativeScanner_l(env, thiz);
if (mp == 0) {
return;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 0f3c063..4dbcb90 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -79,7 +79,6 @@
return (MtpDatabase *)env->GetIntField(database, field_context);
}
-#ifdef HAVE_ANDROID_OS
// ----------------------------------------------------------------------------
class MyMtpDatabase : public MtpDatabase {
@@ -1066,42 +1065,32 @@
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
-#endif // HAVE_ANDROID_OS
-
// ----------------------------------------------------------------------------
static void
android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
env->SetIntField(thiz, field_context, (int)database);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
-#endif
}
static void
android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
database->cleanup(env);
delete database;
env->SetIntField(thiz, field_context, 0);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
-#endif
}
static jstring
android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
{
-#ifdef HAVE_ANDROID_OS
char date[20];
formatDateTime(seconds, date, sizeof(date));
return env->NewStringUTF(date);
-#else
- return NULL;
-#endif
}
// ----------------------------------------------------------------------------
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 40bbaa3..6b73f6c 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -85,8 +85,6 @@
static jfieldID field_objectInfo_dateModified;
static jfieldID field_objectInfo_keywords;
-#ifdef HAVE_ANDROID_OS
-
MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
{
return (MtpDevice*)env->GetIntField(javaDevice, field_context);
@@ -100,15 +98,11 @@
}
}
-#endif // HAVE_ANDROID_OS
-
// ----------------------------------------------------------------------------
static jboolean
android_mtp_MtpDevice_open(JNIEnv *env, jobject thiz, jstring deviceName, jint fd)
{
-#ifdef HAVE_ANDROID_OS
- LOGD("open\n");
const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
if (deviceNameStr == NULL) {
return false;
@@ -120,27 +114,22 @@
if (device)
env->SetIntField(thiz, field_context, (int)device);
return (device != NULL);
-#endif
}
static void
android_mtp_MtpDevice_close(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
- LOGD("close\n");
MtpDevice* device = get_device_from_object(env, thiz);
if (device) {
device->close();
delete device;
env->SetIntField(thiz, field_context, 0);
}
-#endif
}
static jobject
android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device) {
LOGD("android_mtp_MtpDevice_get_device_info device is null");
@@ -173,15 +162,11 @@
delete deviceInfo;
return info;
-#else
- return NULL;
-#endif
}
static jintArray
android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -196,15 +181,11 @@
delete storageIDs;
return array;
-#else
- return NULL;
-#endif
}
static jobject
android_mtp_MtpDevice_get_storage_info(JNIEnv *env, jobject thiz, jint storageID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -234,16 +215,12 @@
delete storageInfo;
return info;
-#else
- return NULL;
-#endif
}
static jintArray
android_mtp_MtpDevice_get_object_handles(JNIEnv *env, jobject thiz,
jint storageID, jint format, jint objectID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -258,15 +235,11 @@
delete handles;
return array;
-#else
- return NULL;
-#endif
}
static jobject
android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -324,9 +297,6 @@
delete objectInfo;
return info;
-#else
- return NULL;
-#endif
}
struct get_object_callback_data {
@@ -344,7 +314,6 @@
static jbyteArray
android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -361,14 +330,12 @@
if (device->readObject(objectID, get_object_callback, objectSize, &data))
return array;
-#endif
return NULL;
}
static jbyteArray
android_mtp_MtpDevice_get_thumbnail(JNIEnv *env, jobject thiz, jint objectID)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (!device)
return NULL;
@@ -382,51 +349,41 @@
free(thumbnail);
return array;
-#else
- return NULL;
-#endif
}
static jboolean
android_mtp_MtpDevice_delete_object(JNIEnv *env, jobject thiz, jint object_id)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
return device->deleteObject(object_id);
else
- #endif
return NULL;
}
static jlong
android_mtp_MtpDevice_get_parent(JNIEnv *env, jobject thiz, jint object_id)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
return device->getParent(object_id);
else
-#endif
return -1;
}
static jlong
android_mtp_MtpDevice_get_storage_id(JNIEnv *env, jobject thiz, jint object_id)
{
- #ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device)
return device->getStorageID(object_id);
else
-#endif
return -1;
}
static jboolean
android_mtp_MtpDevice_import_file(JNIEnv *env, jobject thiz, jint object_id, jstring dest_path)
{
-#ifdef HAVE_ANDROID_OS
MtpDevice* device = get_device_from_object(env, thiz);
if (device) {
const char *destPathStr = env->GetStringUTFChars(dest_path, NULL);
@@ -438,7 +395,7 @@
env->ReleaseStringUTFChars(dest_path, destPathStr);
return result;
}
-#endif
+
return false;
}
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 446b630..107db08 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -22,13 +22,8 @@
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
-#include <sys/ioctl.h>
#include <utils/threads.h>
-#ifdef HAVE_ANDROID_OS
-#include <linux/usb/f_mtp.h>
-#endif
-
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
@@ -39,8 +34,8 @@
using namespace android;
-// MtpStorage class
-jclass clazz_MtpStorage;
+// MtpServer fields
+static jfieldID field_MtpServer_nativeContext;
// MtpStorage fields
static jfieldID field_MtpStorage_storageId;
@@ -57,173 +52,78 @@
// in android_mtp_MtpDatabase.cpp
extern MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database);
-// ----------------------------------------------------------------------------
-
-#ifdef HAVE_ANDROID_OS
-
-static bool ExceptionCheck(void* env)
-{
- return ((JNIEnv *)env)->ExceptionCheck();
+static inline MtpServer* getMtpServer(JNIEnv *env, jobject thiz) {
+ return (MtpServer*)env->GetIntField(thiz, field_MtpServer_nativeContext);
}
-class MtpThread : public Thread {
-private:
- MtpDatabase* mDatabase;
- bool mPtp;
- MtpServer* mServer;
- MtpStorageList mStorageList;
- int mFd;
-
-public:
- MtpThread(MtpDatabase* database, bool usePtp)
- : mDatabase(database),
- mPtp(usePtp),
- mServer(NULL),
- mFd(-1)
- {
- }
-
- virtual ~MtpThread() {
- }
-
- void addStorage(MtpStorage *storage) {
- mStorageList.push(storage);
- if (mServer)
- mServer->addStorage(storage);
- }
-
- void removeStorage(MtpStorageID id) {
- MtpStorage* storage = mServer->getStorage(id);
- if (storage) {
- for (size_t i = 0; i < mStorageList.size(); i++) {
- if (mStorageList[i] == storage) {
- mStorageList.removeAt(i);
- break;
- }
- }
- if (mServer)
- mServer->removeStorage(storage);
- delete storage;
- }
- }
-
- void start() {
- run("MtpThread");
- }
-
- virtual bool threadLoop() {
- sMutex.lock();
-
- mFd = open("/dev/mtp_usb", O_RDWR);
- if (mFd >= 0) {
- mServer = new MtpServer(mFd, mDatabase, mPtp, AID_MEDIA_RW, 0664, 0775);
- for (size_t i = 0; i < mStorageList.size(); i++) {
- mServer->addStorage(mStorageList[i]);
- }
- } else {
- LOGE("could not open MTP driver, errno: %d", errno);
- }
-
- sMutex.unlock();
- mServer->run();
- sMutex.lock();
-
- close(mFd);
- mFd = -1;
- delete mServer;
- mServer = NULL;
-
- sMutex.unlock();
- // delay a bit before retrying to avoid excessive spin
- if (!exitPending()) {
- sleep(1);
- }
-
- return true;
- }
-
- void sendObjectAdded(MtpObjectHandle handle) {
- if (mServer)
- mServer->sendObjectAdded(handle);
- }
-
- void sendObjectRemoved(MtpObjectHandle handle) {
- if (mServer)
- mServer->sendObjectRemoved(handle);
- }
-};
-
-// This smart pointer is necessary for preventing MtpThread from exiting too early
-static sp<MtpThread> sThread;
-
-#endif // HAVE_ANDROID_OS
-
static void
android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase, jboolean usePtp)
{
-#ifdef HAVE_ANDROID_OS
- // create the thread and assign it to the smart pointer
- sThread = new MtpThread(getMtpDatabase(env, javaDatabase), usePtp);
-#endif
-}
-
-static void
-android_mtp_MtpServer_start(JNIEnv *env, jobject thiz)
-{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->start();
- sMutex.unlock();
-#endif // HAVE_ANDROID_OS
-}
-
-static void
-android_mtp_MtpServer_stop(JNIEnv *env, jobject thiz)
-{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread) {
- thread->requestExitAndWait();
- sThread = NULL;
+ int fd = open("/dev/mtp_usb", O_RDWR);
+ if (fd >= 0) {
+ MtpServer* server = new MtpServer(fd, getMtpDatabase(env, javaDatabase),
+ usePtp, AID_MEDIA_RW, 0664, 0775);
+ env->SetIntField(thiz, field_MtpServer_nativeContext, (int)server);
+ } else {
+ LOGE("could not open MTP driver, errno: %d", errno);
}
- sMutex.unlock();
-#endif
+}
+
+static void
+android_mtp_MtpServer_run(JNIEnv *env, jobject thiz)
+{
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->run();
+ else
+ LOGE("server is null in run");
+}
+
+static void
+android_mtp_MtpServer_cleanup(JNIEnv *env, jobject thiz)
+{
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server) {
+ delete server;
+ env->SetIntField(thiz, field_MtpServer_nativeContext, 0);
+ } else {
+ LOGE("server is null in cleanup");
+ }
}
static void
android_mtp_MtpServer_send_object_added(JNIEnv *env, jobject thiz, jint handle)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->sendObjectAdded(handle);
- sMutex.unlock();
-#endif
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->sendObjectAdded(handle);
+ else
+ LOGE("server is null in send_object_added");
}
static void
android_mtp_MtpServer_send_object_removed(JNIEnv *env, jobject thiz, jint handle)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->sendObjectRemoved(handle);
- sMutex.unlock();
-#endif
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server)
+ server->sendObjectRemoved(handle);
+ else
+ LOGE("server is null in send_object_removed");
}
static void
android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread) {
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server) {
jint storageID = env->GetIntField(jstorage, field_MtpStorage_storageId);
jstring path = (jstring)env->GetObjectField(jstorage, field_MtpStorage_path);
jstring description = (jstring)env->GetObjectField(jstorage, field_MtpStorage_description);
@@ -237,7 +137,7 @@
if (descriptionStr != NULL) {
MtpStorage* storage = new MtpStorage(storageID, pathStr, descriptionStr,
reserveSpace, removable, maxFileSize);
- thread->addStorage(storage);
+ server->addStorage(storage);
env->ReleaseStringUTFChars(path, pathStr);
env->ReleaseStringUTFChars(description, descriptionStr);
} else {
@@ -245,24 +145,24 @@
}
}
} else {
- LOGE("MtpThread is null in add_storage");
+ LOGE("server is null in add_storage");
}
- sMutex.unlock();
-#endif
}
static void
android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
{
-#ifdef HAVE_ANDROID_OS
- sMutex.lock();
- MtpThread *thread = sThread.get();
- if (thread)
- thread->removeStorage(storageId);
- else
- LOGE("MtpThread is null in remove_storage");
- sMutex.unlock();
-#endif
+ Mutex::Autolock autoLock(sMutex);
+
+ MtpServer* server = getMtpServer(env, thiz);
+ if (server) {
+ MtpStorage* storage = server->getStorage(storageId);
+ if (storage) {
+ server->removeStorage(storage);
+ delete storage;
+ }
+ } else
+ LOGE("server is null in remove_storage");
}
// ----------------------------------------------------------------------------
@@ -270,8 +170,8 @@
static JNINativeMethod gMethods[] = {
{"native_setup", "(Landroid/mtp/MtpDatabase;Z)V",
(void *)android_mtp_MtpServer_setup},
- {"native_start", "()V", (void *)android_mtp_MtpServer_start},
- {"native_stop", "()V", (void *)android_mtp_MtpServer_stop},
+ {"native_run", "()V", (void *)android_mtp_MtpServer_run},
+ {"native_cleanup", "()V", (void *)android_mtp_MtpServer_cleanup},
{"native_send_object_added", "(I)V", (void *)android_mtp_MtpServer_send_object_added},
{"native_send_object_removed", "(I)V", (void *)android_mtp_MtpServer_send_object_removed},
{"native_add_storage", "(Landroid/mtp/MtpStorage;)V",
@@ -320,13 +220,17 @@
LOGE("Can't find MtpStorage.mMaxFileSize");
return -1;
}
- clazz_MtpStorage = (jclass)env->NewGlobalRef(clazz);
clazz = env->FindClass("android/mtp/MtpServer");
if (clazz == NULL) {
LOGE("Can't find android/mtp/MtpServer");
return -1;
}
+ field_MtpServer_nativeContext = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (field_MtpServer_nativeContext == NULL) {
+ LOGE("Can't find MtpServer.mNativeContext");
+ return -1;
+ }
return AndroidRuntime::registerNativeMethods(env,
"android/mtp/MtpServer", gMethods, NELEM(gMethods));
diff --git a/media/libeffects/factory/Android.mk b/media/libeffects/factory/Android.mk
index 20f58e5..26265ae 100644
--- a/media/libeffects/factory/Android.mk
+++ b/media/libeffects/factory/Android.mk
@@ -12,14 +12,6 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE:= libeffects
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
-endif
-
-ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += libdl
-endif
-
-LOCAL_C_INCLUDES := \
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index a3e76d9..a9689bc 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -130,10 +130,43 @@
return ret;
}
+int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+{
+ int ret = init();
+ if (ret < 0) {
+ return ret;
+ }
+ effect_entry_t *fx = (effect_entry_t *)self;
+ pthread_mutex_lock(&gLibLock);
+ if (fx->lib == NULL) {
+ pthread_mutex_unlock(&gLibLock);
+ return -EPIPE;
+ }
+ pthread_mutex_lock(&fx->lib->lock);
+ pthread_mutex_unlock(&gLibLock);
+
+ if ((*fx->subItfe)->process_reverse != NULL) {
+ ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer);
+ } else {
+ ret = -ENOSYS;
+ }
+ pthread_mutex_unlock(&fx->lib->lock);
+ return ret;
+}
+
+
const struct effect_interface_s gInterface = {
Effect_Process,
Effect_Command,
- Effect_GetDescriptor
+ Effect_GetDescriptor,
+ NULL
+};
+
+const struct effect_interface_s gInterfaceWithReverse = {
+ Effect_Process,
+ Effect_Command,
+ Effect_GetDescriptor,
+ Effect_ProcessReverse
};
/////////////////////////////////////////////////
@@ -266,7 +299,13 @@
// add entry to effect list
fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
fx->subItfe = itfe;
- fx->itfe = (struct effect_interface_s *)&gInterface;
+ if ((*itfe)->process_reverse != NULL) {
+ fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse;
+ LOGV("EffectCreate() gInterfaceWithReverse");
+ } else {
+ fx->itfe = (struct effect_interface_s *)&gInterface;
+ LOGV("EffectCreate() gInterface");
+ }
fx->lib = l;
e = (list_elem_t *)malloc(sizeof(list_elem_t));
diff --git a/media/libeffects/lvm/wrapper/Android.mk b/media/libeffects/lvm/wrapper/Android.mk
index ab13605..f097dd0 100644
--- a/media/libeffects/lvm/wrapper/Android.mk
+++ b/media/libeffects/lvm/wrapper/Android.mk
@@ -19,12 +19,7 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
-
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_LDLIBS += -ldl
-else
-LOCAL_SHARED_LIBRARIES += libdl
-endif
+ libdl
LOCAL_C_INCLUDES += \
@@ -54,12 +49,7 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
-
-ifeq ($(TARGET_SIMULATOR),true)
-LOCAL_LDLIBS += -ldl
-else
-LOCAL_SHARED_LIBRARIES += libdl
-endif
+ libdl
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/Reverb \
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 21c451f..efa1c45 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -3231,7 +3231,8 @@
const struct effect_interface_s gLvmEffectInterface = {
Effect_process,
Effect_command,
- Effect_getDescriptor
+ Effect_getDescriptor,
+ NULL,
}; /* end gLvmEffectInterface */
audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 2727375..663f8ff 100755
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -2134,7 +2134,8 @@
const struct effect_interface_s gReverbInterface = {
Reverb_process,
Reverb_command,
- Reverb_getDescriptor
+ Reverb_getDescriptor,
+ NULL,
}; /* end gReverbInterface */
audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
new file mode 100755
index 0000000..77d40b6
--- /dev/null
+++ b/media/libeffects/preprocessing/Android.mk
@@ -0,0 +1,32 @@
+LOCAL_PATH:= $(call my-dir)
+
+# audio preprocessing wrapper
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libaudiopreprocessing
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
+
+LOCAL_SRC_FILES:= \
+ PreProcessing.cpp
+
+LOCAL_C_INCLUDES += \
+ external/webrtc/src \
+ external/webrtc/src/modules/interface \
+ external/webrtc/src/modules/audio_processing/main/interface \
+ system/media/audio_effects/include
+
+LOCAL_C_INCLUDES += $(call include-path-for, speex)
+
+LOCAL_SHARED_LIBRARIES := \
+ libwebrtc_audio_preprocessing \
+ libspeexresampler \
+ libutils
+
+ifeq ($(TARGET_SIMULATOR),true)
+LOCAL_LDLIBS += -ldl
+else
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
new file mode 100755
index 0000000..ba286a1
--- /dev/null
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -0,0 +1,1609 @@
+/*
+ * Copyright (C) 2011 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 <stdlib.h>
+#include <string.h>
+#define LOG_TAG "PreProcessing"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <hardware/audio_effect.h>
+#include <audio_effects/effect_aec.h>
+#include <audio_effects/effect_agc.h>
+#include <audio_effects/effect_ns.h>
+#include "modules/interface/module_common_types.h"
+#include "modules/audio_processing/main/interface/audio_processing.h"
+#include "speex/speex_resampler.h"
+
+
+//------------------------------------------------------------------------------
+// local definitions
+//------------------------------------------------------------------------------
+
+// maximum number of sessions
+#define PREPROC_NUM_SESSIONS 8
+
+// types of pre processing modules
+enum preproc_id
+{
+ PREPROC_AGC, // Automatic Gain Control
+ PREPROC_AEC, // Acoustic Echo Canceler
+ PREPROC_NS, // Noise Suppressor
+ PREPROC_NUM_EFFECTS
+};
+
+// Session state
+enum preproc_session_state {
+ PREPROC_SESSION_STATE_INIT, // initialized
+ PREPROC_SESSION_STATE_CONFIG // configuration received
+};
+
+// Effect/Preprocessor state
+enum preproc_effect_state {
+ PREPROC_EFFECT_STATE_INIT, // initialized
+ PREPROC_EFFECT_STATE_CREATED, // webRTC engine created
+ PREPROC_EFFECT_STATE_CONFIG, // configuration received/disabled
+ PREPROC_EFFECT_STATE_ACTIVE // active/enabled
+};
+
+// handle on webRTC engine
+typedef void* preproc_fx_handle_t;
+
+typedef struct preproc_session_s preproc_session_t;
+typedef struct preproc_effect_s preproc_effect_t;
+typedef struct preproc_ops_s preproc_ops_t;
+
+// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
+// Function pointer can be null if no action required.
+struct preproc_ops_s {
+ int (* create)(preproc_effect_t *fx);
+ int (* init)(preproc_effect_t *fx);
+ int (* reset)(preproc_effect_t *fx);
+ void (* enable)(preproc_effect_t *fx);
+ void (* disable)(preproc_effect_t *fx);
+ int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
+ int (* get_parameter)(preproc_effect_t *fx, void *param, size_t *size, void *value);
+ int (* set_device)(preproc_effect_t *fx, uint32_t device);
+};
+
+// Effect context
+struct preproc_effect_s {
+ const struct effect_interface_s *itfe;
+ uint32_t procId; // type of pre processor (enum preproc_id)
+ uint32_t state; // current state (enum preproc_effect_state)
+ preproc_session_t *session; // session the effect is on
+ const preproc_ops_t *ops; // effect ops table
+ preproc_fx_handle_t engine; // handle on webRTC engine
+};
+
+// Session context
+struct preproc_session_s {
+ struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
+ uint32_t state; // current state (enum preproc_session_state)
+ int id; // audio session ID
+ int io; // handle of input stream this session is on
+ webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
+ size_t apmFrameCount; // buffer size for webRTC process (10 ms)
+ uint32_t apmSamplingRate; // webRTC APM sampling rate (8/16 or 32 kHz)
+ size_t frameCount; // buffer size before input resampler ( <=> apmFrameCount)
+ uint32_t samplingRate; // sampling rate at effect process interface
+ uint32_t inChannelCount; // input channel count
+ uint32_t outChannelCount; // output channel count
+ uint32_t createdMsk; // bit field containing IDs of crested pre processors
+ uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
+ uint32_t processedMsk; // bit field containing IDs of pre processors already
+ // processed in current round
+ webrtc::AudioFrame *procFrame; // audio frame passed to webRTC AMP ProcessStream()
+ int16_t *inBuf; // input buffer used when resampling
+ size_t inBufSize; // input buffer size in frames
+ size_t framesIn; // number of frames in input buffer
+ SpeexResamplerState *inResampler; // handle on input speex resampler
+ int16_t *outBuf; // output buffer used when resampling
+ size_t outBufSize; // output buffer size in frames
+ size_t framesOut; // number of frames in output buffer
+ SpeexResamplerState *outResampler; // handle on output speex resampler
+ uint32_t revChannelCount; // number of channels on reverse stream
+ uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
+ // with reverse channel
+ uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
+ // channel already processed in current round
+ webrtc::AudioFrame *revFrame; // audio frame passed to webRTC AMP AnalyzeReverseStream()
+ int16_t *revBuf; // reverse channel input buffer
+ size_t revBufSize; // reverse channel input buffer size
+ size_t framesRev; // number of frames in reverse channel input buffer
+ SpeexResamplerState *revResampler; // handle on reverse channel input speex resampler
+};
+
+//------------------------------------------------------------------------------
+// Effect descriptors
+//------------------------------------------------------------------------------
+
+// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
+// as the pre processing effects are not defined by OpenSL ES
+
+// Automatic Gain Control
+static const effect_descriptor_t sAgcDescriptor = {
+ { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+ { 0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Automatic Gain Control",
+ "The Android Open Source Project"
+};
+
+// Acoustic Echo Cancellation
+static const effect_descriptor_t sAecDescriptor = {
+ { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+ { 0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Acoustic Echo Canceler",
+ "The Android Open Source Project"
+};
+
+// Noise suppression
+static const effect_descriptor_t sNsDescriptor = {
+ { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
+ { 0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Noise Suppression",
+ "The Android Open Source Project"
+};
+
+
+static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
+ &sAgcDescriptor,
+ &sAecDescriptor,
+ &sNsDescriptor
+};
+
+//------------------------------------------------------------------------------
+// Helper functions
+//------------------------------------------------------------------------------
+
+const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
+ FX_IID_AGC,
+ FX_IID_AEC,
+ FX_IID_NS
+};
+
+
+const effect_uuid_t * ProcIdToUuid(int procId)
+{
+ if (procId >= PREPROC_NUM_EFFECTS) {
+ return EFFECT_UUID_NULL;
+ }
+ return sUuidToPreProcTable[procId];
+}
+
+uint32_t UuidToProcId(const effect_uuid_t * uuid)
+{
+ size_t i;
+ for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
+ if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
+ break;
+ }
+ }
+ return i;
+}
+
+bool HasReverseStream(uint32_t procId)
+{
+ if (procId == PREPROC_AEC) {
+ return true;
+ }
+ return false;
+}
+
+
+//------------------------------------------------------------------------------
+// Automatic Gain Control (AGC)
+//------------------------------------------------------------------------------
+
+static const int kAgcDefaultTargetLevel = 0;
+static const int kAgcDefaultCompGain = 90;
+static const bool kAgcDefaultLimiter = true;
+
+int AgcInit (preproc_effect_t *effect)
+{
+ LOGV("AgcInit");
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+ agc->set_mode(webrtc::GainControl::kFixedDigital);
+ agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
+ agc->set_compression_gain_db(kAgcDefaultCompGain);
+ agc->enable_limiter(kAgcDefaultLimiter);
+ return 0;
+}
+
+int AgcCreate(preproc_effect_t *effect)
+{
+ webrtc::GainControl *agc = effect->session->apm->gain_control();
+ LOGV("AgcCreate got agc %p", agc);
+ if (agc == NULL) {
+ LOGW("AgcCreate Error");
+ return -ENOMEM;
+ }
+ effect->engine = static_cast<preproc_fx_handle_t>(agc);
+ AgcInit(effect);
+ return 0;
+}
+
+int AgcGetParameter(preproc_effect_t *effect,
+ void *pParam,
+ size_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ t_agc_settings *pProperties = (t_agc_settings *)pValue;
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ case AGC_PARAM_COMP_GAIN:
+ if (*pValueSize < sizeof(int16_t)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ if (*pValueSize < sizeof(bool)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+ case AGC_PARAM_PROPERTIES:
+ if (*pValueSize < sizeof(t_agc_settings)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ LOGW("AgcGetParameter() unknown param %08x", param);
+ status = -EINVAL;
+ break;
+ }
+
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ *(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
+ LOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ *(int16_t *) pValue = (int16_t)(agc->compression_gain_db() * 100);
+ LOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ *(bool *) pValue = (bool)agc->is_limiter_enabled();
+ LOGV("AgcGetParameter() limiter enabled %s",
+ (*(int16_t *) pValue != 0) ? "true" : "false");
+ break;
+ case AGC_PARAM_PROPERTIES:
+ pProperties->targetLevel = (int16_t)(agc->target_level_dbfs() * -100);
+ pProperties->compGain = (int16_t)(agc->compression_gain_db() * 100);
+ pProperties->limiterEnabled = (bool)agc->is_limiter_enabled();
+ break;
+ default:
+ LOGW("AgcGetParameter() unknown param %d", param);
+ status = -EINVAL;
+ break;
+ }
+ return status;
+}
+
+int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ t_agc_settings *pProperties = (t_agc_settings *)pValue;
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ LOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
+ status = agc->set_target_level_dbfs(-(*(int16_t *)pValue / 100));
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ LOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
+ status = agc->set_compression_gain_db(*(int16_t *)pValue / 100);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ LOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
+ status = agc->enable_limiter(*(bool *)pValue);
+ break;
+ case AGC_PARAM_PROPERTIES:
+ LOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
+ pProperties->targetLevel,
+ pProperties->compGain,
+ pProperties->limiterEnabled);
+ status = agc->set_target_level_dbfs(-(pProperties->targetLevel / 100));
+ if (status != 0) break;
+ status = agc->set_compression_gain_db(pProperties->compGain / 100);
+ if (status != 0) break;
+ status = agc->enable_limiter(pProperties->limiterEnabled);
+ break;
+ default:
+ LOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+
+ LOGV("AgcSetParameter() done status %d", status);
+
+ return status;
+}
+
+void AgcEnable(preproc_effect_t *effect)
+{
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+ LOGV("AgcEnable agc %p", agc);
+ agc->Enable(true);
+}
+
+void AgcDisable(preproc_effect_t *effect)
+{
+ LOGV("AgcDisable");
+ webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+ agc->Enable(false);
+}
+
+
+static const preproc_ops_t sAgcOps = {
+ AgcCreate,
+ AgcInit,
+ NULL,
+ AgcEnable,
+ AgcDisable,
+ AgcSetParameter,
+ AgcGetParameter,
+ NULL
+};
+
+
+//------------------------------------------------------------------------------
+// Acoustic Echo Canceler (AEC)
+//------------------------------------------------------------------------------
+
+static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
+ webrtc::EchoControlMobile::kEarpiece;
+static const bool kAecDefaultComfortNoise = true;
+
+int AecInit (preproc_effect_t *effect)
+{
+ LOGV("AecInit");
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ aec->set_routing_mode(kAecDefaultMode);
+ aec->enable_comfort_noise(kAecDefaultComfortNoise);
+ return 0;
+}
+
+int AecCreate(preproc_effect_t *effect)
+{
+ webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
+ LOGV("AecCreate got aec %p", aec);
+ if (aec == NULL) {
+ LOGW("AgcCreate Error");
+ return -ENOMEM;
+ }
+ effect->engine = static_cast<preproc_fx_handle_t>(aec);
+ AecInit (effect);
+ return 0;
+}
+
+int AecGetParameter(preproc_effect_t *effect,
+ void *pParam,
+ size_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+
+ if (*pValueSize < sizeof(uint32_t)) {
+ return -EINVAL;
+ }
+ switch (param) {
+ case AEC_PARAM_ECHO_DELAY:
+ case AEC_PARAM_PROPERTIES:
+ *(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
+ LOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
+ break;
+ default:
+ LOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ return status;
+}
+
+int AecSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ uint32_t value = *(uint32_t *)pValue;
+
+ switch (param) {
+ case AEC_PARAM_ECHO_DELAY:
+ case AEC_PARAM_PROPERTIES:
+ status = effect->session->apm->set_stream_delay_ms(value/1000);
+ LOGV("AecSetParameter() echo delay %d us, status %d", value, status);
+ break;
+ default:
+ LOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ return status;
+}
+
+void AecEnable(preproc_effect_t *effect)
+{
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ LOGV("AecEnable aec %p", aec);
+ aec->Enable(true);
+}
+
+void AecDisable(preproc_effect_t *effect)
+{
+ LOGV("AecDisable");
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ aec->Enable(false);
+}
+
+int AecSetDevice(preproc_effect_t *effect, uint32_t device)
+{
+ LOGV("AecSetDevice %08x", device);
+ webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
+ webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
+
+ switch(device) {
+ case AUDIO_DEVICE_OUT_EARPIECE:
+ mode = webrtc::EchoControlMobile::kEarpiece;
+ break;
+ case AUDIO_DEVICE_OUT_SPEAKER:
+ mode = webrtc::EchoControlMobile::kSpeakerphone;
+ break;
+ case AUDIO_DEVICE_OUT_WIRED_HEADSET:
+ case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+ default:
+ break;
+ }
+ aec->set_routing_mode(mode);
+ return 0;
+}
+
+static const preproc_ops_t sAecOps = {
+ AecCreate,
+ AecInit,
+ NULL,
+ AecEnable,
+ AecDisable,
+ AecSetParameter,
+ AecGetParameter,
+ AecSetDevice
+};
+
+//------------------------------------------------------------------------------
+// Noise Suppression (NS)
+//------------------------------------------------------------------------------
+
+static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
+
+int NsInit (preproc_effect_t *effect)
+{
+ LOGV("NsInit");
+ webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+ ns->set_level(kNsDefaultLevel);
+ return 0;
+}
+
+int NsCreate(preproc_effect_t *effect)
+{
+ webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
+ LOGV("NsCreate got ns %p", ns);
+ if (ns == NULL) {
+ LOGW("AgcCreate Error");
+ return -ENOMEM;
+ }
+ effect->engine = static_cast<preproc_fx_handle_t>(ns);
+ NsInit (effect);
+ return 0;
+}
+
+int NsGetParameter(preproc_effect_t *effect,
+ void *pParam,
+ size_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ return status;
+}
+
+int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ return status;
+}
+
+void NsEnable(preproc_effect_t *effect)
+{
+ webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+ LOGV("NsEnable ns %p", ns);
+ ns->Enable(true);
+}
+
+void NsDisable(preproc_effect_t *effect)
+{
+ LOGV("NsDisable");
+ webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
+ ns->Enable(false);
+}
+
+static const preproc_ops_t sNsOps = {
+ NsCreate,
+ NsInit,
+ NULL,
+ NsEnable,
+ NsDisable,
+ NsSetParameter,
+ NsGetParameter,
+ NULL
+};
+
+
+static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
+ &sAgcOps,
+ &sAecOps,
+ &sNsOps
+};
+
+
+//------------------------------------------------------------------------------
+// Effect functions
+//------------------------------------------------------------------------------
+
+void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
+
+extern "C" const struct effect_interface_s sEffectInterface;
+extern "C" const struct effect_interface_s sEffectInterfaceReverse;
+
+#define BAD_STATE_ABORT(from, to) \
+ LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
+
+int Effect_SetState(preproc_effect_t *effect, uint32_t state)
+{
+ int status = 0;
+ LOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
+ switch(state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ effect->ops->disable(effect);
+ Session_SetProcEnabled(effect->session, effect->procId, false);
+ case PREPROC_EFFECT_STATE_CONFIG:
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_INIT:
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ case PREPROC_EFFECT_STATE_CREATED:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ status = effect->ops->create(effect);
+ break;
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ case PREPROC_EFFECT_STATE_CONFIG:
+ LOGE("Effect_SetState invalid transition");
+ status = -ENOSYS;
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ case PREPROC_EFFECT_STATE_CONFIG:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ LOGE("Effect_SetState invalid transition");
+ status = -ENOSYS;
+ break;
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ effect->ops->disable(effect);
+ Session_SetProcEnabled(effect->session, effect->procId, false);
+ break;
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_CONFIG:
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ switch(effect->state) {
+ case PREPROC_EFFECT_STATE_INIT:
+ case PREPROC_EFFECT_STATE_CREATED:
+ case PREPROC_EFFECT_STATE_ACTIVE:
+ LOGE("Effect_SetState invalid transition");
+ status = -ENOSYS;
+ break;
+ case PREPROC_EFFECT_STATE_CONFIG:
+ effect->ops->enable(effect);
+ Session_SetProcEnabled(effect->session, effect->procId, true);
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ break;
+ default:
+ BAD_STATE_ABORT(effect->state, state);
+ }
+ if (status == 0) {
+ effect->state = state;
+ }
+ return status;
+}
+
+int Effect_Init(preproc_effect_t *effect, uint32_t procId)
+{
+ if (HasReverseStream(procId)) {
+ effect->itfe = &sEffectInterfaceReverse;
+ } else {
+ effect->itfe = &sEffectInterface;
+ }
+ effect->ops = sPreProcOps[procId];
+ effect->procId = procId;
+ effect->state = PREPROC_EFFECT_STATE_INIT;
+ return 0;
+}
+
+int Effect_Create(preproc_effect_t *effect,
+ preproc_session_t *session,
+ effect_handle_t *interface)
+{
+ effect->session = session;
+ *interface = (effect_handle_t)&effect->itfe;
+ return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
+}
+
+int Effect_Release(preproc_effect_t *effect)
+{
+ return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
+}
+
+
+//------------------------------------------------------------------------------
+// Session functions
+//------------------------------------------------------------------------------
+
+#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
+
+static const int kPreprocDefaultSr = 16000;
+static const int kPreProcDefaultCnl = 1;
+
+int Session_Init(preproc_session_t *session)
+{
+ size_t i;
+ int status = 0;
+
+ session->state = PREPROC_SESSION_STATE_INIT;
+ session->id = 0;
+ session->io = 0;
+ session->createdMsk = 0;
+ session->apm = NULL;
+ for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
+ status = Effect_Init(&session->effects[i], i);
+ }
+ return status;
+}
+
+
+extern "C" int Session_CreateEffect(preproc_session_t *session,
+ int32_t procId,
+ effect_handle_t *interface)
+{
+ int status = -ENOMEM;
+
+ LOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
+
+ if (session->createdMsk == 0) {
+ session->apm = webrtc::AudioProcessing::Create(session->io);
+ if (session->apm == NULL) {
+ LOGW("Session_CreateEffect could not get apm engine");
+ goto error;
+ }
+ session->apm->set_sample_rate_hz(kPreprocDefaultSr);
+ session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
+ session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
+ session->procFrame = new webrtc::AudioFrame();
+ if (session->procFrame == NULL) {
+ LOGW("Session_CreateEffect could not allocate audio frame");
+ goto error;
+ }
+ session->revFrame = new webrtc::AudioFrame();
+ if (session->revFrame == NULL) {
+ LOGW("Session_CreateEffect could not allocate reverse audio frame");
+ goto error;
+ }
+ session->apmSamplingRate = kPreprocDefaultSr;
+ session->apmFrameCount = (kPreprocDefaultSr) / 100;
+ session->frameCount = session->apmFrameCount;
+ session->samplingRate = kPreprocDefaultSr;
+ session->inChannelCount = kPreProcDefaultCnl;
+ session->outChannelCount = kPreProcDefaultCnl;
+ session->procFrame->_frequencyInHz = kPreprocDefaultSr;
+ session->procFrame->_audioChannel = kPreProcDefaultCnl;
+ session->revChannelCount = kPreProcDefaultCnl;
+ session->revFrame->_frequencyInHz = kPreprocDefaultSr;
+ session->revFrame->_audioChannel = kPreProcDefaultCnl;
+ session->enabledMsk = 0;
+ session->processedMsk = 0;
+ session->revEnabledMsk = 0;
+ session->revProcessedMsk = 0;
+ session->inResampler = NULL;
+ session->inBuf = NULL;
+ session->inBufSize = 0;
+ session->outResampler = NULL;
+ session->outBuf = NULL;
+ session->outBufSize = 0;
+ session->revResampler = NULL;
+ session->revBuf = NULL;
+ session->revBufSize = 0;
+ }
+ status = Effect_Create(&session->effects[procId], session, interface);
+ if (status < 0) {
+ goto error;
+ }
+ LOGV("Session_CreateEffect OK");
+ session->createdMsk |= (1<<procId);
+ return status;
+
+error:
+ if (session->createdMsk == 0) {
+ delete session->revFrame;
+ session->revFrame = NULL;
+ delete session->procFrame;
+ session->procFrame = NULL;
+ webrtc::AudioProcessing::Destroy(session->apm);
+ session->apm = NULL;
+ }
+ return status;
+}
+
+int Session_ReleaseEffect(preproc_session_t *session,
+ preproc_effect_t *fx)
+{
+ LOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
+ session->createdMsk &= ~(1<<fx->procId);
+ if (session->createdMsk == 0) {
+ webrtc::AudioProcessing::Destroy(session->apm);
+ session->apm = NULL;
+ delete session->procFrame;
+ session->procFrame = NULL;
+ delete session->revFrame;
+ session->revFrame = NULL;
+ if (session->inResampler != NULL) {
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ }
+ if (session->outResampler != NULL) {
+ speex_resampler_destroy(session->outResampler);
+ session->outResampler = NULL;
+ }
+ if (session->revResampler != NULL) {
+ speex_resampler_destroy(session->revResampler);
+ session->revResampler = NULL;
+ }
+ delete session->inBuf;
+ session->inBuf = NULL;
+ delete session->outBuf;
+ session->outBuf = NULL;
+ delete session->revBuf;
+ session->revBuf = NULL;
+
+ session->io = 0;
+ }
+
+ return 0;
+}
+
+
+int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
+{
+ uint32_t sr;
+ uint32_t inCnl = popcount(config->inputCfg.channels);
+ uint32_t outCnl = popcount(config->outputCfg.channels);
+
+ if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
+ config->inputCfg.format != config->outputCfg.format ||
+ config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+ return -EINVAL;
+ }
+
+ LOGV("Session_SetConfig sr %d cnl %08x",
+ config->inputCfg.samplingRate, config->inputCfg.channels);
+ int status;
+
+ // AEC implementation is limited to 16kHz
+ if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
+ session->apmSamplingRate = 32000;
+ } else
+ if (config->inputCfg.samplingRate >= 16000) {
+ session->apmSamplingRate = 16000;
+ } else if (config->inputCfg.samplingRate >= 8000) {
+ session->apmSamplingRate = 8000;
+ }
+ status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
+ if (status < 0) {
+ return -EINVAL;
+ }
+ status = session->apm->set_num_channels(inCnl, outCnl);
+ if (status < 0) {
+ return -EINVAL;
+ }
+ status = session->apm->set_num_reverse_channels(inCnl);
+ if (status < 0) {
+ return -EINVAL;
+ }
+
+ session->samplingRate = config->inputCfg.samplingRate;
+ session->apmFrameCount = session->apmSamplingRate / 100;
+ if (session->samplingRate == session->apmSamplingRate) {
+ session->frameCount = session->apmFrameCount;
+ } else {
+ session->frameCount = (session->apmFrameCount * session->samplingRate) /
+ session->apmSamplingRate + 1;
+ }
+ session->inChannelCount = inCnl;
+ session->outChannelCount = outCnl;
+ session->procFrame->_audioChannel = inCnl;
+ session->procFrame->_frequencyInHz = session->apmSamplingRate;
+
+ session->revChannelCount = inCnl;
+ session->revFrame->_audioChannel = inCnl;
+ session->revFrame->_frequencyInHz = session->apmSamplingRate;
+
+ if (session->inResampler != NULL) {
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ }
+ if (session->outResampler != NULL) {
+ speex_resampler_destroy(session->outResampler);
+ session->outResampler = NULL;
+ }
+ if (session->revResampler != NULL) {
+ speex_resampler_destroy(session->revResampler);
+ session->revResampler = NULL;
+ }
+ if (session->samplingRate != session->apmSamplingRate) {
+ int error;
+ session->inResampler = speex_resampler_init(session->inChannelCount,
+ session->samplingRate,
+ session->apmSamplingRate,
+ RESAMPLER_QUALITY,
+ &error);
+ if (session->inResampler == NULL) {
+ LOGW("Session_SetConfig Cannot create speex resampler: %s",
+ speex_resampler_strerror(error));
+ return -EINVAL;
+ }
+ session->outResampler = speex_resampler_init(session->outChannelCount,
+ session->apmSamplingRate,
+ session->samplingRate,
+ RESAMPLER_QUALITY,
+ &error);
+ if (session->outResampler == NULL) {
+ LOGW("Session_SetConfig Cannot create speex resampler: %s",
+ speex_resampler_strerror(error));
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ return -EINVAL;
+ }
+ session->revResampler = speex_resampler_init(session->inChannelCount,
+ session->samplingRate,
+ session->apmSamplingRate,
+ RESAMPLER_QUALITY,
+ &error);
+ if (session->revResampler == NULL) {
+ LOGW("Session_SetConfig Cannot create speex resampler: %s",
+ speex_resampler_strerror(error));
+ speex_resampler_destroy(session->inResampler);
+ session->inResampler = NULL;
+ speex_resampler_destroy(session->outResampler);
+ session->outResampler = NULL;
+ return -EINVAL;
+ }
+ }
+
+ session->state = PREPROC_SESSION_STATE_CONFIG;
+ return 0;
+}
+
+int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
+{
+ if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
+ config->inputCfg.format != config->outputCfg.format ||
+ config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+ return -EINVAL;
+ }
+
+ LOGV("Session_SetReverseConfig sr %d cnl %08x",
+ config->inputCfg.samplingRate, config->inputCfg.channels);
+
+ if (session->state < PREPROC_SESSION_STATE_CONFIG) {
+ return -ENOSYS;
+ }
+ if (config->inputCfg.samplingRate != session->samplingRate ||
+ config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
+ return -EINVAL;
+ }
+ uint32_t inCnl = popcount(config->inputCfg.channels);
+ int status = session->apm->set_num_reverse_channels(inCnl);
+ if (status < 0) {
+ return -EINVAL;
+ }
+ session->revChannelCount = inCnl;
+ session->revFrame->_audioChannel = inCnl;
+ session->revFrame->_frequencyInHz = session->apmSamplingRate;
+ return 0;
+}
+
+void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
+{
+ if (enabled) {
+ if(session->enabledMsk == 0) {
+ session->framesIn = 0;
+ if (session->inResampler != NULL) {
+ speex_resampler_reset_mem(session->inResampler);
+ }
+ session->framesOut = 0;
+ if (session->outResampler != NULL) {
+ speex_resampler_reset_mem(session->outResampler);
+ }
+ }
+ session->enabledMsk |= (1 << procId);
+ if (HasReverseStream(procId)) {
+ session->framesRev = 0;
+ if (session->revResampler != NULL) {
+ speex_resampler_reset_mem(session->revResampler);
+ }
+ session->revEnabledMsk |= (1 << procId);
+ }
+ } else {
+ session->enabledMsk &= ~(1 << procId);
+ if (HasReverseStream(procId)) {
+ session->revEnabledMsk &= ~(1 << procId);
+ }
+ }
+ LOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
+ procId, enabled, session->enabledMsk, session->revEnabledMsk);
+ session->processedMsk = 0;
+ if (HasReverseStream(procId)) {
+ session->revProcessedMsk = 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Bundle functions
+//------------------------------------------------------------------------------
+
+static int sInitStatus = 1;
+static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
+
+preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
+{
+ size_t i;
+ int free = -1;
+ for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
+ if (sSessions[i].io == ioId) {
+ if (sSessions[i].createdMsk & (1 << procId)) {
+ return NULL;
+ }
+ return &sSessions[i];
+ }
+ }
+ for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
+ if (sSessions[i].io == 0) {
+ sSessions[i].id = sessionId;
+ sSessions[i].io = ioId;
+ return &sSessions[i];
+ }
+ }
+ return NULL;
+}
+
+
+int PreProc_Init() {
+ size_t i;
+ int status = 0;
+
+ if (sInitStatus <= 0) {
+ return sInitStatus;
+ }
+ for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
+ status = Session_Init(&sSessions[i]);
+ }
+ sInitStatus = status;
+ return sInitStatus;
+}
+
+const effect_descriptor_t *PreProc_GetDescriptor(effect_uuid_t *uuid)
+{
+ size_t i;
+ for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
+ if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
+ return sDescriptors[i];
+ }
+ }
+ return NULL;
+}
+
+
+extern "C" {
+
+//------------------------------------------------------------------------------
+// Effect Control Interface Implementation
+//------------------------------------------------------------------------------
+
+int PreProcessingFx_Process(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer)
+{
+ preproc_effect_t * effect = (preproc_effect_t *)self;
+ int status = 0;
+
+ if (effect == NULL){
+ LOGV("PreProcessingFx_Process() ERROR effect == NULL");
+ return -EINVAL;
+ }
+ preproc_session_t * session = (preproc_session_t *)effect->session;
+
+ if (inBuffer == NULL || inBuffer->raw == NULL ||
+ outBuffer == NULL || outBuffer->raw == NULL){
+ LOGW("PreProcessingFx_Process() ERROR bad pointer");
+ return -EINVAL;
+ }
+
+ session->processedMsk |= (1<<effect->procId);
+
+// LOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
+// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
+
+ if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
+ effect->session->processedMsk = 0;
+ size_t framesRq = outBuffer->frameCount;
+ size_t framesWr = 0;
+ if (session->framesOut) {
+ size_t fr = session->framesOut;
+ if (outBuffer->frameCount < fr) {
+ fr = outBuffer->frameCount;
+ }
+ memcpy(outBuffer->s16,
+ session->outBuf,
+ fr * session->outChannelCount * sizeof(int16_t));
+ memcpy(session->outBuf,
+ session->outBuf + fr * session->outChannelCount,
+ (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
+ session->framesOut -= fr;
+ framesWr += fr;
+ }
+ outBuffer->frameCount = framesWr;
+ if (framesWr == framesRq) {
+ inBuffer->frameCount = 0;
+ return 0;
+ }
+
+ if (session->inResampler != NULL) {
+ size_t fr = session->frameCount - session->framesIn;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ if (session->inBufSize < session->framesIn + fr) {
+ session->inBufSize = session->framesIn + fr;
+ session->inBuf = (int16_t *)realloc(session->inBuf,
+ session->inBufSize * session->inChannelCount * sizeof(int16_t));
+ }
+ memcpy(session->inBuf + session->framesIn * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+
+ session->framesIn += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesIn < session->frameCount) {
+ return 0;
+ }
+ size_t frIn = session->framesIn;
+ size_t frOut = session->apmFrameCount;
+ if (session->inChannelCount == 1) {
+ speex_resampler_process_int(session->inResampler,
+ 0,
+ session->inBuf,
+ &frIn,
+ session->procFrame->_payloadData,
+ &frOut);
+ } else {
+ speex_resampler_process_interleaved_int(session->inResampler,
+ session->inBuf,
+ &frIn,
+ session->procFrame->_payloadData,
+ &frOut);
+ }
+ memcpy(session->inBuf,
+ session->inBuf + frIn * session->inChannelCount,
+ (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
+ session->framesIn -= frIn;
+ } else {
+ size_t fr = session->frameCount - session->framesIn;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+ session->framesIn += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesIn < session->frameCount) {
+ return 0;
+ }
+ session->framesIn = 0;
+ }
+ session->procFrame->_payloadDataLengthInSamples =
+ session->apmFrameCount * session->inChannelCount;
+
+ effect->session->apm->ProcessStream(session->procFrame);
+
+ if (session->outBufSize < session->framesOut + session->frameCount) {
+ session->outBufSize = session->framesOut + session->frameCount;
+ session->outBuf = (int16_t *)realloc(session->outBuf,
+ session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ }
+
+ if (session->outResampler != NULL) {
+ size_t frIn = session->apmFrameCount;
+ size_t frOut = session->frameCount;
+ if (session->inChannelCount == 1) {
+ speex_resampler_process_int(session->outResampler,
+ 0,
+ session->procFrame->_payloadData,
+ &frIn,
+ session->outBuf + session->framesOut * session->outChannelCount,
+ &frOut);
+ } else {
+ speex_resampler_process_interleaved_int(session->outResampler,
+ session->procFrame->_payloadData,
+ &frIn,
+ session->outBuf + session->framesOut * session->outChannelCount,
+ &frOut);
+ }
+ session->framesOut += frOut;
+ } else {
+ memcpy(session->outBuf + session->framesOut * session->outChannelCount,
+ session->procFrame->_payloadData,
+ session->frameCount * session->outChannelCount * sizeof(int16_t));
+ session->framesOut += session->frameCount;
+ }
+ size_t fr = session->framesOut;
+ if (framesRq - framesWr < fr) {
+ fr = framesRq - framesWr;
+ }
+ memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
+ session->outBuf,
+ fr * session->outChannelCount * sizeof(int16_t));
+ memcpy(session->outBuf,
+ session->outBuf + fr * session->outChannelCount,
+ (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
+ session->framesOut -= fr;
+ outBuffer->frameCount += fr;
+
+ return 0;
+ } else {
+ return -ENODATA;
+ }
+}
+
+int PreProcessingFx_Command(effect_handle_t self,
+ uint32_t cmdCode,
+ uint32_t cmdSize,
+ void *pCmdData,
+ uint32_t *replySize,
+ void *pReplyData)
+{
+ preproc_effect_t * effect = (preproc_effect_t *) self;
+ int retsize;
+ int status;
+
+ if (effect == NULL){
+ return -EINVAL;
+ }
+
+ //LOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
+
+ switch (cmdCode){
+ case EFFECT_CMD_INIT:
+ if (pReplyData == NULL || *replySize != sizeof(int)){
+ return -EINVAL;
+ }
+ if (effect->ops->init) {
+ effect->ops->init(effect);
+ }
+ *(int *)pReplyData = 0;
+ break;
+
+ case EFFECT_CMD_CONFIGURE:
+ if (pCmdData == NULL||
+ cmdSize != sizeof(effect_config_t)||
+ pReplyData == NULL||
+ *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_CONFIGURE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
+ if (*(int *)pReplyData != 0) {
+ break;
+ }
+ *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+ break;
+
+ case EFFECT_CMD_CONFIGURE_REVERSE:
+ if (pCmdData == NULL||
+ cmdSize != sizeof(effect_config_t)||
+ pReplyData == NULL||
+ *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_CONFIGURE_REVERSE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Session_SetReverseConfig(effect->session,
+ (effect_config_t *)pCmdData);
+ if (*(int *)pReplyData != 0) {
+ break;
+ }
+ break;
+
+ case EFFECT_CMD_RESET:
+ if (effect->ops->reset) {
+ effect->ops->reset(effect);
+ }
+ break;
+
+ case EFFECT_CMD_GET_PARAM:{
+ if (pCmdData == NULL ||
+ cmdSize < (int)sizeof(effect_param_t) ||
+ pReplyData == NULL ||
+ *replySize < (int)sizeof(effect_param_t)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_GET_PARAM: ERROR");
+ return -EINVAL;
+ }
+ effect_param_t *p = (effect_param_t *)pCmdData;
+
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
+
+ p = (effect_param_t *)pReplyData;
+
+ int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
+
+ if (effect->ops->get_parameter) {
+ p->status = effect->ops->get_parameter(effect, p->data,
+ (size_t *)&p->vsize,
+ p->data + voffset);
+ *replySize = sizeof(effect_param_t) + voffset + p->vsize;
+ }
+ } break;
+
+ case EFFECT_CMD_SET_PARAM:{
+ if (pCmdData == NULL||
+ cmdSize < (int)sizeof(effect_param_t) ||
+ pReplyData == NULL ||
+ *replySize != sizeof(int32_t)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_SET_PARAM: ERROR");
+ return -EINVAL;
+ }
+ effect_param_t *p = (effect_param_t *) pCmdData;
+
+ if (p->psize != sizeof(int32_t)){
+ LOGV("PreProcessingFx_Command cmdCode Case: "
+ "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
+ return -EINVAL;
+ }
+ if (effect->ops->set_parameter) {
+ *(int *)pReplyData = effect->ops->set_parameter(effect,
+ (void *)p->data,
+ p->data + p->psize);
+ }
+ } break;
+
+ case EFFECT_CMD_ENABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
+ break;
+
+ case EFFECT_CMD_DISABLE:
+ if (pReplyData == NULL || *replySize != sizeof(int)){
+ LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
+ return -EINVAL;
+ }
+ *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+ break;
+
+ case EFFECT_CMD_SET_DEVICE:
+ case EFFECT_CMD_SET_INPUT_DEVICE:
+ if (pCmdData == NULL ||
+ cmdSize != sizeof(uint32_t)) {
+ LOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
+ return -EINVAL;
+ }
+
+ if (effect->ops->set_device) {
+ effect->ops->set_device(effect, *(uint32_t *)pCmdData);
+ }
+ break;
+
+ case EFFECT_CMD_SET_VOLUME:
+ case EFFECT_CMD_SET_AUDIO_MODE:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+int PreProcessingFx_GetDescriptor(effect_handle_t self,
+ effect_descriptor_t *pDescriptor)
+{
+ preproc_effect_t * effect = (preproc_effect_t *) self;
+
+ if (effect == NULL || pDescriptor == NULL) {
+ return -EINVAL;
+ }
+
+ memcpy(pDescriptor, sDescriptors[effect->procId], sizeof(effect_descriptor_t));
+
+ return 0;
+}
+
+int PreProcessingFx_ProcessReverse(effect_handle_t self,
+ audio_buffer_t *inBuffer,
+ audio_buffer_t *outBuffer)
+{
+ preproc_effect_t * effect = (preproc_effect_t *)self;
+ int status = 0;
+
+ if (effect == NULL){
+ LOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
+ return -EINVAL;
+ }
+ preproc_session_t * session = (preproc_session_t *)effect->session;
+
+ if (inBuffer == NULL || inBuffer->raw == NULL){
+ LOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
+ return -EINVAL;
+ }
+
+ session->revProcessedMsk |= (1<<effect->procId);
+
+// LOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
+// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
+
+
+ if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
+ effect->session->revProcessedMsk = 0;
+ if (session->revResampler != NULL) {
+ size_t fr = session->frameCount - session->framesRev;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ if (session->revBufSize < session->framesRev + fr) {
+ session->revBufSize = session->framesRev + fr;
+ session->revBuf = (int16_t *)realloc(session->revBuf,
+ session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ }
+ memcpy(session->revBuf + session->framesRev * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+
+ session->framesRev += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesRev < session->frameCount) {
+ return 0;
+ }
+ size_t frIn = session->framesRev;
+ size_t frOut = session->apmFrameCount;
+ if (session->inChannelCount == 1) {
+ speex_resampler_process_int(session->revResampler,
+ 0,
+ session->revBuf,
+ &frIn,
+ session->revFrame->_payloadData,
+ &frOut);
+ } else {
+ speex_resampler_process_interleaved_int(session->revResampler,
+ session->revBuf,
+ &frIn,
+ session->revFrame->_payloadData,
+ &frOut);
+ }
+ memcpy(session->revBuf,
+ session->revBuf + frIn * session->inChannelCount,
+ (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
+ session->framesRev -= frIn;
+ } else {
+ size_t fr = session->frameCount - session->framesRev;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
+ inBuffer->s16,
+ fr * session->inChannelCount * sizeof(int16_t));
+ session->framesRev += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesRev < session->frameCount) {
+ return 0;
+ }
+ session->framesRev = 0;
+ }
+ session->revFrame->_payloadDataLengthInSamples =
+ session->apmFrameCount * session->inChannelCount;
+ effect->session->apm->AnalyzeReverseStream(session->revFrame);
+ return 0;
+ } else {
+ return -ENODATA;
+ }
+}
+
+
+// effect_handle_t interface implementation for effect
+const struct effect_interface_s sEffectInterface = {
+ PreProcessingFx_Process,
+ PreProcessingFx_Command,
+ PreProcessingFx_GetDescriptor,
+ NULL
+};
+
+const struct effect_interface_s sEffectInterfaceReverse = {
+ PreProcessingFx_Process,
+ PreProcessingFx_Command,
+ PreProcessingFx_GetDescriptor,
+ PreProcessingFx_ProcessReverse
+};
+
+//------------------------------------------------------------------------------
+// Effect Library Interface Implementation
+//------------------------------------------------------------------------------
+
+int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
+{
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+ if (pNumEffects == NULL) {
+ return -EINVAL;
+ }
+ *pNumEffects = PREPROC_NUM_EFFECTS;
+ return sInitStatus;
+}
+
+int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
+{
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+ if (index >= PREPROC_NUM_EFFECTS) {
+ return -EINVAL;
+ }
+ memcpy(pDescriptor, sDescriptors[index], sizeof(effect_descriptor_t));
+ return 0;
+}
+
+int PreProcessingLib_Create(effect_uuid_t *uuid,
+ int32_t sessionId,
+ int32_t ioId,
+ effect_handle_t *pInterface)
+{
+ LOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
+
+ int status;
+ const effect_descriptor_t *desc;
+ preproc_session_t *session;
+ uint32_t procId;
+
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+ desc = PreProc_GetDescriptor(uuid);
+ if (desc == NULL) {
+ LOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
+ return -EINVAL;
+ }
+ procId = UuidToProcId(&desc->type);
+
+ session = PreProc_GetSession(procId, sessionId, ioId);
+ if (session == NULL) {
+ LOGW("EffectCreate: no more session available");
+ return -EINVAL;
+ }
+
+ status = Session_CreateEffect(session, procId, pInterface);
+
+ if (status < 0 && session->createdMsk == 0) {
+ session->io = 0;
+ }
+ return status;
+}
+
+int PreProcessingLib_Release(effect_handle_t interface)
+{
+ int status;
+ LOGV("EffectRelease start %p", interface);
+ if (PreProc_Init() != 0) {
+ return sInitStatus;
+ }
+
+ preproc_effect_t *fx = (preproc_effect_t *)interface;
+
+ if (fx->session->io == 0) {
+ return -EINVAL;
+ }
+ return Session_ReleaseEffect(fx->session, fx);
+}
+
+int PreProcessingLib_GetDescriptor(effect_uuid_t *uuid,
+ effect_descriptor_t *pDescriptor) {
+
+ if (pDescriptor == NULL || uuid == NULL){
+ return -EINVAL;
+ }
+
+ const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
+ if (desc == NULL) {
+ LOGV("PreProcessingLib_GetDescriptor() not found");
+ return -EINVAL;
+ }
+
+ LOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
+
+ memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
+ return 0;
+}
+
+audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
+ tag : AUDIO_EFFECT_LIBRARY_TAG,
+ version : EFFECT_LIBRARY_API_VERSION,
+ name : "Audio Preprocessing Library",
+ implementor : "The Android Open Source Project",
+ query_num_effects : PreProcessingLib_QueryNumberEffects,
+ query_effect : PreProcessingLib_QueryEffect,
+ create_effect : PreProcessingLib_Create,
+ release_effect : PreProcessingLib_Release,
+ get_descriptor : PreProcessingLib_GetDescriptor
+};
+
+}; // extern "C"
diff --git a/media/libeffects/testlibs/EffectEqualizer.cpp b/media/libeffects/testlibs/EffectEqualizer.cpp
index c2ffce5..b22ebec 100644
--- a/media/libeffects/testlibs/EffectEqualizer.cpp
+++ b/media/libeffects/testlibs/EffectEqualizer.cpp
@@ -736,7 +736,8 @@
const struct effect_interface_s gEqualizerInterface = {
Equalizer_process,
Equalizer_command,
- Equalizer_getDescriptor
+ Equalizer_getDescriptor,
+ NULL
};
diff --git a/media/libeffects/testlibs/EffectReverb.c b/media/libeffects/testlibs/EffectReverb.c
index 02762c9..405f908 100644
--- a/media/libeffects/testlibs/EffectReverb.c
+++ b/media/libeffects/testlibs/EffectReverb.c
@@ -27,7 +27,8 @@
const struct effect_interface_s gReverbInterface = {
Reverb_Process,
Reverb_Command,
- Reverb_GetDescriptor
+ Reverb_GetDescriptor,
+ NULL
};
// Google auxiliary environmental reverb UUID: 1f0ae2e0-4ef7-11df-bc09-0002a5d5c51b
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index dff585f..2160177 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -9,19 +9,12 @@
LOCAL_CFLAGS+= -O2
LOCAL_SHARED_LIBRARIES := \
- libcutils
+ libcutils \
+ libdl
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/soundfx
LOCAL_MODULE:= libvisualizer
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl
-endif
-
-ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_SHARED_LIBRARIES += libdl
-endif
-
LOCAL_C_INCLUDES := \
$(call include-path-for, graphics corecg) \
system/media/audio_effects/include
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index aeebd4d..3c3af8f 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -450,7 +450,8 @@
const struct effect_interface_s gVisualizerInterface = {
Visualizer_process,
Visualizer_command,
- Visualizer_getDescriptor
+ Visualizer_getDescriptor,
+ NULL,
};
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index f7c54fa..7af4a87 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -49,20 +49,12 @@
LOCAL_SHARED_LIBRARIES := \
libui libcutils libutils libbinder libsonivox libicuuc libexpat \
libcamera_client libstagefright_foundation \
- libgui
+ libgui libdl
LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper
LOCAL_MODULE:= libmedia
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl -lpthread
-endif
-
-ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_SHARED_LIBRARIES += libdl
-endif
-
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index c14ee82..b311f35 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -29,6 +29,9 @@
// static
const char *const IStreamListener::kKeyResumeAtPTS = "resume-at-PTS";
+// static
+const char *const IStreamListener::kKeyFormatChange = "format-change";
+
enum {
// IStreamSource
SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index fadad285..ec7d8a0 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -16,10 +16,6 @@
StagefrightPlayer.cpp \
StagefrightRecorder.cpp
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
-LOCAL_LDLIBS += -ldl -lpthread
-endif
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
@@ -32,16 +28,13 @@
libstagefright \
libstagefright_omx \
libstagefright_foundation \
- libgui
+ libgui \
+ libdl
LOCAL_STATIC_LIBRARIES := \
libstagefright_rtsp \
libstagefright_nuplayer \
-ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_SHARED_LIBRARIES += libdl
-endif
-
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 5a5330d..0251baf 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -58,8 +58,10 @@
}
NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
- mLiveSession->disconnect();
- mLiveLooper->stop();
+ if (mLiveSession != NULL) {
+ mLiveSession->disconnect();
+ mLiveLooper->stop();
+ }
}
void NuPlayer::HTTPLiveSource::start() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7cd8b6c..c6fca2c 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -118,9 +118,15 @@
mPlayer->start();
if (mStartupSeekTimeUs >= 0) {
- mPlayer->seekToAsync(mStartupSeekTimeUs);
+ if (mStartupSeekTimeUs == 0) {
+ notifySeekComplete();
+ } else {
+ mPlayer->seekToAsync(mStartupSeekTimeUs);
+ }
+
mStartupSeekTimeUs = -1;
}
+
break;
}
case PLAYING:
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index bbc8a6e..a6a3a18 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -63,8 +63,17 @@
mEOS = true;
break;
} else if (n == INFO_DISCONTINUITY) {
- mTSParser->signalDiscontinuity(
- ATSParser::DISCONTINUITY_SEEK, extra);
+ ATSParser::DiscontinuityType type = ATSParser::DISCONTINUITY_SEEK;
+
+ int32_t formatChange;
+ if (extra != NULL
+ && extra->findInt32(
+ IStreamListener::kKeyFormatChange, &formatChange)
+ && formatChange != 0) {
+ type = ATSParser::DISCONTINUITY_FORMATCHANGE;
+ }
+
+ mTSParser->signalDiscontinuity(type, extra);
} else if (n < 0) {
CHECK_EQ(n, -EWOULDBLOCK);
break;
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 8c4b274..e17e1e8 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -3,8 +3,6 @@
include frameworks/base/media/libstagefright/codecs/common/Config.mk
-BUILD_WITH_SOFTWARE_DECODERS := false
-
LOCAL_SRC_FILES:= \
ACodec.cpp \
AACExtractor.cpp \
@@ -24,7 +22,6 @@
FileSource.cpp \
FLACExtractor.cpp \
HTTPBase.cpp \
- HTTPStream.cpp \
JPEGSource.cpp \
MP3Extractor.cpp \
MPEG2TSWriter.cpp \
@@ -38,13 +35,11 @@
MediaSourceSplitter.cpp \
MetaData.cpp \
NuCachedSource2.cpp \
- NuHTTPDataSource.cpp \
OMXClient.cpp \
OMXCodec.cpp \
OggExtractor.cpp \
SampleIterator.cpp \
SampleTable.cpp \
- ShoutcastSource.cpp \
StagefrightMediaScanner.cpp \
StagefrightMetadataRetriever.cpp \
ThrottledSource.cpp \
@@ -96,26 +91,6 @@
libstagefright_id3 \
libFLAC \
-ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true)
-
-LOCAL_SRC_FILES += \
- ThreadedSource.cpp \
-
-LOCAL_STATIC_LIBRARIES += \
- libstagefright_aacdec \
- libstagefright_amrnbdec \
- libstagefright_amrwbdec \
- libstagefright_avcdec \
- libstagefright_g711dec \
- libstagefright_mp3dec \
- libstagefright_m4vh263dec \
- libstagefright_vorbisdec \
- libstagefright_vpxdec \
- libvpx \
-
-endif
-
-
################################################################################
# The following was shamelessly copied from external/webkit/Android.mk and
@@ -159,10 +134,8 @@
libchromium_net \
libwebcore \
-ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += libstlport
include external/stlport/libstlport.mk
-endif
LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
@@ -175,27 +148,10 @@
libstagefright_enc_common \
libstagefright_avc_common \
libstagefright_foundation \
-
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
- LOCAL_LDLIBS += -lpthread -ldl
- LOCAL_SHARED_LIBRARIES += libdvm
- LOCAL_CPPFLAGS += -DANDROID_SIMULATOR
-endif
-
-ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_SHARED_LIBRARIES += libdl
-endif
-
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
- LOCAL_LDLIBS += -lpthread
-endif
+ libdl
LOCAL_CFLAGS += -Wno-multichar
-ifeq ($(BUILD_WITH_SOFTWARE_DECODERS),true)
- LOCAL_CFLAGS += -DHAVE_SOFTWARE_DECODERS
-endif
-
LOCAL_MODULE:= libstagefright
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 77c25d1..0098537 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -453,7 +453,6 @@
}
void AwesomePlayer::reset() {
- LOGI("reset");
Mutex::Autolock autoLock(mLock);
reset_l();
}
@@ -467,10 +466,8 @@
Playback::STOP, 0);
mDecryptHandle = NULL;
mDrmManagerClient = NULL;
- LOGI("DRM manager client stopped");
}
-
if (mFlags & PLAYING) {
uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
@@ -503,7 +500,6 @@
mPreparedCondition.wait(mLock);
}
- LOGI("cancel player events");
cancelPlayerEvents();
mWVMExtractor.clear();
@@ -890,7 +886,11 @@
CHECK(!(mFlags & AUDIO_RUNNING));
if (mVideoSource == NULL) {
- status_t err = startAudioPlayer_l();
+ // We don't want to post an error notification at this point,
+ // the error returned from MediaPlayer::start() will suffice.
+
+ status_t err = startAudioPlayer_l(
+ false /* sendErrorNotification */);
if (err != OK) {
delete mAudioPlayer;
@@ -940,7 +940,7 @@
return OK;
}
-status_t AwesomePlayer::startAudioPlayer_l() {
+status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) {
CHECK(!(mFlags & AUDIO_RUNNING));
if (mAudioSource == NULL || mAudioPlayer == NULL) {
@@ -958,7 +958,10 @@
true /* sourceAlreadyStarted */);
if (err != OK) {
- notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+ if (sendErrorNotification) {
+ notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+ }
+
return err;
}
@@ -1684,7 +1687,7 @@
if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) {
status_t err = startAudioPlayer_l();
if (err != OK) {
- LOGE("Startung the audio player failed w/ err %d", err);
+ LOGE("Starting the audio player failed w/ err %d", err);
return;
}
}
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
old mode 100644
new mode 100755
index ed8149a..1bc2fb9
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -103,6 +103,10 @@
return OMX_COLOR_Format16bitRGB565;
}
+ if (!strcmp(colorFormat, "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar")) {
+ return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar;
+ }
+
LOGE("Uknown color format (%s), please add it to "
"CameraSource::getColorFormat", colorFormat);
@@ -158,12 +162,10 @@
mVideoSize.width = -1;
mVideoSize.height = -1;
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
mInitCheck = init(camera, proxy, cameraId,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
if (mInitCheck != OK) releaseCamera();
- IPCThreadState::self()->restoreCallingIdentity(token);
}
status_t CameraSource::initCheck() const {
@@ -463,6 +465,22 @@
bool storeMetaDataInVideoBuffers) {
status_t err = OK;
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ err = initWithCameraAccess(camera, proxy, cameraId,
+ videoSize, frameRate,
+ storeMetaDataInVideoBuffers);
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ return err;
+}
+
+status_t CameraSource::initWithCameraAccess(
+ const sp<ICamera>& camera,
+ const sp<ICameraRecordingProxy>& proxy,
+ int32_t cameraId,
+ Size videoSize,
+ int32_t frameRate,
+ bool storeMetaDataInVideoBuffers) {
+ status_t err = OK;
if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
LOGE("Camera connection could not be established.");
@@ -525,6 +543,11 @@
CameraSource::~CameraSource() {
if (mStarted) {
stop();
+ } else if (mInitCheck == OK) {
+ // Camera is initialized but because start() is never called,
+ // the lock on Camera is never released(). This makes sure
+ // Camera's lock is released in this case.
+ releaseCamera();
}
}
@@ -571,6 +594,7 @@
void CameraSource::releaseCamera() {
LOGV("releaseCamera");
if (mCamera != 0) {
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
LOGV("Camera was cold when we started, stopping preview");
mCamera->stopPreview();
@@ -580,6 +604,7 @@
mCamera->unlock();
}
mCamera.clear();
+ IPCThreadState::self()->restoreCallingIdentity(token);
}
if (mCameraRecordingProxy != 0) {
mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index 0d24551..f9d8501 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -24,10 +24,11 @@
#include "include/ChromiumHTTPDataSource.h"
#endif
-#include "include/NuHTTPDataSource.h"
-
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
+
#include <cutils/properties.h>
+#include <cutils/qtaguid.h>
namespace android {
@@ -44,14 +45,12 @@
// static
sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
#if CHROMIUM_AVAILABLE
- char value[PROPERTY_VALUE_MAX];
- if (!property_get("media.stagefright.use-chromium", value, NULL)
- || (strcasecmp("false", value) && strcmp("0", value))) {
return new ChromiumHTTPDataSource(flags);
- } else
#endif
{
- return new NuHTTPDataSource(flags);
+ TRESPASS();
+
+ return NULL;
}
}
@@ -135,4 +134,10 @@
return true;
}
+// static
+void HTTPBase::RegisterSocketUser(int s, uid_t uid) {
+ static const uint32_t kTag = 0xdeadbeef;
+ set_qtaguid(s, kTag, uid);
+}
+
} // namespace android
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
deleted file mode 100644
index d526ebd..0000000
--- a/media/libstagefright/HTTPStream.cpp
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "HTTPStream"
-#include <utils/Log.h>
-
-#include "include/HTTPStream.h"
-
-#include <sys/socket.h>
-
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <media/stagefright/foundation/ADebug.h>
-
-#include <openssl/ssl.h>
-
-namespace android {
-
-// static
-const char *HTTPStream::kStatusKey = ":status:"; // MUST be lowercase.
-
-HTTPStream::HTTPStream()
- : mState(READY),
- mUIDValid(false),
- mSocket(-1),
- mSSLContext(NULL),
- mSSL(NULL) {
-}
-
-HTTPStream::~HTTPStream() {
- disconnect();
-
- if (mSSLContext != NULL) {
- SSL_CTX_free((SSL_CTX *)mSSLContext);
- mSSLContext = NULL;
- }
-}
-
-void HTTPStream::setUID(uid_t uid) {
- mUIDValid = true;
- mUID = uid;
-}
-
-static bool MakeSocketBlocking(int s, bool blocking) {
- // Make socket non-blocking.
- int flags = fcntl(s, F_GETFL, 0);
- if (flags == -1) {
- return false;
- }
-
- if (blocking) {
- flags &= ~O_NONBLOCK;
- } else {
- flags |= O_NONBLOCK;
- }
-
- return fcntl(s, F_SETFL, flags) != -1;
-}
-
-static status_t MyConnect(
- int s, const struct sockaddr *addr, socklen_t addrlen) {
- status_t result = UNKNOWN_ERROR;
-
- MakeSocketBlocking(s, false);
-
- if (connect(s, addr, addrlen) == 0) {
- result = OK;
- } else if (errno != EINPROGRESS) {
- result = -errno;
- } else {
- for (;;) {
- fd_set rs, ws;
- FD_ZERO(&rs);
- FD_ZERO(&ws);
- FD_SET(s, &rs);
- FD_SET(s, &ws);
-
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 100000ll;
-
- int nfds = ::select(s + 1, &rs, &ws, NULL, &tv);
-
- if (nfds < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- result = -errno;
- break;
- }
-
- if (FD_ISSET(s, &ws) && !FD_ISSET(s, &rs)) {
- result = OK;
- break;
- }
-
- if (FD_ISSET(s, &rs) || FD_ISSET(s, &ws)) {
- // Get the pending error.
- int error = 0;
- socklen_t errorLen = sizeof(error);
- if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &errorLen) == -1) {
- // Couldn't get the real error, so report why not.
- result = -errno;
- } else {
- result = -error;
- }
- break;
- }
-
- // Timeout expired. Try again.
- }
- }
-
- MakeSocketBlocking(s, true);
-
- return result;
-}
-
-// Apparently under out linux closing a socket descriptor from one thread
-// will not unblock a pending send/recv on that socket on another thread.
-static ssize_t MySendReceive(
- int s, void *data, size_t size, int flags, bool sendData) {
- ssize_t result = 0;
-
- if (s < 0) {
- return -1;
- }
- while (size > 0) {
- fd_set rs, ws, es;
- FD_ZERO(&rs);
- FD_ZERO(&ws);
- FD_ZERO(&es);
- FD_SET(s, sendData ? &ws : &rs);
- FD_SET(s, &es);
-
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 100000ll;
-
- int nfds = ::select(
- s + 1,
- sendData ? NULL : &rs,
- sendData ? &ws : NULL,
- &es,
- &tv);
-
- if (nfds < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- result = -errno;
- break;
- } else if (nfds == 0) {
- // timeout
-
- continue;
- }
-
- CHECK_EQ(nfds, 1);
-
- ssize_t nbytes =
- sendData ? send(s, data, size, flags) : recv(s, data, size, flags);
-
- if (nbytes < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- result = -errno;
- break;
- } else if (nbytes == 0) {
- result = 0;
- break;
- }
-
- data = (uint8_t *)data + nbytes;
- size -= nbytes;
-
- result = nbytes;
- break;
- }
-
- return result;
-}
-
-static ssize_t MySend(int s, const void *data, size_t size, int flags) {
- return MySendReceive(
- s, const_cast<void *>(data), size, flags, true /* sendData */);
-}
-
-static ssize_t MyReceive(int s, void *data, size_t size, int flags) {
- return MySendReceive(s, data, size, flags, false /* sendData */);
-}
-
-status_t HTTPStream::connect(const char *server, int port, bool https) {
- if (port < 0) {
- port = https ? 443 : 80;
- }
-
- Mutex::Autolock autoLock(mLock);
-
- status_t err = OK;
-
- if (mState == CONNECTED) {
- return ERROR_ALREADY_CONNECTED;
- }
-
- if (port < 0 || port > (int) USHRT_MAX) {
- return UNKNOWN_ERROR;
- }
-
- char service[sizeof("65536")];
- sprintf(service, "%d", port);
- struct addrinfo hints, *ai;
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
- hints.ai_socktype = SOCK_STREAM;
-
- int ret = getaddrinfo(server, service, &hints, &ai);
- if (ret) {
- return ERROR_UNKNOWN_HOST;
- }
-
- CHECK_EQ(mSocket, -1);
-
- mState = CONNECTING;
- status_t res = -1;
- struct addrinfo *tmp;
- for (tmp = ai; tmp; tmp = tmp->ai_next) {
- mSocket = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
- if (mSocket < 0) {
- continue;
- }
-
- if (mUIDValid) {
- RegisterSocketUser(mSocket, mUID);
- }
-
- setReceiveTimeout(30); // Time out reads after 30 secs by default.
-
- int s = mSocket;
-
- mLock.unlock();
-
- res = MyConnect(s, tmp->ai_addr, tmp->ai_addrlen);
-
- mLock.lock();
-
- if (mState != CONNECTING) {
- close(s);
- freeaddrinfo(ai);
- return UNKNOWN_ERROR;
- }
-
- if (res == OK) {
- break;
- }
-
- close(s);
- }
-
- freeaddrinfo(ai);
-
- if (res != OK) {
- close(mSocket);
- mSocket = -1;
-
- mState = READY;
- return res;
- }
-
- if (https) {
- CHECK(mSSL == NULL);
-
- if (mSSLContext == NULL) {
- SSL_library_init();
-
- mSSLContext = SSL_CTX_new(TLSv1_client_method());
-
- if (mSSLContext == NULL) {
- LOGE("failed to create SSL context");
- mState = READY;
- return ERROR_IO;
- }
- }
-
- mSSL = SSL_new((SSL_CTX *)mSSLContext);
-
- if (mSSL == NULL) {
- LOGE("failed to create SSL session");
-
- mState = READY;
- return ERROR_IO;
- }
-
- int res = SSL_set_fd((SSL *)mSSL, mSocket);
-
- if (res == 1) {
- res = SSL_connect((SSL *)mSSL);
- }
-
- if (res != 1) {
- SSL_free((SSL *)mSSL);
- mSSL = NULL;
-
- LOGE("failed to connect over SSL");
- mState = READY;
-
- return ERROR_IO;
- }
- }
-
- mState = CONNECTED;
-
- return OK;
-}
-
-status_t HTTPStream::disconnect() {
- Mutex::Autolock autoLock(mLock);
-
- if (mState != CONNECTED && mState != CONNECTING) {
- return ERROR_NOT_CONNECTED;
- }
-
- if (mSSL != NULL) {
- SSL_shutdown((SSL *)mSSL);
-
- SSL_free((SSL *)mSSL);
- mSSL = NULL;
- }
-
- CHECK(mSocket >= 0);
- close(mSocket);
- mSocket = -1;
-
- mState = READY;
-
- return OK;
-}
-
-status_t HTTPStream::send(const char *data, size_t size) {
- if (mState != CONNECTED) {
- return ERROR_NOT_CONNECTED;
- }
-
- while (size > 0) {
- ssize_t n;
- if (mSSL != NULL) {
- n = SSL_write((SSL *)mSSL, data, size);
-
- if (n < 0) {
- n = -SSL_get_error((SSL *)mSSL, n);
- }
- } else {
- n = MySend(mSocket, data, size, 0);
- }
-
- if (n < 0) {
- disconnect();
-
- return n;
- } else if (n == 0) {
- disconnect();
-
- return ERROR_CONNECTION_LOST;
- }
-
- size -= (size_t)n;
- data += (size_t)n;
- }
-
- return OK;
-}
-
-status_t HTTPStream::send(const char *data) {
- return send(data, strlen(data));
-}
-
-// A certain application spawns a local webserver that sends invalid responses,
-// specifically it terminates header line with only a newline instead of the
-// CRLF (carriage-return followed by newline) required by the HTTP specs.
-// The workaround accepts both behaviours but could potentially break
-// legitimate responses that use a single newline to "fold" headers, which is
-// why it's not yet on by default.
-#define WORKAROUND_FOR_MISSING_CR 1
-
-status_t HTTPStream::receive_line(char *line, size_t size) {
- if (mState != CONNECTED) {
- return ERROR_NOT_CONNECTED;
- }
-
- bool saw_CR = false;
- size_t length = 0;
-
- for (;;) {
- char c;
- ssize_t n;
- if (mSSL != NULL) {
- n = SSL_read((SSL *)mSSL, &c, 1);
-
- if (n < 0) {
- n = -SSL_get_error((SSL *)mSSL, n);
- }
- } else {
- n = MyReceive(mSocket, &c, 1, 0);
- }
-
- if (n < 0) {
- disconnect();
-
- return ERROR_IO;
- } else if (n == 0) {
- disconnect();
-
- return ERROR_CONNECTION_LOST;
- }
-
-#if WORKAROUND_FOR_MISSING_CR
- if (c == '\n') {
- // We have a complete line.
-
- line[saw_CR ? length - 1 : length] = '\0';
- return OK;
- }
-#else
- if (saw_CR && c == '\n') {
- // We have a complete line.
-
- line[length - 1] = '\0';
- return OK;
- }
-#endif
-
- saw_CR = (c == '\r');
-
- if (length + 1 >= size) {
- return ERROR_MALFORMED;
- }
- line[length++] = c;
- }
-}
-
-status_t HTTPStream::receive_header(int *http_status) {
- *http_status = -1;
- mHeaders.clear();
-
- char line[2048];
- status_t err = receive_line(line, sizeof(line));
- if (err != OK) {
- return err;
- }
-
- mHeaders.add(AString(kStatusKey), AString(line));
-
- char *spacePos = strchr(line, ' ');
- if (spacePos == NULL) {
- // Malformed response?
- return UNKNOWN_ERROR;
- }
-
- char *status_start = spacePos + 1;
- char *status_end = status_start;
- while (isdigit(*status_end)) {
- ++status_end;
- }
-
- if (status_end == status_start) {
- // Malformed response, status missing?
- return UNKNOWN_ERROR;
- }
-
- memmove(line, status_start, status_end - status_start);
- line[status_end - status_start] = '\0';
-
- long tmp = strtol(line, NULL, 10);
- if (tmp < 0 || tmp > 999) {
- return UNKNOWN_ERROR;
- }
-
- *http_status = (int)tmp;
-
- for (;;) {
- err = receive_line(line, sizeof(line));
- if (err != OK) {
- return err;
- }
-
- if (*line == '\0') {
- // Empty line signals the end of the header.
- break;
- }
-
- // puts(line);
-
- char *colonPos = strchr(line, ':');
- if (colonPos == NULL) {
- AString key = line;
- key.tolower();
-
- mHeaders.add(key, AString());
- } else {
- char *end_of_key = colonPos;
- while (end_of_key > line && isspace(end_of_key[-1])) {
- --end_of_key;
- }
-
- char *start_of_value = colonPos + 1;
- while (isspace(*start_of_value)) {
- ++start_of_value;
- }
-
- *end_of_key = '\0';
-
- AString key = line;
- key.tolower();
-
- mHeaders.add(key, AString(start_of_value));
- }
- }
-
- return OK;
-}
-
-ssize_t HTTPStream::receive(void *data, size_t size) {
- size_t total = 0;
- while (total < size) {
- ssize_t n;
- if (mSSL != NULL) {
- n = SSL_read((SSL *)mSSL, (char *)data + total, size - total);
-
- if (n < 0) {
- n = -SSL_get_error((SSL *)mSSL, n);
- }
- } else {
- n = MyReceive(mSocket, (char *)data + total, size - total, 0);
- }
-
- if (n < 0) {
- LOGE("recv failed, errno = %d (%s)", (int)n, strerror(-n));
-
- disconnect();
- return (ssize_t)ERROR_IO;
- } else if (n == 0) {
- disconnect();
-
- LOGE("recv failed, server is gone, total received: %d bytes",
- total);
-
- return total == 0 ? (ssize_t)ERROR_CONNECTION_LOST : total;
- }
-
- total += (size_t)n;
- }
-
- return (ssize_t)total;
-}
-
-bool HTTPStream::find_header_value(const AString &key, AString *value) const {
- AString key_lower = key;
- key_lower.tolower();
-
- ssize_t index = mHeaders.indexOfKey(key_lower);
- if (index < 0) {
- value->clear();
- return false;
- }
-
- *value = mHeaders.valueAt(index);
-
- return true;
-}
-
-void HTTPStream::setReceiveTimeout(int seconds) {
- if (seconds < 0) {
- // Disable the timeout.
- seconds = 0;
- }
-
- struct timeval tv;
- tv.tv_usec = 0;
- tv.tv_sec = seconds;
- CHECK_EQ(0, setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)));
-}
-
-// static
-void HTTPStream::RegisterSocketUser(int s, uid_t uid) {
- // Lower bits MUST be 0.
- static const uint64_t kTag = 0xdeadbeef00000000ll;
-
- AString line = StringPrintf("t %d %llu %d", s, kTag, uid);
-
- int fd = open("/proc/net/xt_qtaguid/ctrl", O_WRONLY);
- write(fd, line.c_str(), line.size());
- close(fd);
- fd = -1;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
old mode 100644
new mode 100755
index f075699..8c9ff87
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -246,6 +246,7 @@
mIsFileSizeLimitExplicitlyRequested(false),
mPaused(false),
mStarted(false),
+ mWriterThreadStarted(false),
mOffset(0),
mMdatOffset(0),
mEstimatedMoovBoxSize(0),
@@ -269,6 +270,7 @@
mIsFileSizeLimitExplicitlyRequested(false),
mPaused(false),
mStarted(false),
+ mWriterThreadStarted(false),
mOffset(0),
mMdatOffset(0),
mEstimatedMoovBoxSize(0),
@@ -538,6 +540,9 @@
void MPEG4Writer::stopWriterThread() {
LOGD("Stopping writer thread");
+ if (!mWriterThreadStarted) {
+ return;
+ }
{
Mutex::Autolock autolock(mLock);
@@ -548,6 +553,7 @@
void *dummy;
pthread_join(mThread, &dummy);
+ mWriterThreadStarted = false;
LOGD("Writer thread stopped");
}
@@ -603,10 +609,25 @@
writeInt32(0x40000000); // w
}
+void MPEG4Writer::release() {
+ close(mFd);
+ mFd = -1;
+ mInitCheck = NO_INIT;
+ mStarted = false;
+}
status_t MPEG4Writer::stop() {
if (mInitCheck != OK) {
return OK;
+ } else {
+ if (!mWriterThreadStarted ||
+ !mStarted) {
+ if (mWriterThreadStarted) {
+ stopWriterThread();
+ }
+ release();
+ return OK;
+ }
}
status_t err = OK;
@@ -637,10 +658,7 @@
// Do not write out movie header on error.
if (err != OK) {
- close(mFd);
- mFd = -1;
- mInitCheck = NO_INIT;
- mStarted = false;
+ release();
return err;
}
@@ -688,11 +706,7 @@
CHECK(mBoxes.empty());
- close(mFd);
- mFd = -1;
- mInitCheck = NO_INIT;
- mStarted = false;
-
+ release();
return err;
}
@@ -1415,6 +1429,7 @@
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&mThread, &attr, ThreadWrapper, this);
pthread_attr_destroy(&attr);
+ mWriterThreadStarted = true;
return OK;
}
@@ -1700,7 +1715,10 @@
return ERROR_MALFORMED;
}
}
-
+// FIXME:
+// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
+// and remove #if 0
+#if 0
{
// Check on the profiles
// These profiles requires additional parameter set extensions
@@ -1710,7 +1728,7 @@
return BAD_VALUE;
}
}
-
+#endif
return OK;
}
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
deleted file mode 100644
index 2949767..0000000
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NuHTTPDataSource"
-#include <utils/Log.h>
-
-#include "include/NuHTTPDataSource.h"
-
-#include <cutils/properties.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaErrors.h>
-
-namespace android {
-
-static bool ParseSingleUnsignedLong(
- const char *from, unsigned long *x) {
- char *end;
- *x = strtoul(from, &end, 10);
-
- if (end == from || *end != '\0') {
- return false;
- }
-
- return true;
-}
-
-static bool ParseURL(
- const char *url, String8 *host, unsigned *port,
- String8 *path, bool *https) {
- host->setTo("");
- *port = 0;
- path->setTo("");
-
- size_t hostStart;
- if (!strncasecmp("http://", url, 7)) {
- hostStart = 7;
- *https = false;
- } else if (!strncasecmp("https://", url, 8)) {
- hostStart = 8;
- *https = true;
- } else {
- return false;
- }
-
- const char *slashPos = strchr(&url[hostStart], '/');
-
- if (slashPos == NULL) {
- host->setTo(&url[hostStart]);
- path->setTo("/");
- } else {
- host->setTo(&url[hostStart], slashPos - &url[hostStart]);
- path->setTo(slashPos);
- }
-
- const char *colonPos = strchr(host->string(), ':');
-
- if (colonPos != NULL) {
- unsigned long x;
- if (!ParseSingleUnsignedLong(colonPos + 1, &x) || x >= 65536) {
- return false;
- }
-
- *port = x;
-
- size_t colonOffset = colonPos - host->string();
- String8 tmp(host->string(), colonOffset);
- *host = tmp;
- } else {
- *port = (*https) ? 443 : 80;
- }
-
- return true;
-}
-
-NuHTTPDataSource::NuHTTPDataSource(uint32_t flags)
- : mFlags(flags),
- mState(DISCONNECTED),
- mPort(0),
- mHTTPS(false),
- mOffset(0),
- mContentLength(0),
- mContentLengthValid(false),
- mHasChunkedTransferEncoding(false),
- mChunkDataBytesLeft(0),
- mDecryptHandle(NULL),
- mDrmManagerClient(NULL) {
-}
-
-NuHTTPDataSource::~NuHTTPDataSource() {
- if (mDecryptHandle != NULL) {
- // To release mDecryptHandle
- CHECK(mDrmManagerClient);
- mDrmManagerClient->closeDecryptSession(mDecryptHandle);
- mDecryptHandle = NULL;
- }
-
- if (mDrmManagerClient != NULL) {
- delete mDrmManagerClient;
- mDrmManagerClient = NULL;
- }
-}
-
-status_t NuHTTPDataSource::connect(
- const char *uri,
- const KeyedVector<String8, String8> *overrides,
- off64_t offset) {
- String8 headers;
- MakeFullHeaders(overrides, &headers);
-
- return connect(uri, headers, offset);
-}
-
-status_t NuHTTPDataSource::connect(
- const char *uri,
- const String8 &headers,
- off64_t offset) {
- String8 host, path;
- unsigned port;
-
- mUri = uri;
- mContentType = String8("application/octet-stream");
-
- bool https;
- if (!ParseURL(uri, &host, &port, &path, &https)) {
- return ERROR_MALFORMED;
- }
-
- uid_t uid;
- if (getUID(&uid)) {
- mHTTP.setUID(uid);
- }
-
- return connect(host, port, path, https, headers, offset);
-}
-
-static bool IsRedirectStatusCode(int httpStatus) {
- return httpStatus == 301 || httpStatus == 302
- || httpStatus == 303 || httpStatus == 307;
-}
-
-status_t NuHTTPDataSource::connect(
- const char *host, unsigned port, const char *path,
- bool https,
- const String8 &headers,
- off64_t offset) {
- if (!(mFlags & kFlagIncognito)) {
- LOGI("connect to %s:%u%s @%lld", host, port, path, offset);
- } else {
- LOGI("connect to <URL suppressed> @%lld", offset);
- }
-
- bool needsToReconnect = true;
-
- if (mState == CONNECTED && host == mHost && port == mPort
- && https == mHTTPS && offset == mOffset) {
- if (mContentLengthValid && mOffset == mContentLength) {
- LOGI("Didn't have to reconnect, old one's still good.");
- needsToReconnect = false;
- }
- }
-
- mHost = host;
- mPort = port;
- mPath = path;
- mHTTPS = https;
- mHeaders = headers;
-
- status_t err = OK;
-
- mState = CONNECTING;
-
- if (needsToReconnect) {
- mHTTP.disconnect();
- err = mHTTP.connect(host, port, https);
- }
-
- if (err != OK) {
- mState = DISCONNECTED;
- } else if (mState != CONNECTING) {
- err = UNKNOWN_ERROR;
- } else {
- mState = CONNECTED;
-
- mOffset = offset;
- mContentLength = 0;
- mContentLengthValid = false;
-
- String8 request("GET ");
- request.append(mPath);
- request.append(" HTTP/1.1\r\n");
- request.append("Host: ");
- request.append(mHost);
- if (mPort != 80) {
- request.append(StringPrintf(":%u", mPort).c_str());
- }
- request.append("\r\n");
-
- if (offset != 0) {
- char rangeHeader[128];
- sprintf(rangeHeader, "Range: bytes=%lld-\r\n", offset);
- request.append(rangeHeader);
- }
-
- request.append(mHeaders);
- request.append("\r\n");
-
- int httpStatus;
- if ((err = mHTTP.send(request.string(), request.size())) != OK
- || (err = mHTTP.receive_header(&httpStatus)) != OK) {
- mHTTP.disconnect();
- mState = DISCONNECTED;
- return err;
- }
-
- if (IsRedirectStatusCode(httpStatus)) {
- AString value;
- CHECK(mHTTP.find_header_value("Location", &value));
-
- mState = DISCONNECTED;
-
- mHTTP.disconnect();
-
- return connect(value.c_str(), headers, offset);
- }
-
- if (httpStatus < 200 || httpStatus >= 300) {
- mState = DISCONNECTED;
- mHTTP.disconnect();
-
- return ERROR_IO;
- }
-
- mHasChunkedTransferEncoding = false;
-
- {
- AString value;
- if (mHTTP.find_header_value("Transfer-Encoding", &value)) {
- // We don't currently support any transfer encodings but
- // chunked.
-
- if (!strcasecmp(value.c_str(), "chunked")) {
- LOGI("Chunked transfer encoding applied.");
- mHasChunkedTransferEncoding = true;
- mChunkDataBytesLeft = 0;
- } else {
- mState = DISCONNECTED;
- mHTTP.disconnect();
-
- LOGE("We don't support '%s' transfer encoding.", value.c_str());
-
- return ERROR_UNSUPPORTED;
- }
- }
- }
-
- {
- AString value;
- if (mHTTP.find_header_value("Content-Type", &value)) {
- mContentType = String8(value.c_str());
- } else {
- mContentType = String8("application/octet-stream");
- }
- }
-
- applyTimeoutResponse();
-
- if (offset == 0) {
- AString value;
- unsigned long x;
- if (mHTTP.find_header_value(AString("Content-Length"), &value)
- && ParseSingleUnsignedLong(value.c_str(), &x)) {
- mContentLength = (off64_t)x;
- mContentLengthValid = true;
- } else {
- LOGW("Server did not give us the content length!");
- }
- } else {
- if (httpStatus != 206 /* Partial Content */) {
- // We requested a range but the server didn't support that.
- LOGE("We requested a range but the server didn't "
- "support that.");
- return ERROR_UNSUPPORTED;
- }
-
- AString value;
- unsigned long x;
- if (mHTTP.find_header_value(AString("Content-Range"), &value)) {
- const char *slashPos = strchr(value.c_str(), '/');
- if (slashPos != NULL
- && ParseSingleUnsignedLong(slashPos + 1, &x)) {
- mContentLength = x;
- mContentLengthValid = true;
- }
- }
- }
- }
-
- return err;
-}
-
-void NuHTTPDataSource::disconnect() {
- if (mState == CONNECTING || mState == CONNECTED) {
- mHTTP.disconnect();
- }
- mState = DISCONNECTED;
-}
-
-status_t NuHTTPDataSource::initCheck() const {
- return mState == CONNECTED ? OK : NO_INIT;
-}
-
-ssize_t NuHTTPDataSource::internalRead(void *data, size_t size) {
- if (!mHasChunkedTransferEncoding) {
- return mHTTP.receive(data, size);
- }
-
- if (mChunkDataBytesLeft < 0) {
- return 0;
- } else if (mChunkDataBytesLeft == 0) {
- char line[1024];
- status_t err = mHTTP.receive_line(line, sizeof(line));
-
- if (err != OK) {
- return err;
- }
-
- LOGV("line = '%s'", line);
-
- char *end;
- unsigned long n = strtoul(line, &end, 16);
-
- if (end == line || (*end != ';' && *end != '\0')) {
- LOGE("malformed HTTP chunk '%s'", line);
- return ERROR_MALFORMED;
- }
-
- mChunkDataBytesLeft = n;
- LOGV("chunk data size = %lu", n);
-
- if (mChunkDataBytesLeft == 0) {
- mChunkDataBytesLeft = -1;
- return 0;
- }
-
- // fall through
- }
-
- if (size > (size_t)mChunkDataBytesLeft) {
- size = mChunkDataBytesLeft;
- }
-
- ssize_t n = mHTTP.receive(data, size);
-
- if (n < 0) {
- return n;
- }
-
- mChunkDataBytesLeft -= (size_t)n;
-
- if (mChunkDataBytesLeft == 0) {
- char line[1024];
- status_t err = mHTTP.receive_line(line, sizeof(line));
-
- if (err != OK) {
- return err;
- }
-
- if (line[0] != '\0') {
- LOGE("missing HTTP chunk terminator.");
- return ERROR_MALFORMED;
- }
- }
-
- return n;
-}
-
-ssize_t NuHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
- LOGV("readAt offset %ld, size %d", offset, size);
-
- Mutex::Autolock autoLock(mLock);
-
- if (offset != mOffset) {
- String8 host = mHost;
- String8 path = mPath;
- String8 headers = mHeaders;
- status_t err = connect(host, mPort, path, mHTTPS, headers, offset);
-
- if (err != OK) {
- return err;
- }
- }
-
- if (mContentLengthValid) {
- size_t avail =
- (offset >= mContentLength) ? 0 : mContentLength - offset;
-
- if (size > avail) {
- size = avail;
- }
- }
-
- size_t numBytesRead = 0;
- while (numBytesRead < size) {
- int64_t startTimeUs = ALooper::GetNowUs();
-
- ssize_t n =
- internalRead((uint8_t *)data + numBytesRead, size - numBytesRead);
-
- if (n < 0) {
- if (numBytesRead == 0 || mContentLengthValid) {
- return n;
- }
-
- // If there was an error we want to at least return the data
- // we've already successfully read. The next call to read will
- // then return the error.
- n = 0;
- }
-
- int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
- addBandwidthMeasurement(n, delayUs);
-
- numBytesRead += (size_t)n;
-
- if (n == 0) {
- if (mContentLengthValid) {
- // We know the content length and made sure not to read beyond
- // it and yet the server closed the connection on us.
- return ERROR_IO;
- }
-
- break;
- }
- }
-
- mOffset += numBytesRead;
-
- return numBytesRead;
-}
-
-status_t NuHTTPDataSource::getSize(off64_t *size) {
- *size = 0;
-
- if (mState != CONNECTED) {
- return ERROR_IO;
- }
-
- if (mContentLengthValid) {
- *size = mContentLength;
- return OK;
- }
-
- return ERROR_UNSUPPORTED;
-}
-
-uint32_t NuHTTPDataSource::flags() {
- return kWantsPrefetching | kIsHTTPBasedSource;
-}
-
-// static
-void NuHTTPDataSource::MakeFullHeaders(
- const KeyedVector<String8, String8> *overrides, String8 *headers) {
- headers->setTo("");
-
- headers->append("User-Agent: stagefright/1.1 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- headers->append(value);
- headers->append(")\r\n");
-
- if (overrides == NULL) {
- return;
- }
-
- for (size_t i = 0; i < overrides->size(); ++i) {
- String8 line;
- line.append(overrides->keyAt(i));
- line.append(": ");
- line.append(overrides->valueAt(i));
- line.append("\r\n");
-
- headers->append(line);
- }
-}
-
-void NuHTTPDataSource::applyTimeoutResponse() {
- AString timeout;
- if (mHTTP.find_header_value("X-SocketTimeout", &timeout)) {
- const char *s = timeout.c_str();
- char *end;
- long tmp = strtol(s, &end, 10);
- if (end == s || *end != '\0') {
- LOGW("Illegal X-SocketTimeout value given.");
- return;
- }
-
- LOGI("overriding default timeout, new timeout is %ld seconds", tmp);
- mHTTP.setReceiveTimeout(tmp);
- }
-}
-
-sp<DecryptHandle> NuHTTPDataSource::DrmInitialization() {
- if (mDrmManagerClient == NULL) {
- mDrmManagerClient = new DrmManagerClient();
- }
-
- if (mDrmManagerClient == NULL) {
- return NULL;
- }
-
- if (mDecryptHandle == NULL) {
- /* Note if redirect occurs, mUri is the redirect uri instead of the
- * original one
- */
- mDecryptHandle = mDrmManagerClient->openDecryptSession(mUri);
- }
-
- if (mDecryptHandle == NULL) {
- delete mDrmManagerClient;
- mDrmManagerClient = NULL;
- }
-
- return mDecryptHandle;
-}
-
-void NuHTTPDataSource::getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client) {
- handle = mDecryptHandle;
-
- *client = mDrmManagerClient;
-}
-
-String8 NuHTTPDataSource::getUri() {
- return mUri;
-}
-
-String8 NuHTTPDataSource::getMIMEType() const {
- return mContentType;
-}
-
-} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
old mode 100644
new mode 100755
index 06363ee..4f8336e
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,20 +18,11 @@
#define LOG_TAG "OMXCodec"
#include <utils/Log.h>
-#include "include/AACDecoder.h"
#include "include/AACEncoder.h"
-#include "include/AMRNBDecoder.h"
#include "include/AMRNBEncoder.h"
-#include "include/AMRWBDecoder.h"
#include "include/AMRWBEncoder.h"
-#include "include/AVCDecoder.h"
#include "include/AVCEncoder.h"
-#include "include/G711Decoder.h"
-#include "include/M4vH263Decoder.h"
#include "include/M4vH263Encoder.h"
-#include "include/MP3Decoder.h"
-#include "include/VorbisDecoder.h"
-#include "include/VPXDecoder.h"
#include "include/ESDS.h"
@@ -53,10 +44,6 @@
#include <OMX_Audio.h>
#include <OMX_Component.h>
-#if HAVE_SOFTWARE_DECODERS
-#include "include/ThreadedSource.h"
-#endif
-
#include "include/avc_utils.h"
namespace android {
@@ -79,24 +66,6 @@
FACTORY_CREATE_ENCODER(AVCEncoder)
FACTORY_CREATE_ENCODER(M4vH263Encoder)
-#if HAVE_SOFTWARE_DECODERS
-
-#define FACTORY_CREATE(name) \
-static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
- return new name(source); \
-}
-
-FACTORY_CREATE(AMRNBDecoder)
-FACTORY_CREATE(AMRWBDecoder)
-FACTORY_CREATE(AACDecoder)
-FACTORY_CREATE(AVCDecoder)
-FACTORY_CREATE(G711Decoder)
-FACTORY_CREATE(MP3Decoder)
-FACTORY_CREATE(M4vH263Decoder)
-FACTORY_CREATE(VorbisDecoder)
-FACTORY_CREATE(VPXDecoder)
-#endif
-
static sp<MediaSource> InstantiateSoftwareEncoder(
const char *name, const sp<MediaSource> &source,
const sp<MetaData> &meta) {
@@ -122,40 +91,6 @@
return NULL;
}
-static sp<MediaSource> InstantiateSoftwareCodec(
- const char *name, const sp<MediaSource> &source) {
-#if HAVE_SOFTWARE_DECODERS
- struct FactoryInfo {
- const char *name;
- sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &);
- };
-
- static const FactoryInfo kFactoryInfo[] = {
- FACTORY_REF(AMRNBDecoder)
- FACTORY_REF(AMRWBDecoder)
- FACTORY_REF(AACDecoder)
- FACTORY_REF(AVCDecoder)
- FACTORY_REF(G711Decoder)
- FACTORY_REF(MP3Decoder)
- FACTORY_REF(M4vH263Decoder)
- FACTORY_REF(VorbisDecoder)
- FACTORY_REF(VPXDecoder)
- };
- for (size_t i = 0;
- i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
- if (!strcmp(name, kFactoryInfo[i].name)) {
- if (!strcmp(name, "VPXDecoder")) {
- return new ThreadedSource(
- (*kFactoryInfo[i].CreateFunc)(source));
- }
- return (*kFactoryInfo[i].CreateFunc)(source);
- }
- }
-#endif
-
- return NULL;
-}
-
#undef FACTORY_REF
#undef FACTORY_CREATE
@@ -163,23 +98,17 @@
{ MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
// { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
{ MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" },
- { MEDIA_MIMETYPE_AUDIO_MPEG, "MP3Decoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amr.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBDecoder" },
// { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBDecoder" },
// { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.decoder" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "AACDecoder" },
{ MEDIA_MIMETYPE_AUDIO_G711_ALAW, "OMX.google.g711.alaw.decoder" },
- { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "G711Decoder" },
{ MEDIA_MIMETYPE_AUDIO_G711_MLAW, "OMX.google.g711.mlaw.decoder" },
- { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "G711Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.DECODER" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" },
@@ -187,14 +116,12 @@
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.google.mpeg4.decoder" },
- { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.DECODER" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.google.h263.decoder" },
- { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.DECODER" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" },
@@ -203,11 +130,8 @@
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.SEC.AVC.Decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.h264.decoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.google.avc.decoder" },
- { MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },
{ MEDIA_MIMETYPE_AUDIO_VORBIS, "OMX.google.vorbis.decoder" },
- { MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" },
{ MEDIA_MIMETYPE_VIDEO_VPX, "OMX.google.vpx.decoder" },
- { MEDIA_MIMETYPE_VIDEO_VPX, "VPXDecoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG2, "OMX.Nvidia.mpeg2v.decode" },
};
@@ -218,18 +142,21 @@
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" },
+ { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.encoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Encoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Encoder" },
+ { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.encoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Encoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Encoder" },
+ { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.H264E" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
@@ -393,7 +320,17 @@
if (!strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.DECODER")) {
quirks |= kRequiresAllocateBufferOnInputPorts;
quirks |= kRequiresAllocateBufferOnOutputPorts;
- } else if (!strncmp(componentName, "OMX.TI.", 7)) {
+ }
+
+ // FIXME:
+ // Remove the quirks after the work is done.
+ else if (!strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.MPEG4E") ||
+ !strcmp(componentName, "OMX.TI.DUCATI1.VIDEO.H264E")) {
+
+ quirks |= kRequiresAllocateBufferOnInputPorts;
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
+ }
+ else if (!strncmp(componentName, "OMX.TI.", 7)) {
// Apparently I must not use OMX_UseBuffer on either input or
// output ports on any of the TI components or quote:
// "(I) may have unexpected problem (sic) which can be timing related
@@ -505,14 +442,15 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
componentName = matchingCodecs[i].string();
- sp<MediaSource> softwareCodec = createEncoder?
- InstantiateSoftwareEncoder(componentName, source, meta):
- InstantiateSoftwareCodec(componentName, source);
+ if (createEncoder) {
+ sp<MediaSource> softwareCodec =
+ InstantiateSoftwareEncoder(componentName, source, meta);
- if (softwareCodec != NULL) {
- LOGV("Successfully allocated software codec '%s'", componentName);
+ if (softwareCodec != NULL) {
+ LOGV("Successfully allocated software codec '%s'", componentName);
- return softwareCodec;
+ return softwareCodec;
+ }
}
LOGV("Attempting to allocate OMX node '%s'", componentName);
@@ -887,6 +825,7 @@
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420SemiPlanar:
+ case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
return (width * height * 3) / 2;
default:
@@ -910,6 +849,7 @@
}
}
+
// Check whether the target color format is supported.
return isColorFormatSupported(*colorFormat, kPortIndexInput);
}
@@ -1032,6 +972,11 @@
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
video_def->xFramerate = 0; // No need for output port
+ // FIXME:
+ // Revmoe this workaround after work is done.
+ if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) {
+ video_def->xFramerate = (frameRate << 16);
+ }
video_def->nBitrate = bitRate; // Q16 format
video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
@@ -1304,6 +1249,12 @@
h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile);
h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
+ // FIXME:
+ // Remove the workaround after the work in done.
+ if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) {
+ h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
+ }
+
if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
h264type.nSliceHeaderSpacing = 0;
h264type.bUseHadamard = OMX_TRUE;
@@ -3588,7 +3539,7 @@
}
status_t OMXCodec::stop() {
- CODEC_LOGI("stop mState=%d", mState);
+ CODEC_LOGV("stop mState=%d", mState);
Mutex::Autolock autoLock(mLock);
@@ -3650,7 +3601,6 @@
mLeftOverBuffer = NULL;
}
- CODEC_LOGI("stopping video source");
mSource->stop();
CODEC_LOGI("stopped in state %d", mState);
@@ -4380,36 +4330,26 @@
status_t QueryCodecs(
const sp<IOMX> &omx,
- const char *mime, bool queryDecoders,
+ const char *mime, bool queryDecoders, bool hwCodecOnly,
Vector<CodecCapabilities> *results) {
+ Vector<String8> matchingCodecs;
results->clear();
- for (int index = 0;; ++index) {
- const char *componentName;
+ OMXCodec::findMatchingCodecs(mime,
+ !queryDecoders /*createEncoder*/,
+ NULL /*matchComponentName*/,
+ hwCodecOnly ? OMXCodec::kHardwareCodecsOnly : 0 /*flags*/,
+ &matchingCodecs);
- if (!queryDecoders) {
- componentName = GetCodec(
- kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
- } else {
- componentName = GetCodec(
- kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
- }
-
- if (!componentName) {
- return OK;
- }
+ for (size_t c = 0; c < matchingCodecs.size(); c++) {
+ const char *componentName = matchingCodecs.itemAt(c).string();
if (strncmp(componentName, "OMX.", 4)) {
// Not an OpenMax component but a software codec.
-#if HAVE_SOFTWARE_DECODERS
results->push();
CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
caps->mComponentName = componentName;
-#endif
-
continue;
}
@@ -4464,6 +4404,8 @@
CHECK_EQ(omx->freeNode(node), (status_t)OK);
}
+
+ return OK;
}
void OMXCodec::restorePatchedDataPointer(BufferInfo *info) {
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
deleted file mode 100644
index 783f2d0..0000000
--- a/media/libstagefright/ShoutcastSource.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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 "include/HTTPStream.h"
-
-#include <stdlib.h>
-
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/ShoutcastSource.h>
-
-namespace android {
-
-ShoutcastSource::ShoutcastSource(HTTPStream *http)
- : mHttp(http),
- mMetaDataOffset(0),
- mBytesUntilMetaData(0),
- mGroup(NULL),
- mStarted(false) {
- AString metaint;
- if (mHttp->find_header_value("icy-metaint", &metaint)) {
- char *end;
- const char *start = metaint.c_str();
- mMetaDataOffset = strtol(start, &end, 10);
- CHECK(end > start && *end == '\0');
- CHECK(mMetaDataOffset > 0);
-
- mBytesUntilMetaData = mMetaDataOffset;
- }
-}
-
-ShoutcastSource::~ShoutcastSource() {
- if (mStarted) {
- stop();
- }
-
- delete mHttp;
- mHttp = NULL;
-}
-
-status_t ShoutcastSource::start(MetaData *) {
- CHECK(!mStarted);
-
- mGroup = new MediaBufferGroup;
- mGroup->add_buffer(new MediaBuffer(4096)); // XXX
-
- mStarted = true;
-
- return OK;
-}
-
-status_t ShoutcastSource::stop() {
- CHECK(mStarted);
-
- delete mGroup;
- mGroup = NULL;
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> ShoutcastSource::getFormat() {
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
- meta->setInt32(kKeySampleRate, 44100);
- meta->setInt32(kKeyChannelCount, 2); // XXX
-
- return meta;
-}
-
-status_t ShoutcastSource::read(
- MediaBuffer **out, const ReadOptions *options) {
- CHECK(mStarted);
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- return ERROR_UNSUPPORTED;
- }
-
- MediaBuffer *buffer;
- status_t err = mGroup->acquire_buffer(&buffer);
- if (err != OK) {
- return err;
- }
-
- *out = buffer;
-
- size_t num_bytes = buffer->size();
- if (mMetaDataOffset > 0 && num_bytes > mBytesUntilMetaData) {
- num_bytes = mBytesUntilMetaData;
- }
-
- ssize_t n = mHttp->receive(buffer->data(), num_bytes);
-
- if (n <= 0) {
- return (status_t)n;
- }
-
- buffer->set_range(0, n);
-
- mBytesUntilMetaData -= (size_t)n;
-
- if (mBytesUntilMetaData == 0) {
- unsigned char num_16_byte_blocks = 0;
- n = mHttp->receive((char *)&num_16_byte_blocks, 1);
- CHECK_EQ(n, 1);
-
- char meta[255 * 16];
- size_t meta_size = num_16_byte_blocks * 16;
- size_t meta_length = 0;
- while (meta_length < meta_size) {
- n = mHttp->receive(&meta[meta_length], meta_size - meta_length);
- if (n <= 0) {
- return (status_t)n;
- }
-
- meta_length += (size_t) n;
- }
-
- while (meta_length > 0 && meta[meta_length - 1] == '\0') {
- --meta_length;
- }
-
- if (meta_length > 0) {
- // Technically we should probably attach this meta data to the
- // next buffer. XXX
- buffer->meta_data()->setData('shou', 'shou', meta, meta_length);
- }
-
- mBytesUntilMetaData = mMetaDataOffset;
- }
-
- return OK;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/ThreadedSource.cpp b/media/libstagefright/ThreadedSource.cpp
deleted file mode 100644
index 38c6e2d..0000000
--- a/media/libstagefright/ThreadedSource.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ThreadedSource"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "include/ThreadedSource.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-static const size_t kMaxQueueSize = 2;
-
-ThreadedSource::ThreadedSource(const sp<MediaSource> &source)
- : mSource(source),
- mReflector(new AHandlerReflector<ThreadedSource>(this)),
- mLooper(new ALooper),
- mStarted(false) {
- mLooper->registerHandler(mReflector);
-}
-
-ThreadedSource::~ThreadedSource() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t ThreadedSource::start(MetaData *params) {
- CHECK(!mStarted);
-
- status_t err = mSource->start(params);
-
- if (err != OK) {
- return err;
- }
-
- mFinalResult = OK;
- mSeekTimeUs = -1;
- mDecodePending = false;
-
- Mutex::Autolock autoLock(mLock);
- postDecodeMore_l();
-
- CHECK_EQ(mLooper->start(), (status_t)OK);
-
- mStarted = true;
-
- return OK;
-}
-
-status_t ThreadedSource::stop() {
- CHECK(mStarted);
-
- CHECK_EQ(mLooper->stop(), (status_t)OK);
-
- Mutex::Autolock autoLock(mLock);
- clearQueue_l();
-
- status_t err = mSource->stop();
-
- mStarted = false;
-
- return err;
-}
-
-sp<MetaData> ThreadedSource::getFormat() {
- return mSource->getFormat();
-}
-
-status_t ThreadedSource::read(
- MediaBuffer **buffer, const ReadOptions *options) {
- *buffer = NULL;
-
- Mutex::Autolock autoLock(mLock);
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- int32_t seekComplete = 0;
-
- sp<AMessage> msg = new AMessage(kWhatSeek, mReflector->id());
- msg->setInt64("timeUs", seekTimeUs);
- msg->setInt32("mode", seekMode);
- msg->setPointer("complete", &seekComplete);
- msg->post();
-
- while (!seekComplete) {
- mCondition.wait(mLock);
- }
- }
-
- while (mQueue.empty() && mFinalResult == OK) {
- mCondition.wait(mLock);
- }
-
- if (!mQueue.empty()) {
- *buffer = *mQueue.begin();
- mQueue.erase(mQueue.begin());
-
- if (mFinalResult == OK) {
- postDecodeMore_l();
- }
-
- return OK;
- }
-
- return mFinalResult;
-}
-
-void ThreadedSource::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatSeek:
- {
- CHECK(msg->findInt64("timeUs", &mSeekTimeUs));
- CHECK_GE(mSeekTimeUs, 0ll);
-
- int32_t x;
- CHECK(msg->findInt32("mode", &x));
- mSeekMode = (ReadOptions::SeekMode)x;
-
- int32_t *seekComplete;
- CHECK(msg->findPointer("complete", (void **)&seekComplete));
-
- Mutex::Autolock autoLock(mLock);
- clearQueue_l();
- mFinalResult = OK;
-
- *seekComplete = 1;
- mCondition.signal();
-
- postDecodeMore_l();
- break;
- }
-
- case kWhatDecodeMore:
- {
- {
- Mutex::Autolock autoLock(mLock);
- mDecodePending = false;
-
- if (mQueue.size() == kMaxQueueSize) {
- break;
- }
- }
-
- MediaBuffer *buffer;
- ReadOptions options;
- if (mSeekTimeUs >= 0) {
- options.setSeekTo(mSeekTimeUs, mSeekMode);
- mSeekTimeUs = -1ll;
- }
- status_t err = mSource->read(&buffer, &options);
-
- Mutex::Autolock autoLock(mLock);
-
- if (err != OK) {
- mFinalResult = err;
- } else {
- mQueue.push_back(buffer);
-
- if (mQueue.size() < kMaxQueueSize) {
- postDecodeMore_l();
- }
- }
-
- mCondition.signal();
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
-}
-
-void ThreadedSource::postDecodeMore_l() {
- if (mDecodePending) {
- return;
- }
-
- mDecodePending = true;
- (new AMessage(kWhatDecodeMore, mReflector->id()))->post();
-}
-
-void ThreadedSource::clearQueue_l() {
- while (!mQueue.empty()) {
- MediaBuffer *buffer = *mQueue.begin();
- mQueue.erase(mQueue.begin());
-
- buffer->release();
- buffer = NULL;
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/libstagefright/XINGSeeker.cpp
index 0d0d6c2..2091381 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/libstagefright/XINGSeeker.cpp
@@ -24,8 +24,8 @@
static bool parse_xing_header(
const sp<DataSource> &source, off64_t first_frame_pos,
int32_t *frame_number = NULL, int32_t *byte_number = NULL,
- char *table_of_contents = NULL, int32_t *quality_indicator = NULL,
- int64_t *duration = NULL);
+ unsigned char *table_of_contents = NULL,
+ int32_t *quality_indicator = NULL, int64_t *duration = NULL);
// static
sp<XINGSeeker> XINGSeeker::CreateFromSource(
@@ -94,7 +94,7 @@
static bool parse_xing_header(
const sp<DataSource> &source, off64_t first_frame_pos,
int32_t *frame_number, int32_t *byte_number,
- char *table_of_contents, int32_t *quality_indicator,
+ unsigned char *table_of_contents, int32_t *quality_indicator,
int64_t *duration) {
if (frame_number) {
*frame_number = 0;
diff --git a/media/libstagefright/chromium_http/Android.mk b/media/libstagefright/chromium_http/Android.mk
index 80b2478..6573e3c 100644
--- a/media/libstagefright/chromium_http/Android.mk
+++ b/media/libstagefright/chromium_http/Android.mk
@@ -15,10 +15,8 @@
LOCAL_CFLAGS += -Wno-multichar
-ifneq ($(TARGET_SIMULATOR),true)
LOCAL_SHARED_LIBRARIES += libstlport
include external/stlport/libstlport.mk
-endif
LOCAL_MODULE:= libstagefright_chromium_http
diff --git a/media/libstagefright/codecs/aacdec/AACDecoder.cpp b/media/libstagefright/codecs/aacdec/AACDecoder.cpp
deleted file mode 100644
index d2e3eaa..0000000
--- a/media/libstagefright/codecs/aacdec/AACDecoder.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * 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 "AACDecoder.h"
-#define LOG_TAG "AACDecoder"
-
-#include "../../include/ESDS.h"
-
-#include "pvmp4audiodecoder_api.h"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-AACDecoder::AACDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mConfig(new tPVMP4AudioDecoderExternal),
- mDecoderBuf(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mInputBuffer(NULL) {
-
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t sampleRate;
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- mMeta = new MetaData;
- mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
-
- // We'll always output stereo, regardless of how many channels are
- // present in the input due to decoder limitations.
- mMeta->setInt32(kKeyChannelCount, 2);
- mMeta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- mMeta->setInt64(kKeyDuration, durationUs);
- }
- mMeta->setCString(kKeyDecoderComponent, "AACDecoder");
-
- mInitCheck = initCheck();
-}
-
-status_t AACDecoder::initCheck() {
- memset(mConfig, 0, sizeof(tPVMP4AudioDecoderExternal));
- mConfig->outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
- mConfig->aacPlusEnabled = 1;
-
- // The software decoder doesn't properly support mono output on
- // AACplus files. Always output stereo.
- mConfig->desiredChannels = 2;
-
- UInt32 memRequirements = PVMP4AudioDecoderGetMemRequirements();
- mDecoderBuf = malloc(memRequirements);
-
- status_t err = PVMP4AudioDecoderInitLibrary(mConfig, mDecoderBuf);
- if (err != MP4AUDEC_SUCCESS) {
- LOGE("Failed to initialize MP4 audio decoder");
- return UNKNOWN_ERROR;
- }
-
- uint32_t type;
- const void *data;
- size_t size;
- sp<MetaData> meta = mSource->getFormat();
- if (meta->findData(kKeyESDS, &type, &data, &size)) {
- ESDS esds((const char *)data, size);
- CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
- &codec_specific_data, &codec_specific_data_size);
-
- mConfig->pInputBuffer = (UChar *)codec_specific_data;
- mConfig->inputBufferCurrentLength = codec_specific_data_size;
- mConfig->inputBufferMaxLength = 0;
-
- if (PVMP4AudioDecoderConfig(mConfig, mDecoderBuf)
- != MP4AUDEC_SUCCESS) {
- return ERROR_UNSUPPORTED;
- }
- }
- return OK;
-}
-
-AACDecoder::~AACDecoder() {
- if (mStarted) {
- stop();
- }
-
- delete mConfig;
- mConfig = NULL;
-}
-
-status_t AACDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(4096 * 2));
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mStarted = true;
- mNumDecodedBuffers = 0;
- mUpsamplingFactor = 2;
-
- return OK;
-}
-
-status_t AACDecoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- free(mDecoderBuf);
- mDecoderBuf = NULL;
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AACDecoder::getFormat() {
- return mMeta;
-}
-
-status_t AACDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumSamplesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
- PVMP4AudioDecoderResetBuffer(mDecoderBuf);
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumSamplesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
-
- mConfig->pInputBuffer =
- (UChar *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
- mConfig->inputBufferMaxLength = 0;
- mConfig->inputBufferUsedLength = 0;
- mConfig->remainderBits = 0;
-
- mConfig->pOutputBuffer = static_cast<Int16 *>(buffer->data());
- mConfig->pOutputBuffer_plus = &mConfig->pOutputBuffer[2048];
- mConfig->repositionFlag = false;
-
- Int decoderErr = PVMP4AudioDecodeFrame(mConfig, mDecoderBuf);
-
- /*
- * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
- * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
- * rate system and the sampling rate in the final output is actually
- * doubled compared with the core AAC decoder sampling rate.
- *
- * Explicit signalling is done by explicitly defining SBR audio object
- * type in the bitstream. Implicit signalling is done by embedding
- * SBR content in AAC extension payload specific to SBR, and hence
- * requires an AAC decoder to perform pre-checks on actual audio frames.
- *
- * Thus, we could not say for sure whether a stream is
- * AAC+/eAAC+ until the first data frame is decoded.
- */
- if (++mNumDecodedBuffers <= 2) {
- LOGV("audio/extended audio object type: %d + %d",
- mConfig->audioObjectType, mConfig->extendedAudioObjectType);
- LOGV("aac+ upsampling factor: %d desired channels: %d",
- mConfig->aacPlusUpsamplingFactor, mConfig->desiredChannels);
-
- CHECK(mNumDecodedBuffers > 0);
-
- if (decoderErr != MP4AUDEC_SUCCESS) {
- // If decoding fails this early, the fields in mConfig may
- // not be valid and we cannot recover.
-
- LOGE("Unable to decode aac content, decoder returned error %d",
- decoderErr);
-
- buffer->release();
- buffer = NULL;
-
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- return ERROR_UNSUPPORTED;
- }
-
- if (mNumDecodedBuffers == 1) {
- mUpsamplingFactor = mConfig->aacPlusUpsamplingFactor;
- // Check on the sampling rate to see whether it is changed.
- int32_t sampleRate;
- CHECK(mMeta->findInt32(kKeySampleRate, &sampleRate));
- if (mConfig->samplingRate != sampleRate) {
- mMeta->setInt32(kKeySampleRate, mConfig->samplingRate);
- LOGW("Sample rate was %d Hz, but now is %d Hz",
- sampleRate, mConfig->samplingRate);
- buffer->release();
- mInputBuffer->release();
- mInputBuffer = NULL;
- return INFO_FORMAT_CHANGED;
- }
- } else { // mNumDecodedBuffers == 2
- if (mConfig->extendedAudioObjectType == MP4AUDIO_AAC_LC ||
- mConfig->extendedAudioObjectType == MP4AUDIO_LTP) {
- if (mUpsamplingFactor == 2) {
- // The stream turns out to be not aacPlus mode anyway
- LOGW("Disable AAC+/eAAC+ since extended audio object type is %d",
- mConfig->extendedAudioObjectType);
- mConfig->aacPlusEnabled = 0;
- }
- } else {
- if (mUpsamplingFactor == 1) {
- // aacPlus mode does not buy us anything, but to cause
- // 1. CPU load to increase, and
- // 2. a half speed of decoding
- LOGW("Disable AAC+/eAAC+ since upsampling factor is 1");
- mConfig->aacPlusEnabled = 0;
- }
- }
- }
- }
-
- size_t numOutBytes =
- mConfig->frameLength * sizeof(int16_t) * mConfig->desiredChannels;
- if (mUpsamplingFactor == 2) {
- if (mConfig->desiredChannels == 1) {
- memcpy(&mConfig->pOutputBuffer[1024], &mConfig->pOutputBuffer[2048], numOutBytes * 2);
- }
- numOutBytes *= 2;
- }
-
- if (decoderErr != MP4AUDEC_SUCCESS) {
- LOGW("AAC decoder returned error %d, substituting silence", decoderErr);
-
- memset(buffer->data(), 0, numOutBytes);
-
- // Discard input buffer.
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- // fall through
- }
-
- buffer->set_range(0, numOutBytes);
-
- if (mInputBuffer != NULL) {
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
- mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumSamplesOutput * 1000000) / mConfig->samplingRate);
-
- mNumSamplesOutput += mConfig->frameLength * mUpsamplingFactor;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index 359a2ec..20c7bc0 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -143,7 +143,6 @@
unpack_idx.cpp \
window_tables_fxp.cpp \
pvmp4setaudioconfig.cpp \
- AACDecoder.cpp \
LOCAL_CFLAGS := -DAAC_PLUS -DHQ_SBR -DPARAMETRICSTEREO -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF= -DOSCL_UNUSED_ARG=
diff --git a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp b/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
deleted file mode 100644
index a11d46b..0000000
--- a/media/libstagefright/codecs/amrnb/dec/AMRNBDecoder.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AMRNBDecoder"
-#include <utils/Log.h>
-
-#include "AMRNBDecoder.h"
-
-#include "gsmamr_dec.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-static const int32_t kNumSamplesPerFrame = 160;
-static const int32_t kSampleRate = 8000;
-
-AMRNBDecoder::AMRNBDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mState(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mInputBuffer(NULL) {
-}
-
-AMRNBDecoder::~AMRNBDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t AMRNBDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t)));
-
- CHECK_EQ(GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder"), 0);
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mStarted = true;
-
- return OK;
-}
-
-status_t AMRNBDecoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- GSMDecodeFrameExit(&mState);
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AMRNBDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t numChannels;
- int32_t sampleRate;
-
- CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
- CHECK_EQ(numChannels, 1);
-
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
- CHECK_EQ(sampleRate, kSampleRate);
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, numChannels);
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "AMRNBDecoder");
-
- return meta;
-}
-
-status_t AMRNBDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumSamplesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumSamplesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
-
- const uint8_t *inputPtr =
- (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- int32_t numBytesRead =
- AMRDecode(mState,
- (Frame_Type_3GPP)((inputPtr[0] >> 3) & 0x0f),
- (UWord8 *)&inputPtr[1],
- static_cast<int16_t *>(buffer->data()),
- MIME_IETF);
-
- if (numBytesRead == -1 ) {
- LOGE("PV AMR decoder AMRDecode() call failed");
- buffer->release();
- buffer = NULL;
- return ERROR_MALFORMED;
- }
- ++numBytesRead; // Include the frame type header byte.
-
- buffer->set_range(0, kNumSamplesPerFrame * sizeof(int16_t));
-
- if (static_cast<size_t>(numBytesRead) > mInputBuffer->range_length()) {
- // This is bad, should never have happened, but did. Abort now.
-
- buffer->release();
- buffer = NULL;
-
- return ERROR_MALFORMED;
- }
-
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + numBytesRead,
- mInputBuffer->range_length() - numBytesRead);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumSamplesOutput * 1000000) / kSampleRate);
-
- mNumSamplesOutput += kNumSamplesPerFrame;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 5862abc..23a22ef 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- AMRNBDecoder.cpp \
src/a_refl.cpp \
src/agc.cpp \
src/amrdecode.cpp \
diff --git a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp b/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
deleted file mode 100644
index 5b111ef..0000000
--- a/media/libstagefright/codecs/amrwb/AMRWBDecoder.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * 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 "AMRWBDecoder.h"
-
-#include "pvamrwbdecoder.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-static const int32_t kNumSamplesPerFrame = 320;
-static const int32_t kSampleRate = 16000;
-
-AMRWBDecoder::AMRWBDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mState(NULL),
- mDecoderBuf(NULL),
- mDecoderCookie(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mInputBuffer(NULL) {
-}
-
-AMRWBDecoder::~AMRWBDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t AMRWBDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kNumSamplesPerFrame * sizeof(int16_t)));
-
- int32_t memReq = pvDecoder_AmrWbMemRequirements();
- mDecoderBuf = malloc(memReq);
-
- pvDecoder_AmrWb_Init(&mState, mDecoderBuf, &mDecoderCookie);
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mStarted = true;
-
- return OK;
-}
-
-status_t AMRWBDecoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- free(mDecoderBuf);
- mDecoderBuf = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AMRWBDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t numChannels;
- int32_t sampleRate;
-
- CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
- CHECK_EQ(numChannels, 1);
-
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
- CHECK_EQ(sampleRate, kSampleRate);
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, numChannels);
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "AMRWBDecoder");
-
- return meta;
-}
-
-static size_t getFrameSize(unsigned FT) {
- static const size_t kFrameSizeWB[9] = {
- 132, 177, 253, 285, 317, 365, 397, 461, 477
- };
-
- size_t frameSize = kFrameSizeWB[FT];
-
- // Round up bits to bytes and add 1 for the header byte.
- frameSize = (frameSize + 7) / 8 + 1;
-
- return frameSize;
-}
-
-status_t AMRWBDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumSamplesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumSamplesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
-
- const uint8_t *inputPtr =
- (const uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- int16 mode = ((inputPtr[0] >> 3) & 0x0f);
- size_t frameSize = getFrameSize(mode);
- CHECK(mInputBuffer->range_length() >= frameSize);
-
- int16 frameType;
- RX_State_wb rx_state;
- mime_unsorting(
- const_cast<uint8_t *>(&inputPtr[1]),
- mInputSampleBuffer,
- &frameType, &mode, 1, &rx_state);
-
- int16_t *outPtr = (int16_t *)buffer->data();
-
- int16_t numSamplesOutput;
- pvDecoder_AmrWb(
- mode, mInputSampleBuffer,
- outPtr,
- &numSamplesOutput,
- mDecoderBuf, frameType, mDecoderCookie);
-
- CHECK_EQ(numSamplesOutput, kNumSamplesPerFrame);
-
- for (int i = 0; i < kNumSamplesPerFrame; ++i) {
- /* Delete the 2 LSBs (14-bit output) */
- outPtr[i] &= 0xfffC;
- }
-
- buffer->set_range(0, numSamplesOutput * sizeof(int16_t));
-
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + frameSize,
- mInputBuffer->range_length() - frameSize);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumSamplesOutput * 1000000) / kSampleRate);
-
- mNumSamplesOutput += kNumSamplesPerFrame;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
index ab591d7..c9e1c25 100644
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ b/media/libstagefright/codecs/amrwb/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- AMRWBDecoder.cpp \
src/agc2_amr_wb.cpp \
src/band_pass_6k_7k.cpp \
src/dec_acelp_2p_in_64.cpp \
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
deleted file mode 100644
index 490129f..0000000
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "AVCDecoder"
-#include <utils/Log.h>
-
-#include "AVCDecoder.h"
-
-#include "avcdec_api.h"
-#include "avcdec_int.h"
-
-#include <OMX_Component.h>
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-namespace android {
-
-static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
-
-static int32_t Malloc(void *userData, int32_t size, int32_t attrs) {
- return reinterpret_cast<int32_t>(malloc(size));
-}
-
-static void Free(void *userData, int32_t ptr) {
- free(reinterpret_cast<void *>(ptr));
-}
-
-AVCDecoder::AVCDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mHandle(new tagAVCHandle),
- mInputBuffer(NULL),
- mAnchorTimeUs(0),
- mNumSamplesOutput(0),
- mPendingSeekTimeUs(-1),
- mPendingSeekMode(MediaSource::ReadOptions::SEEK_CLOSEST_SYNC),
- mTargetTimeUs(-1),
- mSPSSeen(false),
- mPPSSeen(false) {
- memset(mHandle, 0, sizeof(tagAVCHandle));
- mHandle->AVCObject = NULL;
- mHandle->userData = this;
- mHandle->CBAVC_DPBAlloc = ActivateSPSWrapper;
- mHandle->CBAVC_FrameBind = BindFrameWrapper;
- mHandle->CBAVC_FrameUnbind = UnbindFrame;
- mHandle->CBAVC_Malloc = Malloc;
- mHandle->CBAVC_Free = Free;
-
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
- int32_t width, height;
- CHECK(mSource->getFormat()->findInt32(kKeyWidth, &width));
- CHECK(mSource->getFormat()->findInt32(kKeyHeight, &height));
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
- mFormat->setRect(kKeyCropRect, 0, 0, width - 1, height - 1);
- mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
- mFormat->setCString(kKeyDecoderComponent, "AVCDecoder");
-
- int64_t durationUs;
- if (mSource->getFormat()->findInt64(kKeyDuration, &durationUs)) {
- mFormat->setInt64(kKeyDuration, durationUs);
- }
-}
-
-AVCDecoder::~AVCDecoder() {
- if (mStarted) {
- stop();
- }
-
- PVAVCCleanUpDecoder(mHandle);
-
- delete mHandle;
- mHandle = NULL;
-}
-
-status_t AVCDecoder::start(MetaData *) {
- CHECK(!mStarted);
-
- uint32_t type;
- const void *data;
- size_t size;
- sp<MetaData> meta = mSource->getFormat();
- if (meta->findData(kKeyAVCC, &type, &data, &size)) {
- // Parse the AVCDecoderConfigurationRecord
-
- const uint8_t *ptr = (const uint8_t *)data;
-
- CHECK(size >= 7);
- CHECK_EQ(ptr[0], 1); // configurationVersion == 1
- uint8_t profile = ptr[1];
- uint8_t level = ptr[3];
-
- // There is decodable content out there that fails the following
- // assertion, let's be lenient for now...
- // CHECK((ptr[4] >> 2) == 0x3f); // reserved
-
- size_t lengthSize = 1 + (ptr[4] & 3);
-
- // commented out check below as H264_QVGA_500_NO_AUDIO.3gp
- // violates it...
- // CHECK((ptr[5] >> 5) == 7); // reserved
-
- size_t numSeqParameterSets = ptr[5] & 31;
-
- ptr += 6;
- size -= 6;
-
- for (size_t i = 0; i < numSeqParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
-
- ptr += 2;
- size -= 2;
-
- CHECK(size >= length);
-
- addCodecSpecificData(ptr, length);
-
- ptr += length;
- size -= length;
- }
-
- CHECK(size >= 1);
- size_t numPictureParameterSets = *ptr;
- ++ptr;
- --size;
-
- for (size_t i = 0; i < numPictureParameterSets; ++i) {
- CHECK(size >= 2);
- size_t length = U16_AT(ptr);
-
- ptr += 2;
- size -= 2;
-
- CHECK(size >= length);
-
- addCodecSpecificData(ptr, length);
-
- ptr += length;
- size -= length;
- }
- }
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumSamplesOutput = 0;
- mPendingSeekTimeUs = -1;
- mPendingSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;
- mTargetTimeUs = -1;
- mSPSSeen = false;
- mPPSSeen = false;
- mStarted = true;
-
- return OK;
-}
-
-void AVCDecoder::addCodecSpecificData(const uint8_t *data, size_t size) {
- MediaBuffer *buffer = new MediaBuffer(size + 4);
- memcpy(buffer->data(), kStartCode, 4);
- memcpy((uint8_t *)buffer->data() + 4, data, size);
- buffer->set_range(0, size + 4);
-
- mCodecSpecificData.push(buffer);
-}
-
-status_t AVCDecoder::stop() {
- CHECK(mStarted);
-
- for (size_t i = 0; i < mCodecSpecificData.size(); ++i) {
- (*mCodecSpecificData.editItemAt(i)).release();
- }
- mCodecSpecificData.clear();
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- mSource->stop();
-
- releaseFrames();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> AVCDecoder::getFormat() {
- return mFormat;
-}
-
-static void findNALFragment(
- const MediaBuffer *buffer, const uint8_t **fragPtr, size_t *fragSize) {
- const uint8_t *data =
- (const uint8_t *)buffer->data() + buffer->range_offset();
-
- size_t size = buffer->range_length();
-
- CHECK(size >= 4);
- CHECK(!memcmp(kStartCode, data, 4));
-
- size_t offset = 4;
- while (offset + 3 < size && memcmp(kStartCode, &data[offset], 4)) {
- ++offset;
- }
-
- *fragPtr = &data[4];
- if (offset + 3 >= size) {
- *fragSize = size - 4;
- } else {
- *fragSize = offset - 4;
- }
-}
-
-MediaBuffer *AVCDecoder::drainOutputBuffer() {
- int32_t index;
- int32_t Release;
- AVCFrameIO Output;
- Output.YCbCr[0] = Output.YCbCr[1] = Output.YCbCr[2] = NULL;
- AVCDec_Status status = PVAVCDecGetOutput(mHandle, &index, &Release, &Output);
-
- if (status != AVCDEC_SUCCESS) {
- LOGV("PVAVCDecGetOutput returned error %d", status);
- return NULL;
- }
-
- CHECK(index >= 0);
- CHECK(index < (int32_t)mFrames.size());
-
- MediaBuffer *mbuf = mFrames.editItemAt(index);
-
- bool skipFrame = false;
-
- if (mTargetTimeUs >= 0) {
- int64_t timeUs;
- CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
- CHECK(timeUs <= mTargetTimeUs);
-
- if (timeUs < mTargetTimeUs) {
- // We're still waiting for the frame with the matching
- // timestamp and we won't return the current one.
- skipFrame = true;
-
- LOGV("skipping frame at %lld us", timeUs);
- } else {
- LOGV("found target frame at %lld us", timeUs);
-
- mTargetTimeUs = -1;
- }
- }
-
- if (!skipFrame) {
- mbuf->set_range(0, mbuf->size());
- mbuf->add_ref();
-
- return mbuf;
- }
-
- return new MediaBuffer(0);
-}
-
-status_t AVCDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- LOGV("seek requested to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
-
- CHECK(seekTimeUs >= 0);
- mPendingSeekTimeUs = seekTimeUs;
- mPendingSeekMode = mode;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- PVAVCDecReset(mHandle);
- }
-
- if (mInputBuffer == NULL) {
- LOGV("fetching new input buffer.");
-
- bool seeking = false;
-
- if (!mCodecSpecificData.isEmpty()) {
- mInputBuffer = mCodecSpecificData.editItemAt(0);
- mCodecSpecificData.removeAt(0);
- } else {
- for (;;) {
- if (mPendingSeekTimeUs >= 0) {
- LOGV("reading data from timestamp %lld (%.2f secs)",
- mPendingSeekTimeUs, mPendingSeekTimeUs / 1E6);
- }
-
- ReadOptions seekOptions;
- if (mPendingSeekTimeUs >= 0) {
- seeking = true;
-
- seekOptions.setSeekTo(mPendingSeekTimeUs, mPendingSeekMode);
- mPendingSeekTimeUs = -1;
- }
- status_t err = mSource->read(&mInputBuffer, &seekOptions);
- seekOptions.clearSeekTo();
-
- if (err != OK) {
- *out = drainOutputBuffer();
- return (*out == NULL) ? err : (status_t)OK;
- }
-
- if (mInputBuffer->range_length() > 0) {
- break;
- }
-
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
- }
-
- if (seeking) {
- int64_t targetTimeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
- && targetTimeUs >= 0) {
- mTargetTimeUs = targetTimeUs;
- } else {
- mTargetTimeUs = -1;
- }
- }
- }
-
- const uint8_t *fragPtr;
- size_t fragSize;
- findNALFragment(mInputBuffer, &fragPtr, &fragSize);
-
- bool releaseFragment = true;
- status_t err = UNKNOWN_ERROR;
-
- int nalType;
- int nalRefIdc;
- AVCDec_Status res =
- PVAVCDecGetNALType(
- const_cast<uint8_t *>(fragPtr), fragSize,
- &nalType, &nalRefIdc);
-
- if (res != AVCDEC_SUCCESS) {
- LOGV("cannot determine nal type");
- } else if (nalType == AVC_NALTYPE_SPS || nalType == AVC_NALTYPE_PPS
- || (mSPSSeen && mPPSSeen)) {
- switch (nalType) {
- case AVC_NALTYPE_SPS:
- {
- mSPSSeen = true;
-
- res = PVAVCDecSeqParamSet(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res != AVCDEC_SUCCESS) {
- LOGV("PVAVCDecSeqParamSet returned error %d", res);
- break;
- }
-
- AVCDecObject *pDecVid = (AVCDecObject *)mHandle->AVCObject;
-
- int32_t width =
- (pDecVid->seqParams[0]->pic_width_in_mbs_minus1 + 1) * 16;
-
- int32_t height =
- (pDecVid->seqParams[0]->pic_height_in_map_units_minus1 + 1) * 16;
-
- int32_t crop_left, crop_right, crop_top, crop_bottom;
- if (pDecVid->seqParams[0]->frame_cropping_flag)
- {
- crop_left = 2 * pDecVid->seqParams[0]->frame_crop_left_offset;
- crop_right =
- width - (2 * pDecVid->seqParams[0]->frame_crop_right_offset + 1);
-
- if (pDecVid->seqParams[0]->frame_mbs_only_flag)
- {
- crop_top = 2 * pDecVid->seqParams[0]->frame_crop_top_offset;
- crop_bottom =
- height -
- (2 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
- }
- else
- {
- crop_top = 4 * pDecVid->seqParams[0]->frame_crop_top_offset;
- crop_bottom =
- height -
- (4 * pDecVid->seqParams[0]->frame_crop_bottom_offset + 1);
- }
- } else {
- crop_bottom = height - 1;
- crop_right = width - 1;
- crop_top = crop_left = 0;
- }
-
- int32_t prevCropLeft, prevCropTop;
- int32_t prevCropRight, prevCropBottom;
- if (!mFormat->findRect(
- kKeyCropRect,
- &prevCropLeft, &prevCropTop,
- &prevCropRight, &prevCropBottom)) {
- prevCropLeft = prevCropTop = 0;
- prevCropRight = width - 1;
- prevCropBottom = height - 1;
- }
-
- int32_t oldWidth, oldHeight;
- CHECK(mFormat->findInt32(kKeyWidth, &oldWidth));
- CHECK(mFormat->findInt32(kKeyHeight, &oldHeight));
-
- if (oldWidth != width || oldHeight != height
- || prevCropLeft != crop_left
- || prevCropTop != crop_top
- || prevCropRight != crop_right
- || prevCropBottom != crop_bottom) {
- mFormat->setRect(
- kKeyCropRect,
- crop_left, crop_top, crop_right, crop_bottom);
-
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
-
- err = INFO_FORMAT_CHANGED;
- } else {
- *out = new MediaBuffer(0);
- err = OK;
- }
- break;
- }
-
- case AVC_NALTYPE_PPS:
- {
- mPPSSeen = true;
-
- res = PVAVCDecPicParamSet(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res != AVCDEC_SUCCESS) {
- LOGV("PVAVCDecPicParamSet returned error %d", res);
- break;
- }
-
- *out = new MediaBuffer(0);
-
- err = OK;
- break;
- }
-
- case AVC_NALTYPE_SLICE:
- case AVC_NALTYPE_IDR:
- {
- res = PVAVCDecodeSlice(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res == AVCDEC_PICTURE_OUTPUT_READY) {
- MediaBuffer *mbuf = drainOutputBuffer();
- if (mbuf == NULL) {
- break;
- }
-
- *out = mbuf;
-
- // Do _not_ release input buffer yet.
-
- releaseFragment = false;
- err = OK;
- break;
- }
-
- if (res == AVCDEC_PICTURE_READY || res == AVCDEC_SUCCESS) {
- *out = new MediaBuffer(0);
-
- err = OK;
- } else {
- LOGV("PVAVCDecodeSlice returned error %d", res);
- }
- break;
- }
-
- case AVC_NALTYPE_SEI:
- {
- res = PVAVCDecSEI(
- mHandle, const_cast<uint8_t *>(fragPtr),
- fragSize);
-
- if (res != AVCDEC_SUCCESS) {
- break;
- }
-
- *out = new MediaBuffer(0);
-
- err = OK;
- break;
- }
-
- case AVC_NALTYPE_AUD:
- case AVC_NALTYPE_FILL:
- case AVC_NALTYPE_EOSEQ:
- {
- *out = new MediaBuffer(0);
-
- err = OK;
- break;
- }
-
- default:
- {
- LOGE("Should not be here, unknown nalType %d", nalType);
-
- err = ERROR_MALFORMED;
- break;
- }
- }
- } else {
- // We haven't seen SPS or PPS yet.
-
- *out = new MediaBuffer(0);
- err = OK;
- }
-
- if (releaseFragment) {
- size_t offset = mInputBuffer->range_offset();
- if (fragSize + 4 == mInputBuffer->range_length()) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- } else {
- mInputBuffer->set_range(
- offset + fragSize + 4,
- mInputBuffer->range_length() - fragSize - 4);
- }
- }
-
- return err;
-}
-
-// static
-int32_t AVCDecoder::ActivateSPSWrapper(
- void *userData, unsigned int sizeInMbs, unsigned int numBuffers) {
- return static_cast<AVCDecoder *>(userData)->activateSPS(sizeInMbs, numBuffers);
-}
-
-// static
-int32_t AVCDecoder::BindFrameWrapper(
- void *userData, int32_t index, uint8_t **yuv) {
- return static_cast<AVCDecoder *>(userData)->bindFrame(index, yuv);
-}
-
-// static
-void AVCDecoder::UnbindFrame(void *userData, int32_t index) {
-}
-
-int32_t AVCDecoder::activateSPS(
- unsigned int sizeInMbs, unsigned int numBuffers) {
- CHECK(mFrames.isEmpty());
-
- size_t frameSize = (sizeInMbs << 7) * 3;
- for (unsigned int i = 0; i < numBuffers; ++i) {
- MediaBuffer *buffer = new MediaBuffer(frameSize);
- buffer->setObserver(this);
-
- mFrames.push(buffer);
- }
-
- return 1;
-}
-
-int32_t AVCDecoder::bindFrame(int32_t index, uint8_t **yuv) {
- CHECK(index >= 0);
- CHECK(index < (int32_t)mFrames.size());
-
- CHECK(mInputBuffer != NULL);
- int64_t timeUs;
- CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
- mFrames[index]->meta_data()->setInt64(kKeyTime, timeUs);
-
- *yuv = (uint8_t *)mFrames[index]->data();
-
- return 1;
-}
-
-void AVCDecoder::releaseFrames() {
- for (size_t i = 0; i < mFrames.size(); ++i) {
- MediaBuffer *buffer = mFrames.editItemAt(i);
-
- buffer->setObserver(NULL);
- buffer->release();
- }
- mFrames.clear();
-}
-
-void AVCDecoder::signalBufferReturned(MediaBuffer *buffer) {
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/avc/dec/Android.mk b/media/libstagefright/codecs/avc/dec/Android.mk
index 4d4533b..2949a04 100644
--- a/media/libstagefright/codecs/avc/dec/Android.mk
+++ b/media/libstagefright/codecs/avc/dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- AVCDecoder.cpp \
src/avcdec_api.cpp \
src/avc_bitstream.cpp \
src/header.cpp \
diff --git a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
index 9f141ac..6a476f6 100644
--- a/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/avc/dec/SoftAVC.cpp
@@ -23,6 +23,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
#include "avcdec_api.h"
#include "avcdec_int.h"
@@ -31,6 +32,13 @@
static const char kStartCode[4] = { 0x00, 0x00, 0x00, 0x01 };
+static const CodecProfileLevel kProfileLevels[] = {
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+};
+
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
@@ -181,6 +189,28 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamVideoProfileLevelQuerySupported:
+ {
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+ (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+ if (profileLevel->nPortIndex != 0) { // Input port only
+ LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+ return OMX_ErrorUnsupportedIndex;
+ }
+
+ size_t index = profileLevel->nProfileIndex;
+ size_t nProfileLevels =
+ sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kProfileLevels[index].mProfile;
+ profileLevel->eLevel = kProfileLevels[index].mLevel;
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index 6e98559..6692533 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -2,20 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- G711Decoder.cpp
-
-LOCAL_C_INCLUDES := \
- frameworks/base/media/libstagefright/include \
-
-LOCAL_MODULE := libstagefright_g711dec
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
SoftG711.cpp
LOCAL_C_INCLUDES := \
diff --git a/media/libstagefright/codecs/g711/dec/G711Decoder.cpp b/media/libstagefright/codecs/g711/dec/G711Decoder.cpp
deleted file mode 100644
index 4414e4e..0000000
--- a/media/libstagefright/codecs/g711/dec/G711Decoder.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "G711Decoder"
-#include <utils/Log.h>
-
-#include "G711Decoder.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-static const size_t kMaxNumSamplesPerFrame = 16384;
-
-namespace android {
-
-G711Decoder::G711Decoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL) {
-}
-
-G711Decoder::~G711Decoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t G711Decoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- const char *mime;
- CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
- mIsMLaw = false;
- if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) {
- mIsMLaw = true;
- } else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)) {
- return ERROR_UNSUPPORTED;
- }
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kMaxNumSamplesPerFrame * sizeof(int16_t)));
-
- mSource->start();
-
- mStarted = true;
-
- return OK;
-}
-
-status_t G711Decoder::stop() {
- CHECK(mStarted);
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> G711Decoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t numChannels;
- int32_t sampleRate;
-
- CHECK(srcFormat->findInt32(kKeyChannelCount, &numChannels));
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, numChannels);
- meta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "G711Decoder");
-
- return meta;
-}
-
-status_t G711Decoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
- } else {
- seekTimeUs = -1;
- }
-
- MediaBuffer *inBuffer;
- err = mSource->read(&inBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- if (inBuffer->range_length() > kMaxNumSamplesPerFrame) {
- LOGE("input buffer too large (%d).", inBuffer->range_length());
-
- inBuffer->release();
- inBuffer = NULL;
-
- return ERROR_UNSUPPORTED;
- }
-
- int64_t timeUs;
- CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- const uint8_t *inputPtr =
- (const uint8_t *)inBuffer->data() + inBuffer->range_offset();
-
- MediaBuffer *outBuffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&outBuffer), OK);
-
- if (mIsMLaw) {
- DecodeMLaw(
- static_cast<int16_t *>(outBuffer->data()),
- inputPtr, inBuffer->range_length());
- } else {
- DecodeALaw(
- static_cast<int16_t *>(outBuffer->data()),
- inputPtr, inBuffer->range_length());
- }
-
- // Each 8-bit byte is converted into a 16-bit sample.
- outBuffer->set_range(0, inBuffer->range_length() * 2);
-
- outBuffer->meta_data()->setInt64(kKeyTime, timeUs);
-
- inBuffer->release();
- inBuffer = NULL;
-
- *out = outBuffer;
-
- return OK;
-}
-
-// static
-void G711Decoder::DecodeALaw(
- int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize-- > 0) {
- int32_t x = *in++;
-
- int32_t ix = x ^ 0x55;
- ix &= 0x7f;
-
- int32_t iexp = ix >> 4;
- int32_t mant = ix & 0x0f;
-
- if (iexp > 0) {
- mant += 16;
- }
-
- mant = (mant << 4) + 8;
-
- if (iexp > 1) {
- mant = mant << (iexp - 1);
- }
-
- *out++ = (x > 127) ? mant : -mant;
- }
-}
-
-// static
-void G711Decoder::DecodeMLaw(
- int16_t *out, const uint8_t *in, size_t inSize) {
- while (inSize-- > 0) {
- int32_t x = *in++;
-
- int32_t mantissa = ~x;
- int32_t exponent = (mantissa >> 4) & 7;
- int32_t segment = exponent + 1;
- mantissa &= 0x0f;
-
- int32_t step = 4 << segment;
-
- int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
-
- *out++ = (x < 0x80) ? -abs : abs;
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index f1bec08..2ffa5f2 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- M4vH263Decoder.cpp \
src/adaptive_smooth_no_mmx.cpp \
src/bitstream.cpp \
src/block_idct.cpp \
diff --git a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp b/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
deleted file mode 100644
index 2bdb3ef..0000000
--- a/media/libstagefright/codecs/m4v_h263/dec/M4vH263Decoder.cpp
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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.
- */
-//#define LOG_NDEBUG 0
-#define LOG_TAG "M4vH263Decoder"
-#include <utils/Log.h>
-#include <stdlib.h> // for free
-#include "ESDS.h"
-#include "M4vH263Decoder.h"
-
-#include "mp4dec_api.h"
-
-#include <OMX_Component.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-namespace android {
-
-M4vH263Decoder::M4vH263Decoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mHandle(new tagvideoDecControls),
- mInputBuffer(NULL),
- mNumSamplesOutput(0),
- mTargetTimeUs(-1) {
-
- LOGV("M4vH263Decoder");
- memset(mHandle, 0, sizeof(tagvideoDecControls));
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
-
- // CHECK(mSource->getFormat()->findInt32(kKeyWidth, &mWidth));
- // CHECK(mSource->getFormat()->findInt32(kKeyHeight, &mHeight));
-
- // We'll ignore the dimension advertised by the source, the decoder
- // appears to require us to always start with the default dimensions
- // of 352 x 288 to operate correctly and later react to changes in
- // the dimensions as needed.
- mWidth = 352;
- mHeight = 288;
-
- mFormat->setInt32(kKeyWidth, mWidth);
- mFormat->setInt32(kKeyHeight, mHeight);
- mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
- mFormat->setCString(kKeyDecoderComponent, "M4vH263Decoder");
-}
-
-M4vH263Decoder::~M4vH263Decoder() {
- if (mStarted) {
- stop();
- }
-
- delete mHandle;
- mHandle = NULL;
-}
-
-void M4vH263Decoder::allocateFrames(int32_t width, int32_t height) {
- size_t frameSize =
- (((width + 15) & - 16) * ((height + 15) & - 16) * 3) / 2;
-
- for (uint32_t i = 0; i < 2; ++i) {
- mFrames[i] = new MediaBuffer(frameSize);
- mFrames[i]->setObserver(this);
- }
-
- PVSetReferenceYUV(
- mHandle,
- (uint8_t *)mFrames[1]->data());
-}
-
-status_t M4vH263Decoder::start(MetaData *) {
- CHECK(!mStarted);
-
- const char *mime = NULL;
- sp<MetaData> meta = mSource->getFormat();
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- MP4DecodingMode mode;
- if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
- mode = MPEG4_MODE;
- } else {
- CHECK(!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime));
- mode = H263_MODE;
- }
-
- uint32_t type;
- const void *data = NULL;
- size_t size = 0;
- uint8_t *vol_data[1] = {0};
- int32_t vol_size = 0;
- if (meta->findData(kKeyESDS, &type, &data, &size)) {
- ESDS esds((const uint8_t *)data, size);
- CHECK_EQ(esds.InitCheck(), (status_t)OK);
-
- const void *codec_specific_data;
- size_t codec_specific_data_size;
- esds.getCodecSpecificInfo(
- &codec_specific_data, &codec_specific_data_size);
-
- vol_data[0] = (uint8_t *) malloc(codec_specific_data_size);
- memcpy(vol_data[0], codec_specific_data, codec_specific_data_size);
- vol_size = codec_specific_data_size;
- } else {
- vol_data[0] = NULL;
- vol_size = 0;
-
- }
-
- Bool success = PVInitVideoDecoder(
- mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
- if (vol_data[0]) free(vol_data[0]);
-
- if (success != PV_TRUE) {
- LOGW("PVInitVideoDecoder failed. Unsupported content?");
- return ERROR_UNSUPPORTED;
- }
-
- MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
- if (mode != actualMode) {
- PVCleanUpVideoDecoder(mHandle);
- return UNKNOWN_ERROR;
- }
-
- PVSetPostProcType((VideoDecControls *) mHandle, 0);
-
- int32_t width, height;
- PVGetVideoDimensions(mHandle, &width, &height);
- if (mode == H263_MODE && (width == 0 || height == 0)) {
- width = 352;
- height = 288;
- }
- allocateFrames(width, height);
-
- mSource->start();
-
- mNumSamplesOutput = 0;
- mTargetTimeUs = -1;
- mStarted = true;
-
- return OK;
-}
-
-status_t M4vH263Decoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- mSource->stop();
-
- releaseFrames();
-
- mStarted = false;
- return (PVCleanUpVideoDecoder(mHandle) == PV_TRUE)? OK: UNKNOWN_ERROR;
-}
-
-sp<MetaData> M4vH263Decoder::getFormat() {
- return mFormat;
-}
-
-status_t M4vH263Decoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- *out = NULL;
-
- bool seeking = false;
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- seeking = true;
- CHECK_EQ((int)PVResetVideoDecoder(mHandle), PV_TRUE);
- }
-
- MediaBuffer *inputBuffer = NULL;
- status_t err = mSource->read(&inputBuffer, options);
- if (err != OK) {
- return err;
- }
-
- if (seeking) {
- int64_t targetTimeUs;
- if (inputBuffer->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
- && targetTimeUs >= 0) {
- mTargetTimeUs = targetTimeUs;
- } else {
- mTargetTimeUs = -1;
- }
- }
-
- uint8_t *bitstream =
- (uint8_t *) inputBuffer->data() + inputBuffer->range_offset();
-
- uint32_t timestamp = 0xFFFFFFFF;
- int32_t bufferSize = inputBuffer->range_length();
- uint32_t useExtTimestamp = 0;
- if (PVDecodeVideoFrame(
- mHandle, &bitstream, ×tamp, &bufferSize,
- &useExtTimestamp,
- (uint8_t *)mFrames[mNumSamplesOutput & 0x01]->data())
- != PV_TRUE) {
- LOGE("failed to decode video frame.");
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- return UNKNOWN_ERROR;
- }
-
- int32_t disp_width, disp_height;
- PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
-
- int32_t buf_width, buf_height;
- PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
-
- if (buf_width != mWidth || buf_height != mHeight) {
- ++mNumSamplesOutput; // The client will never get to see this frame.
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- mWidth = buf_width;
- mHeight = buf_height;
- mFormat->setInt32(kKeyWidth, mWidth);
- mFormat->setInt32(kKeyHeight, mHeight);
-
- CHECK_LE(disp_width, buf_width);
- CHECK_LE(disp_height, buf_height);
-
- mFormat->setRect(kKeyCropRect, 0, 0, disp_width - 1, disp_height - 1);
-
- return INFO_FORMAT_CHANGED;
- }
-
- int64_t timeUs;
- CHECK(inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- bool skipFrame = false;
-
- if (mTargetTimeUs >= 0) {
- CHECK(timeUs <= mTargetTimeUs);
-
- if (timeUs < mTargetTimeUs) {
- // We're still waiting for the frame with the matching
- // timestamp and we won't return the current one.
- skipFrame = true;
-
- LOGV("skipping frame at %lld us", timeUs);
- } else {
- LOGV("found target frame at %lld us", timeUs);
-
- mTargetTimeUs = -1;
- }
- }
-
- if (skipFrame) {
- *out = new MediaBuffer(0);
- } else {
- *out = mFrames[mNumSamplesOutput & 0x01];
- (*out)->add_ref();
- (*out)->meta_data()->setInt64(kKeyTime, timeUs);
- }
-
- ++mNumSamplesOutput;
-
- return OK;
-}
-
-void M4vH263Decoder::releaseFrames() {
- for (size_t i = 0; i < sizeof(mFrames) / sizeof(mFrames[0]); ++i) {
- MediaBuffer *buffer = mFrames[i];
-
- buffer->setObserver(NULL);
- buffer->release();
-
- mFrames[i] = NULL;
- }
-}
-
-void M4vH263Decoder::signalBufferReturned(MediaBuffer *buffer) {
- LOGV("signalBufferReturned");
-}
-
-
-} // namespace android
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index cffbfb5..ddced5f 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -23,11 +23,31 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
#include "mp4dec_api.h"
namespace android {
+static const CodecProfileLevel kM4VProfileLevels[] = {
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 },
+ { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
+};
+
+static const CodecProfileLevel kH263ProfileLevels[] = {
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 },
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 },
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
+ { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level10 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level20 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 },
+ { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 },
+};
+
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
@@ -181,6 +201,39 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamVideoProfileLevelQuerySupported:
+ {
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+ (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+ if (profileLevel->nPortIndex != 0) { // Input port only
+ LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+ return OMX_ErrorUnsupportedIndex;
+ }
+
+ size_t index = profileLevel->nProfileIndex;
+ if (mMode == MODE_H263) {
+ size_t nProfileLevels =
+ sizeof(kH263ProfileLevels) / sizeof(kH263ProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kH263ProfileLevels[index].mProfile;
+ profileLevel->eLevel = kH263ProfileLevels[index].mLevel;
+ } else {
+ size_t nProfileLevels =
+ sizeof(kM4VProfileLevels) / sizeof(kM4VProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kM4VProfileLevels[index].mProfile;
+ profileLevel->eLevel = kM4VProfileLevels[index].mLevel;
+ }
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 229988e..a08c9f0 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- MP3Decoder.cpp \
src/pvmp3_normalize.cpp \
src/pvmp3_alias_reduction.cpp \
src/pvmp3_crc.cpp \
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
deleted file mode 100644
index 0ba42ff..0000000
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MP3Decoder"
-
-#include "MP3Decoder.h"
-
-#include "include/pvmp3decoder_api.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
- : mSource(source),
- mNumChannels(0),
- mStarted(false),
- mBufferGroup(NULL),
- mConfig(new tPVMP3DecoderExternal),
- mDecoderBuf(NULL),
- mAnchorTimeUs(0),
- mNumFramesOutput(0),
- mInputBuffer(NULL) {
- init();
-}
-
-void MP3Decoder::init() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- int32_t sampleRate;
- CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels));
- CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
-
- mMeta = new MetaData;
- mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- mMeta->setInt32(kKeyChannelCount, mNumChannels);
- mMeta->setInt32(kKeySampleRate, sampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- mMeta->setInt64(kKeyDuration, durationUs);
- }
-
- mMeta->setCString(kKeyDecoderComponent, "MP3Decoder");
-}
-
-MP3Decoder::~MP3Decoder() {
- if (mStarted) {
- stop();
- }
-
- delete mConfig;
- mConfig = NULL;
-}
-
-status_t MP3Decoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(4608 * 2));
-
- mConfig->equalizerType = flat;
- mConfig->crcEnabled = false;
-
- uint32_t memRequirements = pvmp3_decoderMemRequirements();
- mDecoderBuf = malloc(memRequirements);
-
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
-
- mSource->start();
-
- mAnchorTimeUs = 0;
- mNumFramesOutput = 0;
- mStarted = true;
-
- return OK;
-}
-
-status_t MP3Decoder::stop() {
- CHECK(mStarted);
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- free(mDecoderBuf);
- mDecoderBuf = NULL;
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> MP3Decoder::getFormat() {
- return mMeta;
-}
-
-status_t MP3Decoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumFramesOutput = 0;
-
- if (mInputBuffer) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- // Make sure that the next buffer output does not still
- // depend on fragments from the last one decoded.
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
- } else {
- seekTimeUs = -1;
- }
-
- if (mInputBuffer == NULL) {
- err = mSource->read(&mInputBuffer, options);
-
- if (err != OK) {
- return err;
- }
-
- int64_t timeUs;
- if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumFramesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
- }
-
- MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
-
- mConfig->pInputBuffer =
- (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
-
- mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
- mConfig->inputBufferMaxLength = 0;
- mConfig->inputBufferUsedLength = 0;
-
- mConfig->outputFrameSize = buffer->size() / sizeof(int16_t);
- mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data());
-
- ERROR_CODE decoderErr;
- if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
- != NO_DECODING_ERROR) {
- LOGV("mp3 decoder returned error %d", decoderErr);
-
- if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ||
- mConfig->outputFrameSize == 0) {
-
- if (mConfig->outputFrameSize == 0) {
- LOGE("Output frame size is 0");
- }
- buffer->release();
- buffer = NULL;
-
- mInputBuffer->release();
- mInputBuffer = NULL;
-
- return UNKNOWN_ERROR;
- }
-
- // This is recoverable, just ignore the current frame and
- // play silence instead.
- memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t));
- mConfig->inputBufferUsedLength = mInputBuffer->range_length();
- }
-
- buffer->set_range(
- 0, mConfig->outputFrameSize * sizeof(int16_t));
-
- mInputBuffer->set_range(
- mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
- mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
-
- if (mInputBuffer->range_length() == 0) {
- mInputBuffer->release();
- mInputBuffer = NULL;
- }
-
- buffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumFramesOutput * 1000000) / mConfig->samplingRate);
-
- mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
-
- *out = buffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index 832b885..32bbd6b 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -2,24 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- VPXDecoder.cpp \
-
-LOCAL_MODULE := libstagefright_vpxdec
-
-LOCAL_C_INCLUDES := \
- $(TOP)/frameworks/base/media/libstagefright/include \
- frameworks/base/include/media/stagefright/openmax \
- $(TOP)/external/libvpx \
- $(TOP)/external/libvpx/vpx_codec \
- $(TOP)/external/libvpx/vpx_ports
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
SoftVPX.cpp
LOCAL_C_INCLUDES := \
@@ -30,7 +12,6 @@
frameworks/base/include/media/stagefright/openmax \
LOCAL_STATIC_LIBRARIES := \
- libstagefright_vpxdec \
libvpx
LOCAL_SHARED_LIBRARIES := \
diff --git a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp b/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
deleted file mode 100644
index 489e5ad..0000000
--- a/media/libstagefright/codecs/on2/dec/VPXDecoder.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VPXDecoder"
-#include <utils/Log.h>
-
-#include "VPXDecoder.h"
-
-#include <OMX_Component.h>
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include "vpx/vpx_decoder.h"
-#include "vpx/vpx_codec.h"
-#include "vpx/vp8dx.h"
-
-namespace android {
-
-VPXDecoder::VPXDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferSize(0),
- mCtx(NULL),
- mBufferGroup(NULL),
- mTargetTimeUs(-1) {
- sp<MetaData> inputFormat = source->getFormat();
- const char *mime;
- CHECK(inputFormat->findCString(kKeyMIMEType, &mime));
- CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_VPX));
-
- CHECK(inputFormat->findInt32(kKeyWidth, &mWidth));
- CHECK(inputFormat->findInt32(kKeyHeight, &mHeight));
-
- mBufferSize = (mWidth * mHeight * 3) / 2;
-
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
- mFormat->setInt32(kKeyWidth, mWidth);
- mFormat->setInt32(kKeyHeight, mHeight);
- mFormat->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
- mFormat->setCString(kKeyDecoderComponent, "VPXDecoder");
-
- int64_t durationUs;
- if (inputFormat->findInt64(kKeyDuration, &durationUs)) {
- mFormat->setInt64(kKeyDuration, durationUs);
- }
-}
-
-VPXDecoder::~VPXDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-status_t VPXDecoder::start(MetaData *) {
- if (mStarted) {
- return UNKNOWN_ERROR;
- }
-
- status_t err = mSource->start();
-
- if (err != OK) {
- return err;
- }
-
- mCtx = new vpx_codec_ctx_t;
- vpx_codec_err_t vpx_err;
- if ((vpx_err = vpx_codec_dec_init(
- (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0))) {
- LOGE("on2 decoder failed to initialize. (%d)", vpx_err);
-
- mSource->stop();
-
- return UNKNOWN_ERROR;
- }
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
-
- mTargetTimeUs = -1;
-
- mStarted = true;
-
- return OK;
-}
-
-status_t VPXDecoder::stop() {
- if (!mStarted) {
- return UNKNOWN_ERROR;
- }
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
- delete (vpx_codec_ctx_t *)mCtx;
- mCtx = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> VPXDecoder::getFormat() {
- return mFormat;
-}
-
-status_t VPXDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- *out = NULL;
-
- bool seeking = false;
- int64_t seekTimeUs;
- ReadOptions::SeekMode seekMode;
- if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
- seeking = true;
- }
-
- MediaBuffer *input;
- status_t err = mSource->read(&input, options);
-
- if (err != OK) {
- return err;
- }
-
- LOGV("read %d bytes from source\n", input->range_length());
-
- if (seeking) {
- int64_t targetTimeUs;
- if (input->meta_data()->findInt64(kKeyTargetTime, &targetTimeUs)
- && targetTimeUs >= 0) {
- mTargetTimeUs = targetTimeUs;
- } else {
- mTargetTimeUs = -1;
- }
- }
-
- if (vpx_codec_decode(
- (vpx_codec_ctx_t *)mCtx,
- (uint8_t *)input->data() + input->range_offset(),
- input->range_length(),
- NULL,
- 0)) {
- LOGE("on2 decoder failed to decode frame.");
- input->release();
- input = NULL;
-
- return UNKNOWN_ERROR;
- }
-
- LOGV("successfully decoded 1 or more frames.");
-
- int64_t timeUs;
- CHECK(input->meta_data()->findInt64(kKeyTime, &timeUs));
-
- input->release();
- input = NULL;
-
- bool skipFrame = false;
-
- if (mTargetTimeUs >= 0) {
- CHECK(timeUs <= mTargetTimeUs);
-
- if (timeUs < mTargetTimeUs) {
- // We're still waiting for the frame with the matching
- // timestamp and we won't return the current one.
- skipFrame = true;
-
- LOGV("skipping frame at %lld us", timeUs);
- } else {
- LOGV("found target frame at %lld us", timeUs);
-
- mTargetTimeUs = -1;
- }
- }
-
- if (skipFrame) {
- *out = new MediaBuffer(0);
- return OK;
- }
-
- vpx_codec_iter_t iter = NULL;
- vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
-
- if (img == NULL) {
- // The VPX format supports "internal-only" frames that are
- // referenced by future content but never actually displayed, so
- // this is a perfectly valid scenario.
-
- *out = new MediaBuffer(0);
- return OK;
- }
-
- CHECK_EQ(img->fmt, IMG_FMT_I420);
-
- int32_t width = img->d_w;
- int32_t height = img->d_h;
-
- if (width != mWidth || height != mHeight) {
- LOGI("Image dimensions changed, width = %d, height = %d",
- width, height);
-
- mWidth = width;
- mHeight = height;
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
-
- mBufferSize = (mWidth * mHeight * 3) / 2;
- delete mBufferGroup;
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
- mBufferGroup->add_buffer(new MediaBuffer(mBufferSize));
-
- return INFO_FORMAT_CHANGED;
- }
-
- MediaBuffer *output;
- CHECK_EQ(mBufferGroup->acquire_buffer(&output), OK);
-
- const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y];
- uint8_t *dst = (uint8_t *)output->data();
- for (size_t i = 0; i < img->d_h; ++i) {
- memcpy(dst, srcLine, img->d_w);
-
- srcLine += img->stride[PLANE_Y];
- dst += img->d_w;
- }
-
- srcLine = (const uint8_t *)img->planes[PLANE_U];
- for (size_t i = 0; i < img->d_h / 2; ++i) {
- memcpy(dst, srcLine, img->d_w / 2);
-
- srcLine += img->stride[PLANE_U];
- dst += img->d_w / 2;
- }
-
- srcLine = (const uint8_t *)img->planes[PLANE_V];
- for (size_t i = 0; i < img->d_h / 2; ++i) {
- memcpy(dst, srcLine, img->d_w / 2);
-
- srcLine += img->stride[PLANE_V];
- dst += img->d_w / 2;
- }
-
- output->set_range(0, (width * height * 3) / 2);
-
- output->meta_data()->setInt64(kKeyTime, timeUs);
-
- *out = output;
-
- return OK;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
index ec7bd1c..740c957 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
@@ -23,10 +23,30 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/IOMX.h>
namespace android {
+static const CodecProfileLevel kProfileLevels[] = {
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5 },
+ { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 },
+};
+
template<class T>
static void InitOMXParams(T *params) {
params->nSize = sizeof(T);
@@ -177,6 +197,28 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamVideoProfileLevelQuerySupported:
+ {
+ OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
+ (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
+
+ if (profileLevel->nPortIndex != kInputPortIndex) {
+ LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
+ return OMX_ErrorUnsupportedIndex;
+ }
+
+ size_t index = profileLevel->nProfileIndex;
+ size_t nProfileLevels =
+ sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
+ if (index >= nProfileLevels) {
+ return OMX_ErrorNoMore;
+ }
+
+ profileLevel->eProfile = kProfileLevels[index].mProfile;
+ profileLevel->eLevel = kProfileLevels[index].mLevel;
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalGetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 9251229..f33f3ac 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -2,21 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- VorbisDecoder.cpp \
-
-LOCAL_C_INCLUDES := \
- frameworks/base/media/libstagefright/include \
- external/tremolo \
-
-LOCAL_MODULE := libstagefright_vorbisdec
-
-include $(BUILD_STATIC_LIBRARY)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
SoftVorbis.cpp
LOCAL_C_INCLUDES := \
@@ -24,9 +9,6 @@
frameworks/base/media/libstagefright/include \
frameworks/base/include/media/stagefright/openmax \
-LOCAL_STATIC_LIBRARIES := \
- libstagefright_vorbisdec
-
LOCAL_SHARED_LIBRARIES := \
libvorbisidec libstagefright libstagefright_omx \
libstagefright_foundation libutils
diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
deleted file mode 100644
index e14fb95..0000000
--- a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "VorbisDecoder"
-#include <utils/Log.h>
-
-#include "VorbisDecoder.h"
-
-#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-extern "C" {
- #include <Tremolo/codec_internal.h>
-
- int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
- int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
- int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
-}
-
-namespace android {
-
-VorbisDecoder::VorbisDecoder(const sp<MediaSource> &source)
- : mSource(source),
- mStarted(false),
- mBufferGroup(NULL),
- mAnchorTimeUs(0),
- mNumFramesOutput(0),
- mState(NULL),
- mVi(NULL) {
- sp<MetaData> srcFormat = mSource->getFormat();
- CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels));
- CHECK(srcFormat->findInt32(kKeySampleRate, &mSampleRate));
-}
-
-VorbisDecoder::~VorbisDecoder() {
- if (mStarted) {
- stop();
- }
-}
-
-static void makeBitReader(
- const void *data, size_t size,
- ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) {
- buf->data = (uint8_t *)data;
- buf->size = size;
- buf->refcount = 1;
- buf->ptr.owner = NULL;
-
- ref->buffer = buf;
- ref->begin = 0;
- ref->length = size;
- ref->next = NULL;
-
- oggpack_readinit(bits, ref);
-}
-
-status_t VorbisDecoder::start(MetaData *params) {
- CHECK(!mStarted);
-
- mBufferGroup = new MediaBufferGroup;
- mBufferGroup->add_buffer(
- new MediaBuffer(kMaxNumSamplesPerBuffer * sizeof(int16_t)));
-
- mSource->start();
-
- sp<MetaData> meta = mSource->getFormat();
-
- mVi = new vorbis_info;
- vorbis_info_init(mVi);
-
- ///////////////////////////////////////////////////////////////////////////
-
- uint32_t type;
- const void *data;
- size_t size;
- CHECK(meta->findData(kKeyVorbisInfo, &type, &data, &size));
-
- ogg_buffer buf;
- ogg_reference ref;
- oggpack_buffer bits;
- makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
- CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
-
- ///////////////////////////////////////////////////////////////////////////
-
- CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
-
- makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
- CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
-
- ///////////////////////////////////////////////////////////////////////////
-
- mState = new vorbis_dsp_state;
- CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
-
- mAnchorTimeUs = 0;
- mNumFramesOutput = 0;
-
- // If the source never limits the number of valid frames contained
- // in the input data, we'll assume that all of the decoded frames are
- // valid.
- mNumFramesLeftOnPage = -1;
-
- mStarted = true;
-
- return OK;
-}
-
-status_t VorbisDecoder::stop() {
- CHECK(mStarted);
-
- vorbis_dsp_clear(mState);
- delete mState;
- mState = NULL;
-
- vorbis_info_clear(mVi);
- delete mVi;
- mVi = NULL;
-
- delete mBufferGroup;
- mBufferGroup = NULL;
-
- mSource->stop();
-
- mStarted = false;
-
- return OK;
-}
-
-sp<MetaData> VorbisDecoder::getFormat() {
- sp<MetaData> srcFormat = mSource->getFormat();
-
- sp<MetaData> meta = new MetaData;
- meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- meta->setInt32(kKeyChannelCount, mNumChannels);
- meta->setInt32(kKeySampleRate, mSampleRate);
-
- int64_t durationUs;
- if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
- meta->setInt64(kKeyDuration, durationUs);
- }
-
- meta->setCString(kKeyDecoderComponent, "VorbisDecoder");
-
- return meta;
-}
-
-int VorbisDecoder::decodePacket(MediaBuffer *packet, MediaBuffer *out) {
- ogg_buffer buf;
- buf.data = (uint8_t *)packet->data() + packet->range_offset();
- buf.size = packet->range_length();
- buf.refcount = 1;
- buf.ptr.owner = NULL;
-
- ogg_reference ref;
- ref.buffer = &buf;
- ref.begin = 0;
- ref.length = packet->range_length();
- ref.next = NULL;
-
- ogg_packet pack;
- pack.packet = &ref;
- pack.bytes = packet->range_length();
- pack.b_o_s = 0;
- pack.e_o_s = 0;
- pack.granulepos = 0;
- pack.packetno = 0;
-
- int numFrames = 0;
-
- int err = vorbis_dsp_synthesis(mState, &pack, 1);
- if (err != 0) {
- LOGW("vorbis_dsp_synthesis returned %d", err);
- } else {
- numFrames = vorbis_dsp_pcmout(
- mState, (int16_t *)out->data(), kMaxNumSamplesPerBuffer);
-
- if (numFrames < 0) {
- LOGE("vorbis_dsp_pcmout returned %d", numFrames);
- numFrames = 0;
- }
- }
-
- if (mNumFramesLeftOnPage >= 0) {
- if (numFrames > mNumFramesLeftOnPage) {
- LOGV("discarding %d frames at end of page",
- numFrames - mNumFramesLeftOnPage);
- numFrames = mNumFramesLeftOnPage;
- }
- mNumFramesLeftOnPage -= numFrames;
- }
-
- out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels);
-
- return numFrames;
-}
-
-status_t VorbisDecoder::read(
- MediaBuffer **out, const ReadOptions *options) {
- status_t err;
-
- *out = NULL;
-
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- CHECK(seekTimeUs >= 0);
-
- mNumFramesOutput = 0;
- vorbis_dsp_restart(mState);
- } else {
- seekTimeUs = -1;
- }
-
- MediaBuffer *inputBuffer;
- err = mSource->read(&inputBuffer, options);
-
- if (err != OK) {
- return ERROR_END_OF_STREAM;
- }
-
- int64_t timeUs;
- if (inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
- mAnchorTimeUs = timeUs;
- mNumFramesOutput = 0;
- } else {
- // We must have a new timestamp after seeking.
- CHECK(seekTimeUs < 0);
- }
-
- int32_t numPageSamples;
- if (inputBuffer->meta_data()->findInt32(
- kKeyValidSamples, &numPageSamples)) {
- CHECK(numPageSamples >= 0);
- mNumFramesLeftOnPage = numPageSamples;
- }
-
- MediaBuffer *outputBuffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK);
-
- int numFrames = decodePacket(inputBuffer, outputBuffer);
-
- inputBuffer->release();
- inputBuffer = NULL;
-
- outputBuffer->meta_data()->setInt64(
- kKeyTime,
- mAnchorTimeUs
- + (mNumFramesOutput * 1000000ll) / mSampleRate);
-
- mNumFramesOutput += numFrames;
-
- *out = outputBuffer;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 8ecc17c..73b3d5b 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -36,11 +36,10 @@
#include <ctype.h>
#include <openssl/aes.h>
+#include <openssl/md5.h>
namespace android {
-const int64_t LiveSession::kMaxPlaylistAgeUs = 15000000ll;
-
LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid)
: mFlags(flags),
mUIDValid(uidValid),
@@ -59,7 +58,8 @@
mDurationUs(-1),
mSeekDone(false),
mDisconnectPending(false),
- mMonitorQueueGeneration(0) {
+ mMonitorQueueGeneration(0),
+ mRefreshState(INITIAL_MINIMUM_RELOAD_DELAY) {
if (mUIDValid) {
mHTTPDataSource->setUID(mUID);
}
@@ -175,7 +175,8 @@
mMasterURL = url;
- sp<M3UParser> playlist = fetchPlaylist(url.c_str());
+ bool dummy;
+ sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &dummy);
if (playlist == NULL) {
LOGE("unable to fetch master playlist '%s'.", url.c_str());
@@ -289,7 +290,9 @@
return OK;
}
-sp<M3UParser> LiveSession::fetchPlaylist(const char *url) {
+sp<M3UParser> LiveSession::fetchPlaylist(const char *url, bool *unchanged) {
+ *unchanged = false;
+
sp<ABuffer> buffer;
status_t err = fetchFile(url, &buffer);
@@ -297,6 +300,38 @@
return NULL;
}
+ // MD5 functionality is not available on the simulator, treat all
+ // playlists as changed.
+
+#if defined(HAVE_ANDROID_OS)
+ uint8_t hash[16];
+
+ MD5_CTX m;
+ MD5_Init(&m);
+ MD5_Update(&m, buffer->data(), buffer->size());
+
+ MD5_Final(hash, &m);
+
+ if (mPlaylist != NULL && !memcmp(hash, mPlaylistHash, 16)) {
+ // playlist unchanged
+
+ if (mRefreshState != THIRD_UNCHANGED_RELOAD_ATTEMPT) {
+ mRefreshState = (RefreshState)(mRefreshState + 1);
+ }
+
+ *unchanged = true;
+
+ LOGV("Playlist unchanged, refresh state is now %d",
+ (int)mRefreshState);
+
+ return NULL;
+ }
+
+ memcpy(mPlaylistHash, hash, sizeof(hash));
+
+ mRefreshState = INITIAL_MINIMUM_RELOAD_DELAY;
+#endif
+
sp<M3UParser> playlist =
new M3UParser(url, buffer->data(), buffer->size());
@@ -384,6 +419,63 @@
return index;
}
+bool LiveSession::timeToRefreshPlaylist(int64_t nowUs) const {
+ if (mPlaylist == NULL) {
+ CHECK_EQ((int)mRefreshState, (int)INITIAL_MINIMUM_RELOAD_DELAY);
+ return true;
+ }
+
+ int32_t targetDurationSecs;
+ CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
+
+ int64_t targetDurationUs = targetDurationSecs * 1000000ll;
+
+ int64_t minPlaylistAgeUs;
+
+ switch (mRefreshState) {
+ case INITIAL_MINIMUM_RELOAD_DELAY:
+ {
+ size_t n = mPlaylist->size();
+ if (n > 0) {
+ sp<AMessage> itemMeta;
+ CHECK(mPlaylist->itemAt(n - 1, NULL /* uri */, &itemMeta));
+
+ int64_t itemDurationUs;
+ CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
+
+ minPlaylistAgeUs = itemDurationUs;
+ break;
+ }
+
+ // fall through
+ }
+
+ case FIRST_UNCHANGED_RELOAD_ATTEMPT:
+ {
+ minPlaylistAgeUs = targetDurationUs / 2;
+ break;
+ }
+
+ case SECOND_UNCHANGED_RELOAD_ATTEMPT:
+ {
+ minPlaylistAgeUs = (targetDurationUs * 3) / 2;
+ break;
+ }
+
+ case THIRD_UNCHANGED_RELOAD_ATTEMPT:
+ {
+ minPlaylistAgeUs = targetDurationUs * 3;
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+
+ return mLastPlaylistFetchTimeUs + minPlaylistAgeUs <= nowUs;
+}
+
void LiveSession::onDownloadNext() {
size_t bandwidthIndex = getBandwidthIndex();
@@ -392,8 +484,7 @@
if (mLastPlaylistFetchTimeUs < 0
|| (ssize_t)bandwidthIndex != mPrevBandwidthIndex
- || (!mPlaylist->isComplete()
- && mLastPlaylistFetchTimeUs + kMaxPlaylistAgeUs <= nowUs)) {
+ || (!mPlaylist->isComplete() && timeToRefreshPlaylist(nowUs))) {
AString url;
if (mBandwidthItems.size() > 0) {
url = mBandwidthItems.editItemAt(bandwidthIndex).mURI;
@@ -403,11 +494,25 @@
bool firstTime = (mPlaylist == NULL);
- mPlaylist = fetchPlaylist(url.c_str());
- if (mPlaylist == NULL) {
- LOGE("failed to load playlist at url '%s'", url.c_str());
- mDataSource->queueEOS(ERROR_IO);
- return;
+ if ((ssize_t)bandwidthIndex != mPrevBandwidthIndex) {
+ // If we switch bandwidths, do not pay any heed to whether
+ // playlists changed since the last time...
+ mPlaylist.clear();
+ }
+
+ bool unchanged;
+ sp<M3UParser> playlist = fetchPlaylist(url.c_str(), &unchanged);
+ if (playlist == NULL) {
+ if (unchanged) {
+ // We succeeded in fetching the playlist, but it was
+ // unchanged from the last time we tried.
+ } else {
+ LOGE("failed to load playlist at url '%s'", url.c_str());
+ mDataSource->queueEOS(ERROR_IO);
+ return;
+ }
+ } else {
+ mPlaylist = playlist;
}
if (firstTime) {
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index e069b4d..95f2ae8 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -291,7 +291,7 @@
void finishSeekIfNecessary(int64_t videoTimeUs);
void ensureCacheIsFetching_l();
- status_t startAudioPlayer_l();
+ status_t startAudioPlayer_l(bool sendErrorNotification = true);
void postAudioSeekComplete_l();
void shutdownVideoDecoder_l();
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index 2e25dd9..0e9af69 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -53,6 +53,8 @@
static sp<HTTPBase> Create(uint32_t flags = 0);
+ static void RegisterSocketUser(int s, uid_t uid);
+
protected:
void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
diff --git a/media/libstagefright/include/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
deleted file mode 100644
index 88ba9d6..0000000
--- a/media/libstagefright/include/HTTPStream.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef HTTP_STREAM_H_
-
-#define HTTP_STREAM_H_
-
-#include <sys/types.h>
-
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class HTTPStream {
-public:
- HTTPStream();
- ~HTTPStream();
-
- void setUID(uid_t uid);
-
- status_t connect(const char *server, int port = -1, bool https = false);
- status_t disconnect();
-
- status_t send(const char *data, size_t size);
-
- // Assumes data is a '\0' terminated string.
- status_t send(const char *data);
-
- // Receive up to "size" bytes of data.
- ssize_t receive(void *data, size_t size);
-
- status_t receive_header(int *http_status);
-
- // The header key used to retrieve the status line.
- static const char *kStatusKey;
-
- bool find_header_value(
- const AString &key, AString *value) const;
-
- // Pass a negative value to disable the timeout.
- void setReceiveTimeout(int seconds);
-
- // Receive a line of data terminated by CRLF, line will be '\0' terminated
- // _excluding_ the termianting CRLF.
- status_t receive_line(char *line, size_t size);
-
- static void RegisterSocketUser(int s, uid_t uid);
-
-private:
- enum State {
- READY,
- CONNECTING,
- CONNECTED
- };
-
- State mState;
- Mutex mLock;
-
- bool mUIDValid;
- uid_t mUID;
-
- int mSocket;
-
- KeyedVector<AString, AString> mHeaders;
-
- void *mSSLContext;
- void *mSSL;
-
- HTTPStream(const HTTPStream &);
- HTTPStream &operator=(const HTTPStream &);
-};
-
-} // namespace android
-
-#endif // HTTP_STREAM_H_
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index 188ef5e..116ed0e 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -62,8 +62,6 @@
kMaxNumRetries = 5,
};
- static const int64_t kMaxPlaylistAgeUs;
-
enum {
kWhatConnect = 'conn',
kWhatDisconnect = 'disc',
@@ -106,6 +104,16 @@
int32_t mMonitorQueueGeneration;
+ enum RefreshState {
+ INITIAL_MINIMUM_RELOAD_DELAY,
+ FIRST_UNCHANGED_RELOAD_ATTEMPT,
+ SECOND_UNCHANGED_RELOAD_ATTEMPT,
+ THIRD_UNCHANGED_RELOAD_ATTEMPT
+ };
+ RefreshState mRefreshState;
+
+ uint8_t mPlaylistHash[16];
+
void onConnect(const sp<AMessage> &msg);
void onDisconnect();
void onDownloadNext();
@@ -113,7 +121,7 @@
void onSeek(const sp<AMessage> &msg);
status_t fetchFile(const char *url, sp<ABuffer> *out);
- sp<M3UParser> fetchPlaylist(const char *url);
+ sp<M3UParser> fetchPlaylist(const char *url, bool *unchanged);
size_t getBandwidthIndex();
status_t decryptBuffer(
@@ -121,6 +129,8 @@
void postMonitorQueue(int64_t delayUs = 0);
+ bool timeToRefreshPlaylist(int64_t nowUs) const;
+
static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *);
DISALLOW_EVIL_CONSTRUCTORS(LiveSession);
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
deleted file mode 100644
index c265b3a..0000000
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef NU_HTTP_DATA_SOURCE_H_
-
-#define NU_HTTP_DATA_SOURCE_H_
-
-#include <utils/List.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-
-#include "HTTPStream.h"
-#include "include/HTTPBase.h"
-
-namespace android {
-
-struct NuHTTPDataSource : public HTTPBase {
- NuHTTPDataSource(uint32_t flags = 0);
-
- virtual status_t connect(
- const char *uri,
- const KeyedVector<String8, String8> *headers = NULL,
- off64_t offset = 0);
-
- virtual void disconnect();
-
- virtual status_t initCheck() const;
-
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
- virtual status_t getSize(off64_t *size);
- virtual uint32_t flags();
-
- virtual sp<DecryptHandle> DrmInitialization();
- virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
- virtual String8 getUri();
-
- virtual String8 getMIMEType() const;
-
-protected:
- virtual ~NuHTTPDataSource();
-
-private:
- enum State {
- DISCONNECTED,
- CONNECTING,
- CONNECTED
- };
-
- Mutex mLock;
-
- uint32_t mFlags;
-
- State mState;
-
- String8 mHost;
- unsigned mPort;
- String8 mPath;
- bool mHTTPS;
- String8 mHeaders;
- String8 mUri;
-
- HTTPStream mHTTP;
- off64_t mOffset;
- off64_t mContentLength;
- bool mContentLengthValid;
- bool mHasChunkedTransferEncoding;
-
- String8 mContentType;
-
- // The number of data bytes in the current chunk before any subsequent
- // chunk header (or -1 if no more chunks).
- ssize_t mChunkDataBytesLeft;
-
- sp<DecryptHandle> mDecryptHandle;
- DrmManagerClient *mDrmManagerClient;
-
- status_t connect(
- const char *uri, const String8 &headers, off64_t offset);
-
- status_t connect(
- const char *host, unsigned port, const char *path,
- bool https,
- const String8 &headers,
- off64_t offset);
-
- // Read up to "size" bytes of data, respect transfer encoding.
- ssize_t internalRead(void *data, size_t size);
-
- void applyTimeoutResponse();
-
- static void MakeFullHeaders(
- const KeyedVector<String8, String8> *overrides,
- String8 *headers);
-
- NuHTTPDataSource(const NuHTTPDataSource &);
- NuHTTPDataSource &operator=(const NuHTTPDataSource &);
-};
-
-} // namespace android
-
-#endif // NU_HTTP_DATA_SOURCE_H_
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index ec3e5fa..d54b1c1 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -121,6 +121,7 @@
virtual ~OMX();
private:
+ struct CallbackDispatcherThread;
struct CallbackDispatcher;
Mutex mLock;
diff --git a/media/libstagefright/include/ThreadedSource.h b/media/libstagefright/include/ThreadedSource.h
deleted file mode 100644
index c67295c..0000000
--- a/media/libstagefright/include/ThreadedSource.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef THREADED_SOURCE_H_
-
-#define THREADED_SOURCE_H_
-
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AHandlerReflector.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/MediaSource.h>
-#include <utils/threads.h>
-
-namespace android {
-
-struct ThreadedSource : public MediaSource {
- ThreadedSource(const sp<MediaSource> &source);
-
- virtual status_t start(MetaData *params);
- virtual status_t stop();
-
- virtual sp<MetaData> getFormat();
-
- virtual status_t read(
- MediaBuffer **buffer, const ReadOptions *options);
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
- virtual ~ThreadedSource();
-
-private:
- enum {
- kWhatDecodeMore = 'deco',
- kWhatSeek = 'seek',
- };
-
- sp<MediaSource> mSource;
- sp<AHandlerReflector<ThreadedSource> > mReflector;
- sp<ALooper> mLooper;
-
- Mutex mLock;
- Condition mCondition;
- List<MediaBuffer *> mQueue;
- status_t mFinalResult;
- bool mDecodePending;
- bool mStarted;
-
- int64_t mSeekTimeUs;
- ReadOptions::SeekMode mSeekMode;
-
- void postDecodeMore_l();
- void clearQueue_l();
-
- DISALLOW_EVIL_CONSTRUCTORS(ThreadedSource);
-};
-
-} // namespace android
-
-#endif // THREADED_SOURCE_H_
diff --git a/media/libstagefright/include/XINGSeeker.h b/media/libstagefright/include/XINGSeeker.h
index d5a484e..ec5bd9b 100644
--- a/media/libstagefright/include/XINGSeeker.h
+++ b/media/libstagefright/include/XINGSeeker.h
@@ -37,7 +37,7 @@
int32_t mSizeBytes;
// TOC entries in XING header. Skip the first one since it's always 0.
- char mTableOfContents[99];
+ unsigned char mTableOfContents[99];
XINGSeeker();
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 08ad6f3..d844f3d 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -23,14 +23,7 @@
libui \
libcutils \
libstagefright_foundation \
-
-ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
- LOCAL_LDLIBS += -lpthread -ldl
-endif
-
-ifneq ($(TARGET_SIMULATOR),true)
-LOCAL_SHARED_LIBRARIES += libdl
-endif
+ libdl
LOCAL_MODULE:= libstagefright_omx
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index d23aa3a..bc24dbb 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -20,8 +20,6 @@
#include <dlfcn.h>
-#include <sys/prctl.h>
-
#include "../include/OMX.h"
#include "../include/OMXNodeInstance.h"
@@ -38,11 +36,32 @@
////////////////////////////////////////////////////////////////////////////////
+// This provides the underlying Thread used by CallbackDispatcher.
+// Note that deriving CallbackDispatcher from Thread does not work.
+
+struct OMX::CallbackDispatcherThread : public Thread {
+ CallbackDispatcherThread(CallbackDispatcher *dispatcher)
+ : mDispatcher(dispatcher) {
+ }
+
+private:
+ CallbackDispatcher *mDispatcher;
+
+ bool threadLoop();
+
+ CallbackDispatcherThread(const CallbackDispatcherThread &);
+ CallbackDispatcherThread &operator=(const CallbackDispatcherThread &);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
struct OMX::CallbackDispatcher : public RefBase {
CallbackDispatcher(OMXNodeInstance *owner);
void post(const omx_message &msg);
+ bool loop();
+
protected:
virtual ~CallbackDispatcher();
@@ -54,13 +73,10 @@
Condition mQueueChanged;
List<omx_message> mQueue;
- pthread_t mThread;
+ sp<CallbackDispatcherThread> mThread;
void dispatch(const omx_message &msg);
- static void *ThreadWrapper(void *me);
- void threadEntry();
-
CallbackDispatcher(const CallbackDispatcher &);
CallbackDispatcher &operator=(const CallbackDispatcher &);
};
@@ -68,13 +84,8 @@
OMX::CallbackDispatcher::CallbackDispatcher(OMXNodeInstance *owner)
: mOwner(owner),
mDone(false) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
-
- pthread_create(&mThread, &attr, ThreadWrapper, this);
-
- pthread_attr_destroy(&attr);
+ mThread = new CallbackDispatcherThread(this);
+ mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_AUDIO);
}
OMX::CallbackDispatcher::~CallbackDispatcher() {
@@ -85,11 +96,14 @@
mQueueChanged.signal();
}
- // Don't call join on myself
- CHECK(mThread != pthread_self());
-
- void *dummy;
- pthread_join(mThread, &dummy);
+ // A join on self can happen if the last ref to CallbackDispatcher
+ // is released within the CallbackDispatcherThread loop
+ status_t status = mThread->join();
+ if (status != WOULD_BLOCK) {
+ // Other than join to self, the only other error return codes are
+ // whatever readyToRun() returns, and we don't override that
+ CHECK_EQ(status, NO_ERROR);
+ }
}
void OMX::CallbackDispatcher::post(const omx_message &msg) {
@@ -107,17 +121,7 @@
mOwner->onMessage(msg);
}
-// static
-void *OMX::CallbackDispatcher::ThreadWrapper(void *me) {
- static_cast<CallbackDispatcher *>(me)->threadEntry();
-
- return NULL;
-}
-
-void OMX::CallbackDispatcher::threadEntry() {
- androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
- prctl(PR_SET_NAME, (unsigned long)"OMXCallbackDisp", 0, 0, 0);
-
+bool OMX::CallbackDispatcher::loop() {
for (;;) {
omx_message msg;
@@ -137,6 +141,14 @@
dispatch(msg);
}
+
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool OMX::CallbackDispatcherThread::threadLoop() {
+ return mDispatcher->loop();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 072d6b2..b398c9d 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -34,7 +34,7 @@
#include <openssl/md5.h>
#include <sys/socket.h>
-#include "HTTPStream.h"
+#include "HTTPBase.h"
namespace android {
@@ -251,7 +251,7 @@
mSocket = socket(AF_INET, SOCK_STREAM, 0);
if (mUIDValid) {
- HTTPStream::RegisterSocketUser(mSocket, mUID);
+ HTTPBase::RegisterSocketUser(mSocket, mUID);
}
MakeSocketBlocking(mSocket, false);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 3188959..71d68f6 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -40,7 +40,7 @@
#include <sys/socket.h>
#include <netdb.h>
-#include "HTTPStream.h"
+#include "HTTPBase.h"
// If no access units are received within 5 secs, assume that the rtp
// stream has ended and signal end of stream.
@@ -1181,8 +1181,8 @@
&info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
if (mUIDValid) {
- HTTPStream::RegisterSocketUser(info->mRTPSocket, mUID);
- HTTPStream::RegisterSocketUser(info->mRTCPSocket, mUID);
+ HTTPBase::RegisterSocketUser(info->mRTPSocket, mUID);
+ HTTPBase::RegisterSocketUser(info->mRTCPSocket, mUID);
}
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index c25285e..e590bab 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -16,8 +16,6 @@
LOCAL_PATH:= $(call my-dir)
-ifneq ($(TARGET_SIMULATOR),true)
-
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -45,8 +43,6 @@
include $(BUILD_SHARED_LIBRARY)
-endif
-
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 817eac05..20225ba 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -345,56 +345,28 @@
#ifdef MTP_DEVICE
int MtpDataPacket::read(int fd) {
- // first read the header
- int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret != MTP_CONTAINER_HEADER_SIZE)
+ int ret = ::read(fd, mBuffer, mBufferSize);
+ if (ret < MTP_CONTAINER_HEADER_SIZE)
return -1;
- // then the following data
- int total = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
- allocate(total);
- int remaining = total - MTP_CONTAINER_HEADER_SIZE;
- ret = ::read(fd, &mBuffer[0] + MTP_CONTAINER_HEADER_SIZE, remaining);
- if (ret != remaining)
- return -1;
-
- mPacketSize = total;
+ mPacketSize = ret;
mOffset = MTP_CONTAINER_HEADER_SIZE;
- return total;
-}
-
-int MtpDataPacket::readDataHeader(int fd) {
- int ret = ::read(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret > 0)
- mPacketSize = ret;
- else
- mPacketSize = 0;
return ret;
}
int MtpDataPacket::write(int fd) {
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- // send header separately from data
- int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret == MTP_CONTAINER_HEADER_SIZE)
- ret = ::write(fd, mBuffer + MTP_CONTAINER_HEADER_SIZE,
- mPacketSize - MTP_CONTAINER_HEADER_SIZE);
- return (ret < 0 ? ret : 0);
-}
-
-int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
- MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
- MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
+ int ret = ::write(fd, mBuffer, mPacketSize);
return (ret < 0 ? ret : 0);
}
int MtpDataPacket::writeData(int fd, void* data, uint32_t length) {
- MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length + MTP_CONTAINER_HEADER_SIZE);
+ allocate(length);
+ memcpy(mBuffer + MTP_CONTAINER_HEADER_SIZE, data, length);
+ length += MTP_CONTAINER_HEADER_SIZE;
+ MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
- int ret = ::write(fd, mBuffer, MTP_CONTAINER_HEADER_SIZE);
- if (ret == MTP_CONTAINER_HEADER_SIZE)
- ret = ::write(fd, data, length);
+ int ret = ::write(fd, mBuffer, length);
return (ret < 0 ? ret : 0);
}
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 8a08948..2b81063 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -41,6 +41,7 @@
void setOperationCode(MtpOperationCode code);
void setTransactionID(MtpTransactionID id);
+ inline const uint8_t* getData() const { return mBuffer + MTP_CONTAINER_HEADER_SIZE; }
inline uint8_t getUInt8() { return (uint8_t)mBuffer[mOffset++]; }
inline int8_t getInt8() { return (int8_t)mBuffer[mOffset++]; }
uint16_t getUInt16();
@@ -95,11 +96,9 @@
#ifdef MTP_DEVICE
// fill our buffer with data from the given file descriptor
int read(int fd);
- int readDataHeader(int fd);
// write our data to the given file descriptor
int write(int fd);
- int writeDataHeader(int fd, uint32_t length);
int writeData(int fd, void* data, uint32_t length);
#endif
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 9085f10..a9b539b 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -237,6 +237,8 @@
if (mSessionOpen)
mDatabase->sessionEnded();
+ close(fd);
+ mFD = -1;
}
void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
@@ -729,14 +731,12 @@
}
mfr.offset = 0;
mfr.length = fileLength;
-
- // send data header
- mData.setOperationCode(mRequest.getOperationCode());
- mData.setTransactionID(mRequest.getTransactionID());
- mData.writeDataHeader(mFD, fileLength + MTP_CONTAINER_HEADER_SIZE);
+ mfr.command = mRequest.getOperationCode();
+ mfr.transaction_id = mRequest.getTransactionID();
// then transfer the file
- int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
+ int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+ LOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
close(mfr.fd);
if (ret < 0) {
if (errno == ECANCELED)
@@ -796,15 +796,13 @@
}
mfr.offset = offset;
mfr.length = length;
+ mfr.command = mRequest.getOperationCode();
+ mfr.transaction_id = mRequest.getTransactionID();
mResponse.setParameter(1, length);
- // send data header
- mData.setOperationCode(mRequest.getOperationCode());
- mData.setTransactionID(mRequest.getTransactionID());
- mData.writeDataHeader(mFD, length + MTP_CONTAINER_HEADER_SIZE);
-
- // then transfer the file
- int ret = ioctl(mFD, MTP_SEND_FILE, (unsigned long)&mfr);
+ // transfer the file
+ int ret = ioctl(mFD, MTP_SEND_FILE_WITH_HEADER, (unsigned long)&mfr);
+ LOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
close(mfr.fd);
if (ret < 0) {
if (errno == ECANCELED)
@@ -916,7 +914,7 @@
return MTP_RESPONSE_GENERAL_ERROR;
MtpResponseCode result = MTP_RESPONSE_OK;
mode_t mask;
- int ret;
+ int ret, initialData;
if (mSendObjectHandle == kInvalidObjectHandle) {
LOGE("Expected SendObjectInfo before SendObject");
@@ -924,12 +922,13 @@
goto done;
}
- // read the header
- ret = mData.readDataHeader(mFD);
- // FIXME - check for errors here.
-
- // reset so we don't attempt to send this back
- mData.reset();
+ // read the header, and possibly some data
+ ret = mData.read(mFD);
+ if (ret < MTP_CONTAINER_HEADER_SIZE) {
+ result = MTP_RESPONSE_GENERAL_ERROR;
+ goto done;
+ }
+ initialData = ret - MTP_CONTAINER_HEADER_SIZE;
mtp_file_range mfr;
mfr.fd = open(mSendObjectFilePath, O_RDWR | O_CREAT | O_TRUNC);
@@ -943,16 +942,20 @@
fchmod(mfr.fd, mFilePermission);
umask(mask);
- mfr.offset = 0;
- mfr.length = mSendObjectFileSize;
+ if (initialData > 0)
+ ret = write(mfr.fd, mData.getData(), initialData);
- LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
- // transfer the file
- ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ if (mSendObjectFileSize - initialData > 0) {
+ mfr.offset = initialData;
+ mfr.length = mSendObjectFileSize - initialData;
+
+ LOGV("receiving %s\n", (const char *)mSendObjectFilePath);
+ // transfer the file
+ ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ LOGV("MTP_RECEIVE_FILE returned %d\n", ret);
+ }
close(mfr.fd);
- LOGV("MTP_RECEIVE_FILE returned %d", ret);
-
if (ret < 0) {
unlink(mSendObjectFilePath);
if (errno == ECANCELED)
@@ -962,6 +965,9 @@
}
done:
+ // reset so we don't attempt to send the data back
+ mData.reset();
+
mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat,
result == MTP_RESPONSE_OK);
mSendObjectHandle = kInvalidObjectHandle;
@@ -1094,23 +1100,31 @@
return MTP_RESPONSE_GENERAL_ERROR;
}
- // read the header
- int ret = mData.readDataHeader(mFD);
- // FIXME - check for errors here.
-
- // reset so we don't attempt to send this back
- mData.reset();
-
const char* filePath = (const char *)edit->mPath;
- LOGV("receiving partial %s %lld %ld\n", filePath, offset, length);
- mtp_file_range mfr;
- mfr.fd = edit->mFD;
- mfr.offset = offset;
- mfr.length = length;
+ LOGV("receiving partial %s %lld %lld\n", filePath, offset, length);
- // transfer the file
- ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
- LOGV("MTP_RECEIVE_FILE returned %d", ret);
+ // read the header, and possibly some data
+ int ret = mData.read(mFD);
+ if (ret < MTP_CONTAINER_HEADER_SIZE)
+ return MTP_RESPONSE_GENERAL_ERROR;
+ int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
+
+ if (initialData > 0) {
+ ret = write(edit->mFD, mData.getData(), initialData);
+ offset += initialData;
+ length -= initialData;
+ }
+
+ if (length > 0) {
+ mtp_file_range mfr;
+ mfr.fd = edit->mFD;
+ mfr.offset = offset;
+ mfr.length = length;
+
+ // transfer the file
+ ret = ioctl(mFD, MTP_RECEIVE_FILE, (unsigned long)&mfr);
+ LOGV("MTP_RECEIVE_FILE returned %d", ret);
+ }
if (ret < 0) {
mResponse.setParameter(1, 0);
if (errno == ECANCELED)
@@ -1118,6 +1132,9 @@
else
return MTP_RESPONSE_GENERAL_ERROR;
}
+
+ // reset so we don't attempt to send this back
+ mData.reset();
mResponse.setParameter(1, length);
uint64_t end = offset + length;
if (end > edit->mSize) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java
index 59783e5..4d517db 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPropertiesTest.java
@@ -91,8 +91,12 @@
assertEquals("AudioType Mismatch ", audioCodecType, mvi.getAudioType());
assertEquals("Audio Sampling " + mvi.getAudioSamplingFrequency(),
audioSamplingFrequency, mvi.getAudioSamplingFrequency());
- assertEquals("Audio Channels " + mvi.getAudioChannels(), audioChannel,
- mvi.getAudioChannels());
+ // PV SW AAC codec always returns number of channels as Stereo.
+ // So we do not assert for number of audio channels for AAC_LC
+ if ( audioCodecType != MediaProperties.ACODEC_AAC_LC ) {
+ assertEquals("Audio Channels " + mvi.getAudioChannels(), audioChannel,
+ mvi.getAudioChannels());
+ }
}
protected void validateAudioProperties(int audioCodecType, int duration,
@@ -103,8 +107,12 @@
duration, aT.getDuration(), 10));
assertEquals("Audio Sampling " + aT.getAudioSamplingFrequency(),
audioSamplingFrequency, aT.getAudioSamplingFrequency());
- assertEquals("Audio Channels " + aT.getAudioChannels(), audioChannel,
- aT.getAudioChannels());
+ // PV SW AAC codec always returns number of channels as Stereo.
+ // So we do not assert for number of audio channels for AAC_LC
+ if ( audioCodecType != MediaProperties.ACODEC_AAC_LC ) {
+ assertEquals("Audio Channels " + aT.getAudioChannels(), audioChannel,
+ aT.getAudioChannels());
+ }
}
protected void validateImageProperties(int aspectRatio, int fileType,
diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp
index 2c0e88e..5c016c4 100644
--- a/native/android/native_window.cpp
+++ b/native/android/native_window.cpp
@@ -81,39 +81,9 @@
int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
ARect* inOutDirtyBounds) {
- int type = -1;
- if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &type) != 0 ||
- type != NATIVE_WINDOW_SURFACE) {
- return BAD_VALUE;
- }
-
- Region dirtyRegion;
- Region* dirtyParam = NULL;
- if (inOutDirtyBounds != NULL) {
- dirtyRegion.set(*(Rect*)inOutDirtyBounds);
- dirtyParam = &dirtyRegion;
- }
-
- Surface::SurfaceInfo info;
- status_t res = static_cast<Surface*>(window)->lock(&info, dirtyParam);
- if (res != OK) {
- return -1;
- }
-
- outBuffer->width = (int32_t)info.w;
- outBuffer->height = (int32_t)info.h;
- outBuffer->stride = (int32_t)info.s;
- outBuffer->format = (int32_t)info.format;
- outBuffer->bits = info.bits;
-
- if (inOutDirtyBounds != NULL) {
- *inOutDirtyBounds = dirtyRegion.getBounds();
- }
-
- return 0;
+ return window->perform(window, NATIVE_WINDOW_LOCK, outBuffer, inOutDirtyBounds);
}
int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) {
- status_t res = static_cast<Surface*>(window)->unlockAndPost();
- return res == android::OK ? 0 : -1;
+ return window->perform(window, NATIVE_WINDOW_UNLOCK_AND_POST);
}
diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h
index 337fa96..2f4f2d3 100644
--- a/native/include/android/native_window.h
+++ b/native/include/android/native_window.h
@@ -99,10 +99,16 @@
* width and height must be either both zero or both non-zero.
*
*/
-int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
+int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
+ int32_t width, int32_t height, int32_t format);
/**
* Lock the window's next drawing surface for writing.
+ * inOutDirtyBounds is used as an in/out parameter, upon entering the
+ * function, it contains the dirty region, that is, the region the caller
+ * intends to redraw. When the function returns, inOutDirtyBounds is updated
+ * with the actual area the caller needs to redraw -- this region is often
+ * extended by ANativeWindow_lock.
*/
int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
ARect* inOutDirtyBounds);
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
index e0c38b1..99cbb86 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -67,7 +67,11 @@
/** get service handles */
private static void initService() {
- sService = sAdapter.getNfcAdapterExtrasInterface();
+ final INfcAdapterExtras service = sAdapter.getNfcAdapterExtrasInterface();
+ if (service != null) {
+ // Leave stale rather than receive a null value.
+ sService = service;
+ }
}
/**
@@ -84,18 +88,19 @@
if (sSingleton == null) {
try {
sAdapter = adapter;
- sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
sSingleton = new NfcAdapterExtras();
sEmbeddedEe = new NfcExecutionEnvironment(sSingleton);
+ sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
sRouteOnWhenScreenOn = new CardEmulationRoute(
CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
initService();
} finally {
- if (sSingleton == null) {
- sService = null;
- sEmbeddedEe = null;
- sRouteOff = null;
+ if (sService == null) {
sRouteOnWhenScreenOn = null;
+ sRouteOff = null;
+ sEmbeddedEe = null;
+ sSingleton = null;
+ sAdapter = null;
}
}
}
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 1123e16..6a199db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -226,7 +226,7 @@
#ifndef EGL_ANDROID_image_native_buffer
#define EGL_ANDROID_image_native_buffer 1
struct ANativeWindowBuffer;
-#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
#endif
#ifndef EGL_ANDROID_swap_rectangle
@@ -237,6 +237,11 @@
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
#endif
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID 0x3142 /* EGLConfig attribute */
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 32d1a23..3f547fd 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -88,7 +88,7 @@
* well as how many bits are allocated to each channel. Therefore, the first thing
* GLSurfaceView has to do when starting to render is choose what EGLConfig to use.
* <p>
- * By default GLSurfaceView chooses a EGLConfig that has an RGB_656 pixel format,
+ * By default GLSurfaceView chooses a EGLConfig that has an RGB_565 pixel format,
* with at least a 16-bit depth buffer and no stencil.
* <p>
* If you would prefer a different EGLConfig
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index b5c018f..15e58f2 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -38,15 +38,13 @@
LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
-ifneq ($(TARGET_SIMULATOR),true)
- # we need to access the private Bionic header <bionic_tls.h>
- # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
- # behavior from the bionic Android.mk file
- ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
- LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
- endif
- LOCAL_C_INCLUDES += bionic/libc/private
+# we need to access the private Bionic header <bionic_tls.h>
+# on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
+# behavior from the bionic Android.mk file
+ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
+LOCAL_C_INCLUDES += bionic/libc/private
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
LOCAL_MODULE:= libGLES_android
diff --git a/opengl/libagl2/Android.mk b/opengl/libagl2/Android.mk
index 564932f..b442a2d 100644
--- a/opengl/libagl2/Android.mk
+++ b/opengl/libagl2/Android.mk
@@ -39,15 +39,13 @@
LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
-ifneq ($(TARGET_SIMULATOR),true)
- # we need to access the private Bionic header <bionic_tls.h>
- # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
- # behavior from the bionic Android.mk file
- ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
- LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
- endif
- LOCAL_C_INCLUDES += bionic/libc/private
+# we need to access the private Bionic header <bionic_tls.h>
+# on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
+# behavior from the bionic Android.mk file
+ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
+LOCAL_C_INCLUDES += bionic/libc/private
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
#replace libagl for now
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index ff45edc..3e66a13 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -21,18 +21,14 @@
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
-# needed on sim build because of weird logging issues
-ifeq ($(TARGET_SIMULATOR),true)
-else
- LOCAL_SHARED_LIBRARIES += libdl
- # Bionic's private TLS header relies on the ARCH_ARM_HAVE_TLS_REGISTER to
- # select the appropriate TLS codepath
- ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
- LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
- endif
- # we need to access the private Bionic header <bionic_tls.h>
- LOCAL_C_INCLUDES += bionic/libc/private
+LOCAL_SHARED_LIBRARIES += libdl
+# Bionic's private TLS header relies on the ARCH_ARM_HAVE_TLS_REGISTER to
+# select the appropriate TLS codepath
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
+# we need to access the private Bionic header <bionic_tls.h>
+LOCAL_C_INCLUDES += bionic/libc/private
LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
@@ -81,16 +77,12 @@
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libGLESv1_CM
-# needed on sim build because of weird logging issues
-ifeq ($(TARGET_SIMULATOR),true)
-else
- LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the private Bionic header <bionic_tls.h>
- ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
- LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
- endif
- LOCAL_C_INCLUDES += bionic/libc/private
+LOCAL_SHARED_LIBRARIES += libdl
+# we need to access the private Bionic header <bionic_tls.h>
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
+LOCAL_C_INCLUDES += bionic/libc/private
LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
@@ -117,16 +109,12 @@
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libGLESv2
-# needed on sim build because of weird logging issues
-ifeq ($(TARGET_SIMULATOR),true)
-else
- LOCAL_SHARED_LIBRARIES += libdl
- # we need to access the private Bionic header <bionic_tls.h>
- ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
- LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
- endif
- LOCAL_C_INCLUDES += bionic/libc/private
+LOCAL_SHARED_LIBRARIES += libdl
+# we need to access the private Bionic header <bionic_tls.h>
+ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
+LOCAL_C_INCLUDES += bionic/libc/private
LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index b11db32..ddad2d3 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -31,6 +31,7 @@
#include <cutils/properties.h>
#include <cutils/memory.h>
+#include <utils/CallStack.h>
#include <utils/String8.h>
#include "egldefs.h"
@@ -147,6 +148,10 @@
if (egl_tls_t::logNoContextCall()) {
LOGE("call to OpenGL ES API with no current context "
"(logged once per thread)");
+ LOGE("call stack before error:");
+ CallStack stack;
+ stack.update();
+ stack.dump();
}
return 0;
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 7d5d010..ba5d29a 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -367,7 +367,12 @@
if (cnx->egl.eglGetConfigAttrib(iDpy,
iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
if (format != 0) {
- native_window_set_buffers_geometry(window, 0, 0, format);
+ int err = native_window_set_buffers_format(window, format);
+ if (err != 0) {
+ LOGE("error setting native window pixel format: %s (%d)",
+ strerror(-err), err);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
}
}
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
index 9f6e68c..c2b1142 100644
--- a/opengl/libs/GLES2_dbg/Android.mk
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -31,15 +31,13 @@
LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
-ifneq ($(TARGET_SIMULATOR),true)
- # we need to access the private Bionic header <bionic_tls.h>
- # on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
- # behavior from the bionic Android.mk file
- ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
- LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
- endif
- LOCAL_C_INCLUDES += bionic/libc/private
+# we need to access the private Bionic header <bionic_tls.h>
+# on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
+# behavior from the bionic Android.mk file
+ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
+ LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
+LOCAL_C_INCLUDES += bionic/libc/private
LOCAL_MODULE:= libGLESv2_dbg
LOCAL_MODULE_TAGS := optional
diff --git a/opengl/libs/GLES2_dbg/test/Android.mk b/opengl/libs/GLES2_dbg/test/Android.mk
index 14a84b4..8708d43 100644
--- a/opengl/libs/GLES2_dbg/test/Android.mk
+++ b/opengl/libs/GLES2_dbg/test/Android.mk
@@ -27,9 +27,7 @@
ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
endif
-ifneq ($(TARGET_SIMULATOR),true)
- LOCAL_C_INCLUDES += bionic/libc/private
-endif
+LOCAL_C_INCLUDES += bionic/libc/private
LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
diff --git a/opengl/specs/EGL_ANDROID_blob_cache.txt b/opengl/specs/EGL_ANDROID_blob_cache.txt
new file mode 100644
index 0000000..55dc900
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_blob_cache.txt
@@ -0,0 +1,208 @@
+Name
+
+ ANDROID_blob_cache
+
+Name Strings
+
+ EGL_ANDROID_blob_cache
+
+Contributors
+
+ Jamie Gennis
+
+Contact
+
+ Jamie Gennis, Google Inc. (jgennis 'at' google.com)
+
+Status
+
+ Draft.
+
+Version
+
+ Version 1, April 22, 2011
+
+Number
+
+ EGL Extension #XXX
+
+Dependencies
+
+ Requires EGL 1.0
+
+ This extension is written against the wording of the EGL 1.4 Specification
+
+Overview
+
+ Shader compilation and optimization has been a troublesome aspect of OpenGL
+ programming for a long time. It can consume seconds of CPU cycles during
+ application start-up. Additionally, state-based re-compiles done
+ internally by the drivers add an unpredictable element to application
+ performance tuning, often leading to occasional pauses in otherwise smooth
+ animations.
+
+ This extension provides a mechanism through which client API
+ implementations may cache shader binaries after they are compiled. It may
+ then retrieve those cached shaders during subsequent executions of the same
+ program. The management of the cache is handled by the application (or
+ middleware), allowing it to be tuned to a particular platform or
+ environment.
+
+ While the focus of this extension is on providing a persistent cache for
+ shader binaries, it may also be useful for caching other data. This is
+ perfectly acceptable, but the guarantees provided (or lack thereof) were
+ designed around the shader use case.
+
+ Note that although this extension is written as if the application
+ implements the caching functionality, on the Android OS it is implemented
+ as part of the Android EGL module. This extension is not exposed to
+ applications on Android, but will be used automatically in every
+ application that uses EGL if it is supported by the underlying
+ device-specific EGL implementation.
+
+New Types
+
+ /*
+ * EGLsizei is a signed integer type for representing the size of a memory
+ * buffer.
+ */
+ #include <khrplatform.h>
+ typedef khronos_ssize_t EGLsizei;
+
+ /*
+ * EGLSetBlobFunc is a pointer to an application-provided function that a
+ * client API implementation may use to insert a key/value pair into the
+ * cache.
+ */
+ typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize,
+ const void* value, EGLsizei valueSize)
+
+ /*
+ * EGLGetBlobFunc is a pointer to an application-provided function that a
+ * client API implementation may use to retrieve a cached value from the
+ * cache.
+ */
+ typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize,
+ void* value, EGLsizei valueSize)
+
+New Procedures and Functions
+
+ void eglSetBlobCacheFuncs(EGLDisplay dpy,
+ EGLSetBlobFunc set,
+ EGLGetBlobFunc get);
+
+New Tokens
+
+ None.
+
+Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Add a new subsection after Section 3.8, page 50
+ (Synchronization Primitives)
+
+ "3.9 Persistent Caching
+
+ In order to facilitate persistent caching of internal client API state that
+ is slow to compute or collect, the application may specify callback
+ function pointers through which the client APIs can request data be cached
+ and retrieved. The command
+
+ void eglSetBlobCacheFuncs(EGLDisplay dpy,
+ EGLSetBlobFunc set, EGLGetBlobFunc get);
+
+ sets the callback function pointers that client APIs associated with
+ display <dpy> can use to interact with caching functionality provided by
+ the application. <set> points to a function that inserts a new value into
+ the cache and associates it with the given key. <get> points to a function
+ that retrieves from the cache the value associated with a given key. The
+ semantics of these callback functions are described in Section 3.9.1 (Cache
+ Operations).
+
+ Cache functions may only be specified once during the lifetime of an
+ EGLDisplay. The <set> and <get> functions may be called at any time and
+ from any thread from the time at which eglSetBlobCacheFuncs is called until
+ the time that the last resource associated with <dpy> is deleted and <dpy>
+ itself is terminated. Concurrent calls to these functions from different
+ threads is also allowed.
+
+ If eglSetBlobCacheFuncs generates an error then all client APIs must behave
+ as though eglSetBlobCacheFuncs was not called for the display <dpy>. If
+ <set> or <get> is NULL then an EGL_BAD_PARAMETER error is generated. If a
+ successful eglSetBlobCacheFuncs call was already made for <dpy> and the
+ display has not since been terminated then an EGL_BAD_PARAMETER error is
+ generated.
+
+ 3.9.1 Cache Operations
+
+ To insert a new binary value into the cache and associate it with a given
+ key, a client API implementation can call the application-provided callback
+ function
+
+ void (*set) (const void* key, EGLsizei keySize, const void* value,
+ EGLsizei valueSize)
+
+ <key> and <value> are pointers to the beginning of the key and value,
+ respectively, that are to be inserted. <keySize> and <valueSize> specify
+ the size in bytes of the data pointed to by <key> and <value>,
+ respectively.
+
+ No guarantees are made as to whether a given key/value pair is present in
+ the cache after the set call. If a different value has been associated
+ with the given key in the past then it is undefined which value, if any, is
+ associated with the key after the set call. Note that while there are no
+ guarantees, the cache implementation should attempt to cache the most
+ recently set value for a given key.
+
+ To retrieve the binary value associated with a given key from the cache, a
+ client API implementation can call the application-provided callback
+ function
+
+ EGLsizei (*get) (const void* key, EGLsizei keySize, void* value,
+ EGLsizei valueSize)
+
+ <key> is a pointer to the beginning of the key. <keySize> specifies the
+ size in bytes of the binary key pointed to by <key>. If the cache contains
+ a value associated with the given key then the size of that binary value in
+ bytes is returned. Otherwise 0 is returned.
+
+ If the cache contains a value for the given key and its size in bytes is
+ less than or equal to <valueSize> then the value is written to the memory
+ pointed to by <value>. Otherwise nothing is written to the memory pointed
+ to by <value>.
+
+Issues
+
+ 1. How should errors be handled in the callback functions?
+
+ RESOLVED: No guarantees are made about the presence of values in the cache,
+ so there should not be a need to return error information to the client API
+ implementation. The cache implementation can simply drop a value if it
+ encounters an error during the 'set' callback. Similarly, it can simply
+ return 0 if it encouters an error in a 'get' callback.
+
+ 2. When a client API driver gets updated, that may need to invalidate
+ previously cached entries. How can the driver handle this situation?
+
+ RESPONSE: There are a number of ways the driver can handle this situation.
+ The recommended way is to include the driver version in all cache keys.
+ That way each driver version will use a set of cache keys that are unique
+ to that version, and conflicts should never occur. Updating the driver
+ could then leave a number of values in the cache that will never be
+ requested again. If needed, the cache implementation can handle those
+ values in some way, but the driver does not need to take any special
+ action.
+
+ 3. How much data can be stored in the cache?
+
+ RESPONSE: This is entirely dependent upon the cache implementation.
+ Presumably it will be tuned to store enough data to be useful, but not
+ enough to become problematic. :)
+
+Revision History
+
+#2 (Jamie Gennis, April 25, 2011)
+ - Swapped the order of the size and pointer arguments to the get and set
+ functions.
+
+#1 (Jamie Gennis, April 22, 2011)
+ - Initial draft.
diff --git a/opengl/specs/EGL_ANDROID_recordable.txt b/opengl/specs/EGL_ANDROID_recordable.txt
new file mode 100644
index 0000000..8dbd26f
--- /dev/null
+++ b/opengl/specs/EGL_ANDROID_recordable.txt
@@ -0,0 +1,140 @@
+Name
+
+ ANDROID_recordable
+
+Name Strings
+
+ EGL_ANDROID_recordable
+
+Contributors
+
+ Jamie Gennis
+
+Contact
+
+ Jamie Gennis, Google Inc. (jgennis 'at' google.com)
+
+Status
+
+ Draft.
+
+Version
+
+ Version 1, July 8, 2011
+
+Number
+
+ EGL Extension #XXX
+
+Dependencies
+
+ Requires EGL 1.0
+
+ This extension is written against the wording of the EGL 1.4 Specification
+
+Overview
+
+ Android supports a number of different ANativeWindow implementations that
+ can be used to create an EGLSurface. One implementation, which records the
+ rendered image as a video each time eglSwapBuffers gets called, may have
+ some device-specific restrictions. Because of this, some EGLConfigs may be
+ incompatible with these ANativeWindows. This extension introduces a new
+ boolean EGLConfig attribute that indicates whether the EGLConfig supports
+ rendering to an ANativeWindow that records images to a video.
+
+New Types
+
+ None.
+
+New Procedures and Functions
+
+ None.
+
+New Tokens
+
+ Accepted by the <attribute> parameter of eglGetConfigAttrib and
+ the <attrib_list> parameter of eglChooseConfig:
+
+ EGL_RECORDABLE_ANDROID 0x3142
+
+Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
+
+ Section 3.4, Configuration Management, add a row to Table 3.1.
+
+ Attribute Type Notes
+ ---------------------- ------- --------------------------
+ EGL_RECORDABLE_ANDROID boolean whether video recording is
+ supported
+
+ Section 3.4, Configuration Management, add a row to Table 3.4.
+
+ Attribute Default Selection Sort Sort
+ Criteria Order Priority
+ ---------------------- ------------- --------- ----- --------
+ EGL_RECORDABLE_ANDROID EGL_DONT_CARE Exact None
+
+ Section 3.4, Configuration Management, add a paragraph at the end of the
+ subsection titled Other EGLConfig Attribute Descriptions.
+
+ EGL_RECORDABLE_ANDROID is a boolean indicating whether the config may
+ be used to create an EGLSurface from an ANativeWindow that is a video
+ recorder as indicated by the NATIVE_WINDOW_IS_VIDEO_RECORDER query on
+ the ANativeWindow.
+
+ Section 3.4.1, Querying Configurations, change the last paragraph as follow
+
+ EGLConfigs are not sorted with respect to the parameters
+ EGL_BIND_TO_TEXTURE_RGB, EGL_BIND_TO_TEXTURE_RGBA, EGL_CONFORMANT,
+ EGL_LEVEL, EGL_NATIVE_RENDERABLE, EGL_MAX_SWAP_INTERVAL,
+ EGL_MIN_SWAP_INTERVAL, EGL_RENDERABLE_TYPE, EGL_SURFACE_TYPE,
+ EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RED_VALUE,
+ EGL_TRANSPARENT_GREEN_VALUE, EGL_TRANSPARENT_BLUE_VALUE, and
+ EGL_RECORDABLE_ANDROID.
+
+Issues
+
+ 1. Should this functionality be exposed as a new attribute or as a bit in
+ the EGL_SURFACE_TYPE bitfield?
+
+ RESOLVED: It should be a new attribute. It does not make sense to use up a
+ bit in the limit-size bitfield for a platform-specific extension.
+
+ 2. How should the new attribute affect the sorting of EGLConfigs?
+
+ RESOLVED: It should not affect sorting. Some implementations may not have
+ any drawback associated with using a recordable EGLConfig. Such
+ implementations should not have to double-up some of their configs to one
+ sort earlier than . Implementations that do have drawbacks can use the
+ existing caveat mechanism to report this drawback to the client.
+
+ 3. How is this extension expected to be implemented?
+
+ RESPONSE: There are two basic approaches to implementing this extension
+ that were considered during its design. In both cases it is assumed that a
+ color space conversion must be performed at some point because most video
+ encoding formats use a YUV color space. The two approaches are
+ distinguished by the point at which this color space conversion is
+ performed.
+
+ One approach involves performing the color space conversion as part of the
+ eglSwapBuffers call before queuing the rendered image to the ANativeWindow.
+ In this case, the VisualID of the EGLConfig would correspond to a YUV
+ Android HAL pixel format from which the video encoder can read. The
+ EGLConfig would likely have the EGL_SLOW_CONFIG caveat because using that
+ config to render normal window contents would result in an RGB -> YUV color
+ space conversion when rendering the frame as well as a YUV -> RGB
+ conversion when compositing the window.
+
+ The other approach involves performing the color space conversion in the
+ video encoder. In this case, the VisualID of the EGLConfig would
+ correspond to an RGB HAL pixel format from which the video encoder can
+ read. The EGLConfig would likely not need to have any caveat set, as using
+ this config for normal window rendering would not have any added cost.
+
+Revision History
+
+#2 (Jamie Gennis, July 15, 2011)
+ - Added issue 3.
+
+#1 (Jamie Gennis, July 8, 2011)
+ - Initial draft.
diff --git a/opengl/specs/README b/opengl/specs/README
new file mode 100644
index 0000000..2fa2587
--- /dev/null
+++ b/opengl/specs/README
@@ -0,0 +1,12 @@
+This directory contains OpenGL ES and EGL extension specifications that have
+been or are being defined for Android.
+
+The table below tracks usage of EGL enumerant values that have been reserved
+for use by Android extensions.
+
+ Value Extension
+---------------- ----------------------------------
+0x3140 EGL_ANDROID_image_native_buffer
+0x3141 (unused)
+0x3142 EGL_ANDROID_recordable
+0x3143 - 0x314F (unused)
diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
index ab5f4bd..92d7eb1 100644
--- a/opengl/tests/EGLTest/Android.mk
+++ b/opengl/tests/EGLTest/Android.mk
@@ -2,8 +2,6 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_MODULE := EGL_test
LOCAL_MODULE_TAGS := tests
@@ -29,8 +27,6 @@
include $(BUILD_EXECUTABLE)
-endif
-
# Include subdirectory makefiles
# ============================================================
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
index e8b6c57..5d90ff6 100644
--- a/opengl/tests/gl2_jni/Android.mk
+++ b/opengl/tests/gl2_jni/Android.mk
@@ -2,8 +2,6 @@
# OpenGL ES JNI sample
# This makefile builds both an activity and a shared library.
#########################################################################
-ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
-
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
@@ -47,5 +45,3 @@
include $(BUILD_SHARED_LIBRARY)
-
-endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
index 4acd91f..3d20e72 100644
--- a/opengl/tests/gl_jni/Android.mk
+++ b/opengl/tests/gl_jni/Android.mk
@@ -2,8 +2,6 @@
# OpenGL ES JNI sample
# This makefile builds both an activity and a shared library.
#########################################################################
-ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
-
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
@@ -49,5 +47,3 @@
include $(BUILD_SHARED_LIBRARY)
-
-endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
index 4b79569..65e50e9 100644
--- a/opengl/tests/gl_perfapp/Android.mk
+++ b/opengl/tests/gl_perfapp/Android.mk
@@ -2,8 +2,6 @@
# OpenGL ES Perf App
# This makefile builds both an activity and a shared library.
#########################################################################
-ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
-
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
@@ -50,5 +48,3 @@
include $(BUILD_SHARED_LIBRARY)
-
-endif # TARGET_SIMULATOR
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
index f1a998a..b4b378e 100644
--- a/opengl/tests/gldual/Android.mk
+++ b/opengl/tests/gldual/Android.mk
@@ -2,8 +2,6 @@
# OpenGL ES JNI sample
# This makefile builds both an activity and a shared library.
#########################################################################
-ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
-
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
@@ -47,5 +45,3 @@
include $(BUILD_SHARED_LIBRARY)
-
-endif # TARGET_SIMULATOR
diff --git a/opengl/tests/testPauseResume/Android.mk b/opengl/tests/testPauseResume/Android.mk
index 450473a..cf8bdc3 100644
--- a/opengl/tests/testPauseResume/Android.mk
+++ b/opengl/tests/testPauseResume/Android.mk
@@ -2,8 +2,6 @@
# OpenGL ES JNI sample
# This makefile builds both an activity and a shared library.
#########################################################################
-ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
-
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
@@ -18,5 +16,3 @@
LOCAL_PACKAGE_NAME := TestEGL
include $(BUILD_PACKAGE)
-
-endif # TARGET_SIMULATOR
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
index ab37809..9980e7d 100644
--- a/opengl/tests/testViewport/Android.mk
+++ b/opengl/tests/testViewport/Android.mk
@@ -2,8 +2,6 @@
# OpenGL ES JNI sample
# This makefile builds both an activity and a shared library.
#########################################################################
-ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean
-
TOP_LOCAL_PATH:= $(call my-dir)
# Build activity
@@ -22,5 +20,3 @@
LOCAL_SDK_VERSION := 8
include $(BUILD_PACKAGE)
-
-endif # TARGET_SIMULATOR
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 26ea225..d32df6e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -30,6 +30,15 @@
<service android:name=".screenshot.TakeScreenshotService"
android:exported="false" />
+ <service android:name=".LoadAverageService"
+ android:exported="true" />
+
+ <receiver android:name=".BootReceiver" >
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+
<activity android:name=".usb.UsbStorageActivity"
android:excludeFromRecents="true">
</activity>
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml b/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml
deleted file mode 100644
index 0e58e12..0000000
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg_selector.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
-
- <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
-
- <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
- <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
- <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
- <item android:state_focused="true" android:drawable="@drawable/recents_thumbnail_bg_holo" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml b/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml
new file mode 100644
index 0000000..6cae2c4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_layers.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:drawable="@drawable/recents_thumbnail_bg" android:id="@+id/base_layer"/>
+ <item android:drawable="@drawable/recents_thumbnail_overlay" android:id="@+id/overlay_layer"/>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
new file mode 100644
index 0000000..200bac4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_thumbnail_overlay.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/recents_thumbnail_bg_press" android:state_pressed="true" />
+ <item android:drawable="@*android:color/transparent"/>
+</selector>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
index be4f1d7..8c29042 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -24,14 +24,15 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
- <ImageView android:id="@+id/app_thumbnail"
+ <FrameLayout android:id="@+id/app_thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
- android:background="@drawable/recents_thumbnail_bg_selector"
+ android:clickable="true"
+ android:background="@drawable/recents_thumbnail_layers"
/>
<ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index efdd9ac..20ef7cf 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -51,7 +51,6 @@
android:fadingEdge="horizontal"
android:scrollbars="none"
android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
- android:listSelector="@drawable/recents_thumbnail_bg_selector"
android:layout_gravity="bottom|left"
android:orientation="horizontal"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
index 76965c9..c705a69 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml
@@ -24,13 +24,15 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
- <ImageView android:id="@+id/app_thumbnail"
+ <FrameLayout android:id="@+id/app_thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
+ android:clickable="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
+ android:background="@drawable/recents_thumbnail_layers"
/>
<ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
index 28ef239..c680b8e 100644
--- a/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-port/status_bar_recent_panel.xml
@@ -48,7 +48,6 @@
android:fadingEdge="vertical"
android:scrollbars="none"
android:fadingEdgeLength="@*android:dimen/status_bar_height"
- android:listSelector="@drawable/recents_thumbnail_bg_selector"
android:layout_gravity="bottom|left"
android:clipToPadding="false"
android:clipChildren="false">
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
index 9687866..386ce30 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml
@@ -24,13 +24,15 @@
android:layout_height="wrap_content"
android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
- <ImageView android:id="@+id/app_thumbnail"
+ <FrameLayout android:id="@+id/app_thumbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
android:scaleType="center"
+ android:clickable="true"
+ android:background="@drawable/recents_thumbnail_layers"
/>
<ImageView android:id="@+id/app_icon"
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
index 75fdc67..2c9a152 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_panel.xml
@@ -56,7 +56,6 @@
android:scrollbars="none"
android:fadingEdgeLength="20dip"
android:layout_gravity="bottom|left"
- android:listSelector="@drawable/recents_thumbnail_bg_selector"
android:clipToPadding="false"
android:clipChildren="false">
diff --git a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml b/packages/SystemUI/res/menu/recent_popup_menu.xml
similarity index 70%
rename from packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
rename to packages/SystemUI/res/menu/recent_popup_menu.xml
index f9bba2a..eecfb9a 100644
--- a/packages/SystemUI/res/drawable/recents_thumbnail_bg_holo.xml
+++ b/packages/SystemUI/res/menu/recent_popup_menu.xml
@@ -17,7 +17,7 @@
** limitations under the License.
*/
-->
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
- <item android:drawable="@drawable/recents_thumbnail_bg_press"/>
-</transition>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/recent_remove_item" android:title="@string/status_bar_recent_remove_item_title" />
+ <item android:id="@+id/recent_inspect_item" android:title="@string/status_bar_recent_inspect_item_title" />
+</menu>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index d8aa61f..f22a657 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"توسيع بملء الشاشة"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"تكبير/تصغير التوافق"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"عند تصميم تطبيق لشاشة أصغر، سيظهر عنصر تحكم في التكبير/التصغير بجوار الساعة."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"تم حفظ لقطة الشاشة إلى المعرض."</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"تعذر حفظ لقطة الشاشة."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 20748ee..7560aca 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Разпъване – запълва екрана"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Промяна на мащаба за съвместимост"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Когато дадено приложение е създадено за по-малък екран, до часовника ще се покаже управление за промяна на мащаба."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Екранната снимка е запазена в галерията"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Екранната снимка не можа да бъде запазена"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index c346184..cba8db4 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Estira per omplir pant."</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom de compatibilitat"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Quan una aplicació s\'hagi dissenyat per a una pantalla més petita, apareixerà un control de zoom al costat del rellotge."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Captura de pantalla desada a la galeria"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"No es pot desar la captura de pantalla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 692dd4c..acdbbe5 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Na celou obrazovku"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Kompatibilní přiblížení"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Pokud je aplikace navržena pro menší obrazovku, zobrazí se vedle hodin ovládací prvek přiblížení."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Snímek obrazovky byl uložen do Galerie"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Snímek obrazovky se nepodařilo uložit"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bd1bd02..d74dc62 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Stræk til fuld skærm"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Kompatibilitetszoom"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Når en app er udviklet til en mindre skærm, vises der en zoomfunktion ved uret."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Skærmbilledet gemmes i Galleri"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Skærmbilledet kunne ikke gemmes"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index ed0bfa4..e09598f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Auf Bildschirmgröße anpassen"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Kompatibilitätszoom"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Wenn eine App für einen kleineren Bildschirm ausgelegt ist, wird ein Zoom-Steuerelement neben der Uhr angezeigt."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Screenshot in Galerie gespeichert."</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Screenshot konnte nicht gespeichert werden."</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1d907c5..1fc6871 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Προβoλή σε πλήρη οθ."</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Ζουμ για συμβατότητα"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Όταν μια εφαρμογή έχει σχεδιαστεί για προβολή σε μικρότερη οθόνη, δίπλα από το ρολόι θα εμφανιστεί ένα στοιχείο ελέγχου ζουμ."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Το στιγμιότυπο οθόνης αποθηκεύτηκε στη συλλογή"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Δεν ήταν δυνατή η αποθήκευση του στιγμιοτύπου οθόνης"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index cda0718..c9bb124 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Stretch to fill screen"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Compatibility Zoom"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"When an app was designed for a smaller screen, a zoom control will appear by the clock."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Screenshot saved to Gallery"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Could not save screenshot"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index fd16ccf..ace34d6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Estirar p/ ocupar la pantalla"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom de compatibilidad"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Cuando una aplicación fue diseñada para una pantalla más pequeña, aparece un control de zoom junto al reloj."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Captura de pantalla guardada en la Galería"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"No se pudo guardar la captura de pantalla."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a57258a..d4594df 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Expandir para ajustar"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom de compatibilidad"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Si la aplicación se ha diseñado para una pantalla más pequeña, aparecerá un control de zoom junto al reloj."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Captura de pantalla guardada en la galería"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"No se ha podido guardar la captura de pantalla."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 95f1c75..81d3b84 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"گسترده کردن برای پر کردن صفحه"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"بزرگنمایی سازگاری"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"اگر یک برنامه برای صفحه کوچک تری طراحی شده باشد، یک کنترل بزرگنمایی توسط ساعت نشان داده می شود."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"تصویر از صفحه در گالری ذخیره شد"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"ذخیره تصویر صفحه ممکن نیست"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7bf504f..e0e65ad 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Venytä koko näyttöön"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Yhteensopivuustilan zoomaus"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Jos sovellus on suunniteltu pienemmälle näytölle, kellon viereen tulee näkyviin zoomaussäädin."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Kuvakaappaus on tallennettu galleriaan"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Kuvakaappausta ei voitu tallentaa"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index c1daaa5..1342d8b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Étirer pour remplir l\'écran"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom de compatibilité"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Si une application a été conçue pour un écran plus petit, une commande de zoom s\'affiche à côté de l\'horloge."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Capture d\'écran enregistrée dans la galerie."</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Impossible d\'enregistrer la capture d\'écran."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index decaacd..afb18ab 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Rastegni i ispuni zaslon"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Kompatibilni zum"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Kada je aplikacija dizajnirana za manji zaslon, kontrole zumiranja prikazuju se pored sata."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Snimak zaslona spremljen u Galeriju"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Ne mogu spremiti snimak zaslona"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 696566f..448c3e6 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Nyújtás kitöltéshez"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Kompatibilitás -- nagyítás/kicsinyítés"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Ha egy alkalmazást kisebb képernyőre terveztek, akkor a nagyítás/kicsinyítés vezérlője az óra mellett jelenik meg."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Képernyőkép mentve a galériába"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Nem sikerült menteni a képernyőképet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 78f29c1..02f1ff6 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Rentangkn utk mngisi layar"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom Kompatibilitas"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Saat apl dirancang untuk layar yang lebih kecil, kontrol zoom akan tampil di dekat jam."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Tangkapan layar disimpan ke Galeri"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Tidak dapat menyimpan tangkapan layar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8c6cd6d..763842a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Estendi per riemp. schermo"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom compatibilità"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Se un\'applicazione è stata progettata per uno schermo più piccolo, accanto all\'orologio viene visualizzato un controllo dello zoom."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Screenshot salvato nella galleria"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Impossibile salvare lo screenshot"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 511d49e..5236740 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"מתח כדי למלא את המסך"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"שינוי מרחק מתצוגה לתאימות"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"כאשר יישום מיועד למסך קטן יותר, פקד של מרחק מתצוגה יופיע ליד השעון."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"צילום המסך נשמר בגלריה"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"לא ניתן לשמור את צילום המסך"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 88611dd..2e0fad2 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"画面サイズに合わせて拡大"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"互換ズーム"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"より小型の画面向けのアプリの場合は、ズームコントロールが時計のそばに表示されます。"</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"スクリーンショットがギャラリーに保存されました"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"スクリーンショットを保存できませんでした"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 4cc668a..a46b608 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"전체화면 모드로 확대"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"호환성 확대/축소"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"앱이 작은 화면에 맞도록 설계된 경우 시계 옆에 확대/축소 컨트롤이 표시됩니다."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"캡쳐화면이 갤러리에 저장되었습니다."</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"캡쳐화면을 저장하지 못했습니다."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index fbdba57..356f46b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Ištempti, kad atit. ekr."</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Suderinamumo mastelio keitimas"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Kai programa bus pritaikyta mažesniam ekranui, mastelio keitimo valdiklis bus parodytas šalia laikrodžio."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Ekrano kopija išsaugota galerijoje"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Nepavyko išsaugoti ekrano kopijos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 37e3f92..bf6dbd4 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Stiepiet, lai aizp. ekr."</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Saderības tālummaiņa"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Ja lietotne ir paredzēta mazākam ekrānam, blakus pulkstenim tiks parādīta tālummaiņas vadīkla."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Ekrānuzņēmums ir saglabāts galerijā."</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Nevarēja saglabāt ekrānuzņēmumu."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index c24a8fb..d51f0cc 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -61,8 +61,6 @@
<skip />
<!-- no translation found for compat_mode_help_body (4946726776359270040) -->
<skip />
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Tangkapan skrin disimpan ke Galeri"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Tidak boleh menyimpan tangkapan skrin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index df92a70..be10217 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Strekk for å fylle skjerm"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Kompatibilitets-zooming"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Når en app er utformet for en mindre skjerm, vises det en zoomkontroll ved klokken."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Skjermdump ble lagret i galleriet"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Lagring av skjermdump mislyktes"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 518402f..c83c7c4 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Rek uit v. schermvulling"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Compatibiliteitszoom"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Wanneer een app is ontworpen voor een kleiner scherm, wordt naast de klok een zoomknop weergegeven."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Schermafbeelding is opgeslagen in de galerij"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Schermafbeelding is niet opgeslagen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index c59df62..e5937e2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Rozciągnij, aby wypełnić ekran"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Powiększenie w trybie zgodności"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Jeśli aplikacja została przystosowana do mniejszego ekranu, obok zegara zostanie wyświetlony element sterujący powiększeniem."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Zrzut ekranu został zapisany w galerii."</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Nie można zapisać zrzutu ekranu."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index ee79283..400d805 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Esticar p. caber em ec. int."</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Compatibilidade de zoom"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Sempre que uma aplicação tiver sido concebida para ecrãs mais pequenos, aparecerá um controlo de zoom junto ao relógio."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Captura de ecrã guardada na Galeria"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Não foi possível guardar a captura de ecrã"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 447cce1..90dd212 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Ampliar p/ preencher tela"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom em modo de compatibilidade"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Quando um aplicativo é desenvolvido para uma tela menor, um controle de zoom é exibido perto do relógio."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"A captura de tela foi salva na Galeria"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Não foi possível salvar a captura de tela"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 07394ab..6dfd055 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Înt. pt. a umple ecranul"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom de compatibilitate"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Atunci când o aplicaţie a fost concepută pentru un ecran mai mic, o comandă pentru mărire/micşorare va apărea alături de ceas."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Captura de ecran a fost salvată în Galerie"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Captura de ecran nu a putut fi salvată"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index e4f3e83..d1f6cd2 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Растянуть на весь экран"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Масштаб и совместимость"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Если приложение рассчитано на экран меньших размеров, рядом с часами появятся средства масштабирования."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Скриншот сохранен в галерее"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Не удалось сохранить скриншот"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f720662..d67752b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Na celú obrazovku"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Kompatibilné priblíženie"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Ak je aplikácia navrhnutá pre menšiu obrazovku, zobrazí sa vedľa hodín ovládací prvok priblíženia."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Snímka obrazovky bola uložená do Galérie"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Snímku obrazovky sa nepodarilo uložiť"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 37ecf50..c7aade9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Raztegnitev čez zaslon"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Povečava združljivosti"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Če je program izdelan za manjše zaslone, se ob uri pokaže kontrolnik za povečavo."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Posnetek zaslona je shranjen v galerijo"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Posnetka zaslona ni bilo mogoče shraniti"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 7290f4c..0afdf98 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Развуци на цео екран"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Компатибилно зумирање"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Када је апликација намењена мањем екрану, контрола зумирања приказује се поред сата."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Снимак екрана је сачуван у Галерији"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Није могуће сачувати снимак екрана"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 19c9a09..6cbca3f 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Dra för att fylla skärmen"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom i kompatibilitetsläge"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"När en app är anpassad för en mindre skärm visas ett zoomreglage vid klockan."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Skärmdumpen sparades i galleriet"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Det gick inte att spara skärmdumpen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 15f3007..9744c60 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"ยืดจนเต็มหน้าจอ"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"ความเข้ากันได้ของการย่อ/ขยาย"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"สำหรับแอปพลิเคชันที่ออกแบบมาสำหรับหน้าจอขนาดเล็ก ตัวควบคุมการย่อ/ขยายจะปรากฏขึ้นข้างนาฬิกา"</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"บันทึกภาพหน้าจอในแกลเลอรีแล้ว"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"ไม่สามารถบันทึกภาพหน้าจอ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 93fdb6a..93796f3 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"I-stretch upang mapuno screen"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Zoom sa Pagiging Tugma"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Kapag nakadisenyo ang isang app para sa mas maliit na screen, isang kontrol ng zoom ang lalabas sa may orasan."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Na-save ang screenshot sa Gallery"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Hindi ma-save ang screenshot"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 5ec11b6..2fd0df5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Genişlet (ekran kapansın)"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Uyumluluk Zum\'u"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Uygulama küçük bir ekran için tasarlanmışsa saatin yanında bir yakınlaştırma denetimi görünür."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Ekran görüntüsü Galeri\'ye kaydedildi"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Ekran görüntüsü kaydedilemedi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 759acdc..a81dbbf 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Розтягнути на весь екран"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Елемент керування масштабом для сумісності"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Якщо програму призначено для менших екранів, елемент керування масштабом буде відображатися біля годинника."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Знімок екрана збережено в Галереї"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Неможливо зберегти знімок екрана"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index af44600..b660b98 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"Giãn ra để lấp đầy m.hình"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"Thu phóng tương thích"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"Khi ứng dụng được thiết kế cho một màn hình nhỏ hơn, điều khiển thu phóng sẽ xuất hiện bên cạnh đồng hồ."</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"Đã lưu ảnh chụp màn hình vào Thư viện"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"Không thể lưu ảnh chụp màn hình"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 201ecfa..397d590 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"拉伸以填满屏幕"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"兼容性缩放"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"如果应用程序是针对较小屏幕设计的,则时钟旁会显示缩放控件。"</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"屏幕截图已保存到“图库”"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"无法保存屏幕截图"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index a46a909..61afd2ff 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -57,8 +57,6 @@
<string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string>
<string name="compat_mode_help_header" msgid="7020175705401506719">"相容性縮放"</string>
<string name="compat_mode_help_body" msgid="4946726776359270040">"執行專為較小螢幕設計的應用程式時,系統會在時鐘旁顯示縮放控制項。"</string>
- <!-- no translation found for screenshot_saving_toast (8592630119048713208) -->
- <skip />
- <!-- no translation found for screenshot_failed_toast (655180965533683356) -->
- <skip />
+ <string name="screenshot_saving_toast" msgid="8592630119048713208">"螢幕擷取畫面已儲存至圖片庫"</string>
+ <string name="screenshot_failed_toast" msgid="655180965533683356">"無法儲存螢幕擷取畫面"</string>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 882455e..01cf2dc 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -35,6 +35,14 @@
shown again. [CHAR LIMIT=25] -->
<string name="status_bar_please_disturb_button">Show notifications</string>
+ <!-- Title shown in recents popup for removing an application from the list -->
+ <string name="status_bar_recent_remove_item_title">Remove</string>
+
+ <!-- Title shown in recents popup for inspecting an application's properties -->
+ <string name="status_bar_recent_inspect_item_title">Inspect</string>
+
+
+
<!-- The label in the bar at the top of the status bar when there are no notifications
showing. [CHAR LIMIT=40]-->
diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
new file mode 100644
index 0000000..de005aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 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.systemui;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.util.Slog;
+
+/**
+ * Performs a number of miscellaneous, non-system-critical actions
+ * after the system has finished booting.
+ */
+public class BootReceiver extends BroadcastReceiver {
+ private static final String TAG = "SystemUIBootReceiver";
+
+ @Override
+ public void onReceive(final Context context, Intent intent) {
+ try {
+ // Start the load average overlay, if activated
+ ContentResolver res = context.getContentResolver();
+ if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
+ Intent loadavg = new Intent(context, com.android.systemui.LoadAverageService.class);
+ context.startService(loadavg);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Can't start load average service", e);
+ }
+ }
+}
diff --git a/services/java/com/android/server/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
similarity index 80%
rename from services/java/com/android/server/LoadAverageService.java
rename to packages/SystemUI/src/com/android/systemui/LoadAverageService.java
index da9fc99..67dc3cd 100644
--- a/services/java/com/android/server/LoadAverageService.java
+++ b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.systemui;
+
+import com.android.internal.os.ProcessStats;
import android.app.Service;
import android.content.Context;
@@ -28,7 +30,6 @@
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
-import android.view.WindowManagerImpl;
public class LoadAverageService extends Service {
private View mView;
@@ -91,32 +92,46 @@
setPadding(4, 4, 4, 4);
//setBackgroundResource(com.android.internal.R.drawable.load_average_background);
+ // Need to scale text size by density... but we won't do it
+ // linearly, because with higher dps it is nice to squeeze the
+ // text a bit to fit more of it. And with lower dps, trying to
+ // go much smaller will result in unreadable text.
+ int textSize = 10;
+ float density = c.getResources().getDisplayMetrics().density;
+ if (density < 1) {
+ textSize = 9;
+ } else {
+ textSize = (int)(10*density);
+ if (textSize < 10) {
+ textSize = 10;
+ }
+ }
mLoadPaint = new Paint();
mLoadPaint.setAntiAlias(true);
- mLoadPaint.setTextSize(10);
+ mLoadPaint.setTextSize(textSize);
mLoadPaint.setARGB(255, 255, 255, 255);
mAddedPaint = new Paint();
mAddedPaint.setAntiAlias(true);
- mAddedPaint.setTextSize(10);
+ mAddedPaint.setTextSize(textSize);
mAddedPaint.setARGB(255, 128, 255, 128);
mRemovedPaint = new Paint();
mRemovedPaint.setAntiAlias(true);
mRemovedPaint.setStrikeThruText(true);
- mRemovedPaint.setTextSize(10);
+ mRemovedPaint.setTextSize(textSize);
mRemovedPaint.setARGB(255, 255, 128, 128);
mShadowPaint = new Paint();
mShadowPaint.setAntiAlias(true);
- mShadowPaint.setTextSize(10);
+ mShadowPaint.setTextSize(textSize);
//mShadowPaint.setFakeBoldText(true);
mShadowPaint.setARGB(192, 0, 0, 0);
mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
mShadow2Paint = new Paint();
mShadow2Paint.setAntiAlias(true);
- mShadow2Paint.setTextSize(10);
+ mShadow2Paint.setTextSize(textSize);
//mShadow2Paint.setFakeBoldText(true);
mShadow2Paint.setARGB(192, 0, 0, 0);
mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
@@ -153,14 +168,16 @@
}
@Override
- protected void onMeasure(int widthMeasureSpect, int heightMeasureSpec) {
- setMeasuredDimension(mNeededWidth, mNeededHeight);
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
+ resolveSize(mNeededHeight, heightMeasureSpec));
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
- final int W = getWidth();
+ final int W = mNeededWidth;
+ final int RIGHT = getWidth()-1;
final Stats stats = mStats;
final int userTime = stats.getLastUserTime();
@@ -178,7 +195,7 @@
int systemW = (systemTime*W)/totalTime;
int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
- int x = W - mPaddingRight;
+ int x = RIGHT - mPaddingRight;
int top = mPaddingTop + 2;
int bottom = mPaddingTop + mFH - 2;
@@ -196,15 +213,15 @@
}
int y = mPaddingTop - (int)mAscent;
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
y-1, mShadowPaint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth-1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth-1,
y+1, mShadowPaint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
y-1, mShadow2Paint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth+1,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth+1,
y+1, mShadow2Paint);
- canvas.drawText(stats.mLoadText, W-mPaddingRight-stats.mLoadWidth,
+ canvas.drawText(stats.mLoadText, RIGHT-mPaddingRight-stats.mLoadWidth,
y, mLoadPaint);
int N = stats.countWorkingStats();
@@ -216,7 +233,7 @@
userW = (st.rel_utime*W)/totalTime;
systemW = (st.rel_stime*W)/totalTime;
- x = W - mPaddingRight;
+ x = RIGHT - mPaddingRight;
if (systemW > 0) {
canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
x -= systemW;
@@ -226,18 +243,18 @@
x -= userW;
}
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
y-1, mShadowPaint);
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth-1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth-1,
y+1, mShadowPaint);
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
y-1, mShadow2Paint);
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth+1,
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth+1,
y+1, mShadow2Paint);
Paint p = mLoadPaint;
if (st.added) p = mAddedPaint;
if (st.removed) p = mRemovedPaint;
- canvas.drawText(st.name, W-mPaddingRight-st.nameWidth, y, p);
+ canvas.drawText(st.name, RIGHT-mPaddingRight-st.nameWidth, y, p);
}
}
@@ -270,7 +287,7 @@
super.onCreate();
mView = new LoadView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
index 37a9913..2d327c4 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -53,8 +53,6 @@
void createAnimation(boolean appearing) {
float start, end;
- if (RecentsPanelView.DEBUG) Log.e(TAG, "createAnimation()", new Exception());
-
// 0: on-screen
// height: off-screen
float y = mContentView.getTranslationY();
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 5d29e2a..797f94c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -26,5 +26,5 @@
void handleOnClick(View selectedView);
void handleSwipe(View selectedView, int direction);
- void handleLongPress(View selectedView);
+ void handleLongPress(View selectedView, View anchorView);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index f984aac..2a5d1dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -20,6 +20,7 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -30,7 +31,6 @@
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -42,10 +42,9 @@
import com.android.systemui.R;
-public class RecentsHorizontalScrollView extends HorizontalScrollView
- implements View.OnClickListener, View.OnTouchListener {
- private static final boolean DEBUG_INVALIDATE = false;
+public class RecentsHorizontalScrollView extends HorizontalScrollView {
private static final String TAG = RecentsPanelView.TAG;
+ private static final boolean DEBUG_INVALIDATE = false;
private static final boolean DEBUG = RecentsPanelView.DEBUG;
private LinearLayout mLinearLayout;
private ActivityDescriptionAdapter mAdapter;
@@ -57,6 +56,15 @@
private VelocityTracker mVelocityTracker;
private float mDensityScale;
private float mPagingTouchSlop;
+ private OnLongClickListener mOnLongClick = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = v.findViewById(R.id.app_description);
+ mCurrentView = v;
+ mCallback.handleLongPress(v, anchorView);
+ mCurrentView = null; // make sure we don't accept the return click from this
+ return true;
+ }
+ };
public RecentsHorizontalScrollView(Context context) {
this(context, null);
@@ -72,13 +80,12 @@
return mLinearLayout.getWidth() - getWidth();
}
- public void update() {
+ private void update() {
mLinearLayout.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
- View view = mAdapter.getView(i, null, mLinearLayout);
+ final View view = mAdapter.getView(i, null, mLinearLayout);
view.setClickable(true);
- view.setOnClickListener(this);
- view.setOnTouchListener(this);
+ view.setOnLongClickListener(mOnLongClick);
mLinearLayout.addView(view);
}
// Scroll to end after layout.
@@ -91,7 +98,20 @@
}
@Override
+ public void removeViewInLayout(final View view) {
+ ObjectAnimator anim = animateClosed(view, Constants.MAX_ESCAPE_ANIMATION_DURATION,
+ "y", view.getY(), view.getY() + view.getHeight());
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ RecentsHorizontalScrollView.super.removeView(view);
+ }
+ });
+ anim.start();
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
@@ -100,6 +120,18 @@
case MotionEvent.ACTION_DOWN:
mDragging = false;
mLastY = ev.getY();
+ final float x = ev.getX() + getScrollX();
+ final float y = ev.getY() + getScrollY();
+ mCurrentView = null;
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View item = mLinearLayout.getChildAt(i);
+ if (x >= item.getLeft() && x < item.getRight()
+ && y >= item.getTop() && y < item.getBottom()) {
+ mCurrentView = item;
+ if (DEBUG) Log.v(TAG, "Hit item " + item);
+ break;
+ }
+ }
break;
case MotionEvent.ACTION_MOVE:
@@ -111,6 +143,9 @@
break;
case MotionEvent.ACTION_UP:
+ if (mCurrentView != null) {
+ mCallback.handleOnClick(mCurrentView);
+ }
mDragging = false;
break;
}
@@ -125,7 +160,6 @@
} else if (view.getY() < thumbHeight * (1.0f - Constants.ALPHA_FADE_START)) {
result = 1.0f + (thumbHeight * Constants.ALPHA_FADE_START + view.getY()) / fadeHeight;
}
- if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -138,12 +172,12 @@
mVelocityTracker.addMovement(ev);
final View animView = mCurrentView;
- // TODO: Cache thumbnail
- final View thumb = animView.findViewById(R.id.app_thumbnail);
+
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
if (animView != null) {
final float delta = ev.getY() - mLastY;
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
animView.setY(animView.getY() + delta);
animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
invalidateGlobalRegion(animView);
@@ -167,35 +201,18 @@
long duration =
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
- anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
- anim.setInterpolator(new LinearInterpolator());
- final int swipeDirection = animView.getY() >= 0.0f ?
- RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
- anim.addListener(new AnimatorListener() {
- public void onAnimationStart(Animator animation) {
- }
- public void onAnimationRepeat(Animator animation) {
- }
- public void onAnimationEnd(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- public void onAnimationCancel(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- });
- anim.setDuration(duration);
+ anim = animateClosed(animView, duration, "y", curY, newY);
} else { // Animate back to position
long duration = Math.abs(velocityY) > 0.0f ?
(long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
: Constants.SNAP_BACK_DURATION;
duration = Math.min(duration, Constants.SNAP_BACK_DURATION);
anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
- anim.setInterpolator(new DecelerateInterpolator(2.0f));
+ anim.setInterpolator(new DecelerateInterpolator(4.0f));
anim.setDuration(duration);
}
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
@@ -212,6 +229,26 @@
return true;
}
+ private ObjectAnimator animateClosed(final View animView, long duration,
+ String attr, float from, float to) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(animView, attr, from, to);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getX() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ return anim;
+ }
+
void invalidateGlobalRegion(View view) {
RectF childBounds
= new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
@@ -236,13 +273,8 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- LayoutInflater inflater = (LayoutInflater)
- mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
setScrollbarFadingEnabled(true);
-
mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-
final int leftPadding = mContext.getResources()
.getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
setOverScrollEffectPadding(leftPadding, 0);
@@ -306,16 +338,7 @@
mLinearLayout.setLayoutTransition(transition);
}
- public void onClick(View view) {
- mCallback.handleOnClick(view);
- }
-
public void setCallback(RecentsCallback callback) {
mCallback = callback;
}
-
- public boolean onTouch(View v, MotionEvent event) {
- mCurrentView = v;
- return false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index a55fe9c..bc0a508 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -22,6 +22,7 @@
import android.animation.Animator;
import android.animation.LayoutTransition;
import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -39,16 +40,22 @@
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.net.Uri;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
+import android.widget.Button;
import android.widget.ImageView;
+import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -69,7 +76,7 @@
private int mIconDpi;
private View mRecentsScrim;
private View mRecentsGlowView;
- private View mRecentsContainer;
+ private ViewGroup mRecentsContainer;
private Bitmap mGlowBitmap;
// TODO: add these widgets attributes to the layout file
private int mGlowBitmapPaddingLeftPx;
@@ -107,8 +114,18 @@
}
};
+ private final class OnLongClickDelegate implements View.OnLongClickListener {
+ View mOtherView;
+ OnLongClickDelegate(View other) {
+ mOtherView = other;
+ }
+ public boolean onLongClick(View v) {
+ return mOtherView.performLongClick();
+ }
+ }
+
/* package */ final static class ViewHolder {
- ImageView thumbnailView;
+ View thumbnailView;
ImageView iconView;
TextView labelView;
TextView descriptionView;
@@ -139,7 +156,7 @@
if (convertView == null) {
convertView = mInflater.inflate(R.layout.status_bar_recent_item, null);
holder = new ViewHolder();
- holder.thumbnailView = (ImageView) convertView.findViewById(R.id.app_thumbnail);
+ holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail);
holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -153,11 +170,12 @@
final ActivityDescription activityDescription = mActivityDescriptions.get(activityId);
final Bitmap thumb = activityDescription.thumbnail;
- holder.thumbnailView.setImageBitmap(compositeBitmap(mGlowBitmap, thumb));
+ updateDrawable(holder.thumbnailView, compositeBitmap(mGlowBitmap, thumb));
holder.iconView.setImageDrawable(activityDescription.icon);
holder.labelView.setText(activityDescription.label);
holder.descriptionView.setText(activityDescription.description);
holder.thumbnailView.setTag(activityDescription);
+ holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView));
holder.activityDescription = activityDescription;
return convertView;
@@ -174,6 +192,20 @@
return x >= l && x < r && y >= t && y < b;
}
+ private void updateDrawable(View thumbnailView, Bitmap bitmap) {
+ Drawable d = thumbnailView.getBackground();
+ if (d instanceof LayerDrawable) {
+ LayerDrawable layerD = (LayerDrawable) d;
+ Drawable thumb = layerD.findDrawableByLayerId(R.id.base_layer);
+ if (thumb != null) {
+ layerD.setDrawableByLayerId(R.id.base_layer,
+ new BitmapDrawable(getResources(), bitmap));
+ return;
+ }
+ }
+ Log.w(TAG, "Failed to update drawable");
+ }
+
public void show(boolean show, boolean animate) {
if (animate) {
if (mShowing != show) {
@@ -260,7 +292,7 @@
protected void onFinishInflate() {
super.onFinishInflate();
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mRecentsContainer = findViewById(R.id.recents_container);
+ mRecentsContainer = (ViewGroup) findViewById(R.id.recents_container);
mListAdapter = new ActivityDescriptionAdapter(mContext);
if (mRecentsContainer instanceof RecentsListView) {
RecentsListView listView = (RecentsListView) mRecentsContainer;
@@ -503,7 +535,35 @@
am.removeTask(ad.taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
}
- public void handleLongPress(View selectedView) {
- // TODO show context menu : "Remove from list", "Show properties"
+ private void startApplicationDetailsActivity(String packageName) {
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+ Uri.fromParts("package", packageName, null));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ getContext().startActivity(intent);
+ }
+
+ public void handleLongPress(final View selectedView, final View anchorView) {
+ PopupMenu popup = new PopupMenu(mContext, anchorView == null ? selectedView : anchorView);
+ popup.getMenuInflater().inflate(R.menu.recent_popup_menu, popup.getMenu());
+ popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == R.id.recent_remove_item) {
+ mRecentsContainer.removeViewInLayout(selectedView);
+ } else if (item.getItemId() == R.id.recent_inspect_item) {
+ ViewHolder viewHolder = (ViewHolder) selectedView.getTag();
+ if (viewHolder != null) {
+ final ActivityDescription ad = viewHolder.activityDescription;
+ startApplicationDetailsActivity(ad.packageName);
+ mBar.animateCollapse();
+ } else {
+ throw new IllegalStateException("Oops, no tag on view " + selectedView);
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+ });
+ popup.show();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 27bb0b5..47ee4aa 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -20,6 +20,7 @@
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -42,8 +43,7 @@
import com.android.systemui.R;
-public class RecentsVerticalScrollView extends ScrollView
- implements View.OnClickListener, View.OnTouchListener {
+public class RecentsVerticalScrollView extends ScrollView {
private static final String TAG = RecentsPanelView.TAG;
private static final boolean DEBUG_INVALIDATE = false;
private static final boolean DEBUG = RecentsPanelView.DEBUG;
@@ -57,6 +57,15 @@
private VelocityTracker mVelocityTracker;
private float mDensityScale;
private float mPagingTouchSlop;
+ private OnLongClickListener mOnLongClick = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ final View anchorView = v.findViewById(R.id.app_description);
+ mCurrentView = v;
+ mCallback.handleLongPress(v, anchorView);
+ mCurrentView = null; // make sure we don't accept the return click from this
+ return true;
+ }
+ };
public RecentsVerticalScrollView(Context context) {
this(context, null);
@@ -72,13 +81,12 @@
return mLinearLayout.getHeight() - getHeight();
}
- public void update() {
+ private void update() {
mLinearLayout.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
- View view = mAdapter.getView(i, null, mLinearLayout);
+ final View view = mAdapter.getView(i, null, mLinearLayout);
view.setClickable(true);
- view.setOnClickListener(this);
- view.setOnTouchListener(this);
+ view.setOnLongClickListener(mOnLongClick);
mLinearLayout.addView(view);
}
// Scroll to end after layout.
@@ -91,7 +99,20 @@
}
@Override
+ public void removeViewInLayout(final View view) {
+ ObjectAnimator anim = animateClosed(view, Constants.MAX_ESCAPE_ANIMATION_DURATION,
+ "x", view.getX(), view.getX() + view.getWidth());
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ RecentsVerticalScrollView.super.removeView(view);
+ }
+ });
+ anim.start();
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
@@ -100,6 +121,18 @@
case MotionEvent.ACTION_DOWN:
mDragging = false;
mLastX = ev.getX();
+ final float x = ev.getX() + getScrollX();
+ final float y = ev.getY() + getScrollY();
+ mCurrentView = null;
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View item = mLinearLayout.getChildAt(i);
+ if (x >= item.getLeft() && x < item.getRight()
+ && y >= item.getTop() && y < item.getBottom()) {
+ mCurrentView = item;
+ Log.v(TAG, "Hit item " + item);
+ break;
+ }
+ }
break;
case MotionEvent.ACTION_MOVE:
@@ -111,6 +144,9 @@
break;
case MotionEvent.ACTION_UP:
+ if (mCurrentView != null) {
+ mCallback.handleOnClick(mCurrentView);
+ }
mDragging = false;
break;
}
@@ -125,7 +161,6 @@
} else if (view.getX() < thumbWidth* (1.0f - Constants.ALPHA_FADE_START)) {
result = 1.0f + (thumbWidth*Constants.ALPHA_FADE_START + view.getX()) / fadeWidth;
}
- if (DEBUG) Log.v(TAG, "FADE AMOUNT: " + result);
return result;
}
@@ -138,12 +173,12 @@
mVelocityTracker.addMovement(ev);
final View animView = mCurrentView;
- // TODO: Cache thumbnail
- final View thumb = animView.findViewById(R.id.app_thumbnail);
+
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
if (animView != null) {
final float delta = ev.getX() - mLastX;
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
animView.setX(animView.getX() + delta);
animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
invalidateGlobalRegion(animView);
@@ -163,29 +198,11 @@
final float maxVelocity = Constants.ESCAPE_VELOCITY * mDensityScale;
if (Math.abs(velocityX) > Math.abs(velocityY)
&& Math.abs(velocityX) > maxVelocity
- && (velocityX > 0.0f) == (animView.getX() >= 0)) {
+ && (velocityX >= 0.0f) == (animView.getX() >= 0)) {
long duration =
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX));
duration = Math.min(duration, Constants.MAX_ESCAPE_ANIMATION_DURATION);
- anim = ObjectAnimator.ofFloat(animView, "x", curX, newX);
- anim.setInterpolator(new LinearInterpolator());
- final int swipeDirection = animView.getX() >= 0.0f ?
- RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
- anim.addListener(new AnimatorListener() {
- public void onAnimationStart(Animator animation) {
- }
- public void onAnimationRepeat(Animator animation) {
- }
- public void onAnimationEnd(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- public void onAnimationCancel(Animator animation) {
- mLinearLayout.removeView(mCurrentView);
- mCallback.handleSwipe(animView, swipeDirection);
- }
- });
- anim.setDuration(duration);
+ anim = animateClosed(animView, duration, "x", curX, newX);
} else { // Animate back to position
long duration = Math.abs(velocityX) > 0.0f ?
(long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX))
@@ -196,6 +213,7 @@
anim.setDuration(duration);
}
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
anim.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
@@ -212,6 +230,26 @@
return true;
}
+ private ObjectAnimator animateClosed(final View animView, long duration,
+ String attr, float from, float to) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(animView, attr, from, to);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getX() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(animView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ return anim;
+ }
+
void invalidateGlobalRegion(View view) {
RectF childBounds
= new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
@@ -236,13 +274,8 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- LayoutInflater inflater = (LayoutInflater)
- mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
setScrollbarFadingEnabled(true);
-
mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
-
final int leftPadding = mContext.getResources()
.getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
setOverScrollEffectPadding(leftPadding, 0);
@@ -306,16 +339,7 @@
mLinearLayout.setLayoutTransition(transition);
}
- public void onClick(View view) {
- mCallback.handleOnClick(view);
- }
-
public void setCallback(RecentsCallback callback) {
mCallback = callback;
}
-
- public boolean onTouch(View v, MotionEvent event) {
- mCurrentView = v;
- return false;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 826ac92..dedbe5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -785,7 +785,7 @@
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
} else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
- int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+ int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
BluetoothAdapter.STATE_DISCONNECTED);
if (state == BluetoothAdapter.STATE_CONNECTED) {
iconId = R.drawable.stat_sys_data_bluetooth_connected;
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index c0b0a08..8554b77 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -4,6 +4,7 @@
<application android:label="VpnDialogs">
<activity android:name=".ConfirmDialog"
+ android:permission="android.permission.VPN"
android:theme="@style/transparent">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/packages/VpnDialogs/res/layout/confirm.xml b/packages/VpnDialogs/res/layout/confirm.xml
index 5ab6ee2..11a247a 100644
--- a/packages/VpnDialogs/res/layout/confirm.xml
+++ b/packages/VpnDialogs/res/layout/confirm.xml
@@ -18,7 +18,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="5mm">
+ android:padding="3mm">
<ImageView android:id="@+id/icon"
android:layout_width="@android:dimen/app_icon_size"
diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml
index 330b8e3..3dcbb46 100644
--- a/packages/VpnDialogs/res/layout/manage.xml
+++ b/packages/VpnDialogs/res/layout/manage.xml
@@ -18,6 +18,7 @@
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:padding="3mm"
android:stretchColumns="0,1">
<TableRow>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 21e916b..40c0a02 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -58,6 +58,13 @@
@Override
protected void onResume() {
super.onResume();
+
+ if (getCallingPackage() != null) {
+ Log.e(TAG, getCallingPackage() + " cannot start this activity");
+ finish();
+ return;
+ }
+
try {
mConfig = getIntent().getParcelableExtra("config");
@@ -83,7 +90,6 @@
} else {
PackageManager pm = getPackageManager();
ApplicationInfo app = pm.getApplicationInfo(mConfig.packagz, 0);
-
mDialog = new AlertDialog.Builder(this)
.setIcon(app.loadIcon(pm))
.setTitle(app.loadLabel(pm))
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 8ba235b..935f4ad 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -689,13 +689,11 @@
switch (simState) {
case ABSENT:
- case PERM_DISABLED:
// only force lock screen in case of missing sim if user hasn't
// gone through setup wizard
if (!mUpdateMonitor.isDeviceProvisioned()) {
if (!isShowing()) {
- if (DEBUG) Log.d(TAG, "INTENT_VALUE_ICC_ABSENT "
- + "or PERM_DISABLED and keygaurd isn't showing,"
+ if (DEBUG) Log.d(TAG, "ICC_ABSENT isn't showing,"
+ " we need to show the keyguard since the "
+ "device isn't provisioned yet.");
doKeyguard();
@@ -713,7 +711,17 @@
} else {
resetStateLocked();
}
-
+ break;
+ case PERM_DISABLED:
+ if (!isShowing()) {
+ if (DEBUG) Log.d(TAG, "PERM_DISABLED and "
+ + "keygaurd isn't showing.");
+ doKeyguard();
+ } else {
+ if (DEBUG) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+ + "show permanently disabled message in lockscreen.");
+ resetStateLocked();
+ }
break;
case READY:
if (isShowing()) {
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 75e799c..e177565 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -75,6 +75,7 @@
private StatusView mStatusView;
private final boolean mUseSystemIME = true; // TODO: Make configurable
+ private boolean mResuming; // used to prevent poking the wakelock during onResume()
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
@@ -185,7 +186,9 @@
}
public void afterTextChanged(Editable s) {
- mCallback.pokeWakelock();
+ if (!mResuming) {
+ mCallback.pokeWakelock();
+ }
}
});
}
@@ -208,6 +211,7 @@
/** {@inheritDoc} */
public void onResume() {
+ mResuming = true;
// reset status
mStatusView.resetStatusInfo(mUpdateMonitor, mLockPatternUtils);
@@ -222,6 +226,7 @@
if (deadline != 0) {
handleAttemptLockout(deadline);
}
+ mResuming = false;
}
/** {@inheritDoc} */
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 7f6327d..b963b13 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1555,9 +1555,12 @@
// We restore the panel if it was last open; we skip it if it
// now is open, to avoid a race condition if the user immediately
// opens it when we are resuming.
- if ((st != null) && !st.isOpen && st.wasLastOpen) {
- st.isInExpandedMode = st.wasLastExpanded;
- openPanel(st, null);
+ if (st != null) {
+ st.applyFrozenState();
+ if (!st.isOpen && st.wasLastOpen) {
+ st.isInExpandedMode = st.wasLastExpanded;
+ openPanel(st, null);
+ }
}
}
}
@@ -1665,14 +1668,6 @@
}
}
- // Back cancels action modes first.
- if (mActionMode != null && keyCode == KeyEvent.KEYCODE_BACK) {
- if (action == KeyEvent.ACTION_UP) {
- mActionMode.finish();
- }
- return true;
- }
-
if (!isDestroyed()) {
final Callback cb = getCallback();
final boolean handled = cb != null && mFeatureId < 0 ? cb.dispatchKeyEvent(event)
@@ -1681,6 +1676,7 @@
return true;
}
}
+
return isDown ? PhoneWindow.this.onKeyDown(mFeatureId, event.getKeyCode(), event)
: PhoneWindow.this.onKeyUp(mFeatureId, event.getKeyCode(), event);
}
@@ -1727,7 +1723,32 @@
}
public boolean superDispatchKeyEvent(KeyEvent event) {
- return super.dispatchKeyEvent(event);
+ if (super.dispatchKeyEvent(event)) {
+ return true;
+ }
+
+ // Not handled by the view hierarchy, does the action bar want it
+ // to cancel out of something special?
+ if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ final int action = event.getAction();
+ // Back cancels action modes first.
+ if (mActionMode != null) {
+ if (action == KeyEvent.ACTION_UP) {
+ mActionMode.finish();
+ }
+ return true;
+ }
+
+ // Next collapse any expanded action views.
+ if (mActionBar != null && mActionBar.hasExpandedActionView()) {
+ if (action == KeyEvent.ACTION_UP) {
+ mActionBar.collapseActionView();
+ }
+ return true;
+ }
+ }
+
+ return false;
}
public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
@@ -2235,6 +2256,11 @@
}
mActionModePopup = null;
}
+
+ PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+ if (st != null && st.menu != null && mFeatureId < 0) {
+ st.menu.close();
+ }
}
@Override
@@ -3046,46 +3072,33 @@
getIconMenuView(cb); // Need this initialized to know where our offset goes
- boolean init = false;
if (expandedMenuPresenter == null) {
expandedMenuPresenter = new ListMenuPresenter(
com.android.internal.R.layout.list_menu_item_layout,
com.android.internal.R.style.Theme_ExpandedMenu);
expandedMenuPresenter.setCallback(cb);
+ expandedMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter);
menu.addMenuPresenter(expandedMenuPresenter);
- init = true;
}
expandedMenuPresenter.setItemIndexOffset(iconMenuPresenter.getNumActualItemsShown());
MenuView result = expandedMenuPresenter.getMenuView(decorView);
- if (init && frozenMenuState != null) {
- expandedMenuPresenter.restoreHierarchyState(frozenMenuState);
- // Once we initialize the expanded menu we're done with the frozen state
- // since we will have also restored any icon menu state.
- frozenMenuState = null;
- }
-
return result;
}
MenuView getIconMenuView(MenuPresenter.Callback cb) {
if (menu == null) return null;
- boolean init = false;
if (iconMenuPresenter == null) {
iconMenuPresenter = new IconMenuPresenter();
iconMenuPresenter.setCallback(cb);
+ iconMenuPresenter.setId(com.android.internal.R.id.icon_menu_presenter);
menu.addMenuPresenter(iconMenuPresenter);
- init = true;
}
MenuView result = iconMenuPresenter.getMenuView(decorView);
- if (init && frozenMenuState != null) {
- iconMenuPresenter.restoreHierarchyState(frozenMenuState);
- }
-
return result;
}
@@ -3097,12 +3110,7 @@
if (menu != null) {
savedState.menuState = new Bundle();
- if (iconMenuPresenter != null) {
- iconMenuPresenter.saveHierarchyState(savedState.menuState);
- }
- if (expandedMenuPresenter != null) {
- expandedMenuPresenter.saveHierarchyState(savedState.menuState);
- }
+ menu.savePresenterStates(savedState.menuState);
}
return savedState;
@@ -3127,6 +3135,13 @@
decorView = null;
}
+ void applyFrozenState() {
+ if (menu != null && frozenMenuState != null) {
+ menu.restorePresenterStates(frozenMenuState);
+ frozenMenuState = null;
+ }
+ }
+
private static class SavedState implements Parcelable {
int featureId;
boolean isOpen;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 75d24a1..a0407b9 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -20,23 +20,13 @@
libmedia \
libhardware \
libhardware_legacy \
- libeffects
+ libeffects \
+ libdl
LOCAL_STATIC_LIBRARIES := \
+ libcpustats \
libmedia_helper
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
-
LOCAL_MODULE:= libaudioflinger
-ifeq ($(TARGET_SIMULATOR),true)
- ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt -lpthread
- endif
-endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index daf94f2..86d4cc3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -52,6 +52,9 @@
#include <media/EffectsFactoryApi.h>
#include <audio_effects/effect_visualizer.h>
+#include <cpustats/ThreadCpuUsage.h>
+// #define DEBUG_CPU_USAGE 10 // log statistics every n wall clock seconds
+
// ----------------------------------------------------------------------------
@@ -1529,9 +1532,40 @@
uint32_t idleSleepTime = idleSleepTimeUs();
uint32_t sleepTime = idleSleepTime;
Vector< sp<EffectChain> > effectChains;
+#ifdef DEBUG_CPU_USAGE
+ ThreadCpuUsage cpu;
+ const CentralTendencyStatistics& stats = cpu.statistics();
+#endif
while (!exitPending())
{
+#ifdef DEBUG_CPU_USAGE
+ cpu.sampleAndEnable();
+ unsigned n = stats.n();
+ // cpu.elapsed() is expensive, so don't call it every loop
+ if ((n & 127) == 1) {
+ long long elapsed = cpu.elapsed();
+ if (elapsed >= DEBUG_CPU_USAGE * 1000000000LL) {
+ double perLoop = elapsed / (double) n;
+ double perLoop100 = perLoop * 0.01;
+ double mean = stats.mean();
+ double stddev = stats.stddev();
+ double minimum = stats.minimum();
+ double maximum = stats.maximum();
+ cpu.resetStatistics();
+ LOGI("CPU usage over past %.1f secs (%u mixer loops at %.1f mean ms per loop):\n us per mix loop: mean=%.0f stddev=%.0f min=%.0f max=%.0f\n %% of wall: mean=%.1f stddev=%.1f min=%.1f max=%.1f",
+ elapsed * .000000001, n, perLoop * .000001,
+ mean * .001,
+ stddev * .001,
+ minimum * .001,
+ maximum * .001,
+ mean / perLoop100,
+ stddev / perLoop100,
+ minimum / perLoop100,
+ maximum / perLoop100);
+ }
+ }
+#endif
processConfigEvents();
mixerStatus = MIXER_IDLE;
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 47ca3a0..8e16d94 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -48,9 +48,6 @@
static const int kDumpLockSleep = 20000;
static bool checkPermission() {
-#ifndef HAVE_ANDROID_OS
- return true;
-#endif
if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
if (!ok) LOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
diff --git a/services/camera/libcameraservice/CameraHardwareStub.h b/services/camera/libcameraservice/CameraHardwareStub.h
index 9b66a76..c6d8756 100644
--- a/services/camera/libcameraservice/CameraHardwareStub.h
+++ b/services/camera/libcameraservice/CameraHardwareStub.h
@@ -73,14 +73,7 @@
CameraHardwareStub* mHardware;
public:
PreviewThread(CameraHardwareStub* hw) :
-#ifdef SINGLE_PROCESS
- // In single process mode this thread needs to be a java thread,
- // since we won't be calling through the binder.
- Thread(true),
-#else
- Thread(false),
-#endif
- mHardware(hw) { }
+ Thread(false), mHardware(hw) { }
virtual void onFirstRef() {
run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
}
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
index f86ca47..e390ae20 100644
--- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
@@ -29,7 +29,6 @@
#include <camera/ICamera.h>
#include <camera/ICameraClient.h>
#include <camera/ICameraService.h>
-#include <ui/Overlay.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -311,8 +310,6 @@
virtual status_t registerBuffers(const BufferHeap& buffers);
virtual void postBuffer(ssize_t offset);
virtual void unregisterBuffers();
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format, int32_t orientation);
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
virtual status_t setBufferCount(int bufferCount);
@@ -381,13 +378,6 @@
}
}
-sp<OverlayRef> MSurface::createOverlay(uint32_t w, uint32_t h, int32_t format,
- int32_t orientation) {
- // Not implemented.
- ASSERT(0);
- return NULL;
-}
-
//
// Utilities to use the Holder service
//
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 836c081..e36507a 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -41,10 +41,6 @@
LOCAL_MODULE_TAGS := optional
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -lpthread
-endif
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index cc80062..8902f7a 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -26,26 +26,32 @@
namespace android {
/*
- * A handle to an application that can receive input.
- * Used by the native input dispatcher to indirectly refer to the window manager objects
+ * Describes the properties of an application that can receive input.
+ *
+ * Used by the native input dispatcher as a handle for the window manager objects
* that describe an application.
*/
class InputApplicationHandle : public RefBase {
+public:
+ String8 name;
+ nsecs_t dispatchingTimeout;
+
+ /**
+ * Requests that the state of this object be updated to reflect
+ * the most current available information about the application.
+ *
+ * This method should only be called from within the input dispatcher's
+ * critical section.
+ *
+ * Returns true on success, or false if the handle is no longer valid.
+ */
+ virtual bool update() = 0;
+
protected:
InputApplicationHandle() { }
virtual ~InputApplicationHandle() { }
};
-
-/*
- * An input application describes properties of an application that can receive input.
- */
-struct InputApplication {
- sp<InputApplicationHandle> inputApplicationHandle;
- String8 name;
- nsecs_t dispatchingTimeout;
-};
-
} // namespace android
#endif // _UI_INPUT_APPLICATION_H
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 10b9083..1cac5025 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -211,11 +211,8 @@
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(true), mDispatchFrozen(false), mInputFilterEnabled(false),
- mFocusedWindow(NULL),
- mFocusedApplication(NULL),
mCurrentInputTargetsValid(false),
- mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE),
- mLastHoverWindow(NULL) {
+ mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
mInboundQueue.headSentinel.refCount = -1;
@@ -501,16 +498,15 @@
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
- && mInputTargetWaitApplication != NULL) {
+ && mInputTargetWaitApplicationHandle != NULL) {
int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_Y));
- const InputWindow* touchedWindow = findTouchedWindowAtLocked(x, y);
- if (touchedWindow
- && touchedWindow->inputWindowHandle != NULL
- && touchedWindow->inputWindowHandle->getInputApplicationHandle()
- != mInputTargetWaitApplication) {
+ sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
+ if (touchedWindowHandle != NULL
+ && touchedWindowHandle->inputApplicationHandle
+ != mInputTargetWaitApplicationHandle) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
@@ -524,25 +520,25 @@
return needWake;
}
-const InputWindow* InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
+sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) {
// Traverse windows from front to back to find touched window.
- size_t numWindows = mWindows.size();
+ size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* window = & mWindows.editItemAt(i);
- int32_t flags = window->layoutParamsFlags;
+ sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ int32_t flags = windowHandle->layoutParamsFlags;
- if (window->visible) {
- if (!(flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
- bool isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
- | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
+ if (windowHandle->visible) {
+ if (!(flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
+ bool isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
+ | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
// Found window.
- return window;
+ return windowHandle;
}
}
}
- if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
+ if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
// Error window is on top but not visible, so touch is dropped.
return NULL;
}
@@ -781,8 +777,8 @@
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
- if (mFocusedWindow) {
- commandEntry->inputWindowHandle = mFocusedWindow->inputWindowHandle;
+ if (mFocusedWindowHandle != NULL) {
+ commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
@@ -1011,7 +1007,7 @@
mCurrentInputTargetsValid = false;
mCurrentInputTargets.clear();
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
- mInputTargetWaitApplication.clear();
+ mInputTargetWaitApplicationHandle.clear();
}
void InputDispatcher::commitTargetsLocked() {
@@ -1019,9 +1015,11 @@
}
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
- const EventEntry* entry, const InputApplication* application, const InputWindow* window,
+ const EventEntry* entry,
+ const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime) {
- if (application == NULL && window == NULL) {
+ if (applicationHandle == NULL && windowHandle == NULL) {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
#if DEBUG_FOCUS
LOGD("Waiting for system to become ready for input.");
@@ -1030,29 +1028,29 @@
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplication.clear();
+ mInputTargetWaitApplicationHandle.clear();
}
} else {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
#if DEBUG_FOCUS
LOGD("Waiting for application to become ready for input: %s",
- getApplicationWindowLabelLocked(application, window).string());
+ getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
#endif
- nsecs_t timeout = window ? window->dispatchingTimeout :
- application ? application->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
+ nsecs_t timeout = windowHandle != NULL ? windowHandle->dispatchingTimeout :
+ applicationHandle != NULL ?
+ applicationHandle->dispatchingTimeout : DEFAULT_INPUT_DISPATCHING_TIMEOUT;
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = currentTime + timeout;
mInputTargetWaitTimeoutExpired = false;
- mInputTargetWaitApplication.clear();
+ mInputTargetWaitApplicationHandle.clear();
- if (window && window->inputWindowHandle != NULL) {
- mInputTargetWaitApplication =
- window->inputWindowHandle->getInputApplicationHandle();
+ if (windowHandle != NULL) {
+ mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
}
- if (mInputTargetWaitApplication == NULL && application) {
- mInputTargetWaitApplication = application->inputApplicationHandle;
+ if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
+ mInputTargetWaitApplicationHandle = applicationHandle;
}
}
}
@@ -1062,7 +1060,8 @@
}
if (currentTime >= mInputTargetWaitTimeoutTime) {
- onANRLocked(currentTime, application, window, entry->eventTime, mInputTargetWaitStartTime);
+ onANRLocked(currentTime, applicationHandle, windowHandle,
+ entry->eventTime, mInputTargetWaitStartTime);
// Force poll loop to wake up immediately on next iteration once we get the
// ANR response back from the policy.
@@ -1129,15 +1128,15 @@
// If there is no currently focused window and no focused application
// then drop the event.
- if (! mFocusedWindow) {
- if (mFocusedApplication) {
+ if (mFocusedWindowHandle == NULL) {
+ if (mFocusedApplicationHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Waiting because there is no focused window but there is a "
"focused application that may eventually add a window: %s.",
- getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
+ getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string());
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, NULL, nextWakeupTime);
+ mFocusedApplicationHandle, NULL, nextWakeupTime);
goto Unresponsive;
}
@@ -1147,34 +1146,34 @@
}
// Check permissions.
- if (! checkInjectionPermission(mFocusedWindow, entry->injectionState)) {
+ if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
goto Failed;
}
// If the currently focused window is paused then keep waiting.
- if (mFocusedWindow->paused) {
+ if (mFocusedWindowHandle->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because focused window is paused.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
+ mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime);
goto Unresponsive;
}
// If the currently focused window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindow)) {
+ if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) {
#if DEBUG_FOCUS
LOGD("Waiting because focused window still processing previous input.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, mFocusedWindow, nextWakeupTime);
+ mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime);
goto Unresponsive;
}
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindow,
+ addWindowTargetLocked(mFocusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
// Done.
@@ -1236,7 +1235,7 @@
// Update the touch state as needed based on the properties of the touch event.
int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;
InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;
- const InputWindow* newHoverWindow = NULL;
+ sp<InputWindowHandle> newHoverWindowHandle;
bool isSplit = mTouchState.split;
bool switchedDevice = mTouchState.deviceId >= 0
@@ -1279,42 +1278,44 @@
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(sample->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
- const InputWindow* newTouchedWindow = NULL;
- const InputWindow* topErrorWindow = NULL;
+ sp<InputWindowHandle> newTouchedWindowHandle;
+ sp<InputWindowHandle> topErrorWindowHandle;
bool isTouchModal = false;
// Traverse windows from front to back to find touched window and outside targets.
- size_t numWindows = mWindows.size();
+ size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* window = & mWindows.editItemAt(i);
- int32_t flags = window->layoutParamsFlags;
+ sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ int32_t flags = windowHandle->layoutParamsFlags;
- if (flags & InputWindow::FLAG_SYSTEM_ERROR) {
- if (! topErrorWindow) {
- topErrorWindow = window;
+ if (flags & InputWindowHandle::FLAG_SYSTEM_ERROR) {
+ if (topErrorWindowHandle == NULL) {
+ topErrorWindowHandle = windowHandle;
}
}
- if (window->visible) {
- if (! (flags & InputWindow::FLAG_NOT_TOUCHABLE)) {
- isTouchModal = (flags & (InputWindow::FLAG_NOT_FOCUSABLE
- | InputWindow::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || window->touchableRegionContainsPoint(x, y)) {
- if (! screenWasOff || flags & InputWindow::FLAG_TOUCHABLE_WHEN_WAKING) {
- newTouchedWindow = window;
+ if (windowHandle->visible) {
+ if (! (flags & InputWindowHandle::FLAG_NOT_TOUCHABLE)) {
+ isTouchModal = (flags & (InputWindowHandle::FLAG_NOT_FOCUSABLE
+ | InputWindowHandle::FLAG_NOT_TOUCH_MODAL)) == 0;
+ if (isTouchModal || windowHandle->touchableRegionContainsPoint(x, y)) {
+ if (! screenWasOff
+ || (flags & InputWindowHandle::FLAG_TOUCHABLE_WHEN_WAKING)) {
+ newTouchedWindowHandle = windowHandle;
}
break; // found touched window, exit window loop
}
}
if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- && (flags & InputWindow::FLAG_WATCH_OUTSIDE_TOUCH)) {
+ && (flags & InputWindowHandle::FLAG_WATCH_OUTSIDE_TOUCH)) {
int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE;
- if (isWindowObscuredAtPointLocked(window, x, y)) {
+ if (isWindowObscuredAtPointLocked(windowHandle, x, y)) {
outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
- mTempTouchState.addOrUpdateWindow(window, outsideTargetFlags, BitSet32(0));
+ mTempTouchState.addOrUpdateWindow(
+ windowHandle, outsideTargetFlags, BitSet32(0));
}
}
}
@@ -1322,7 +1323,7 @@
// If there is an error window but it is not taking focus (typically because
// it is invisible) then wait for it. Any other focused window may in
// fact be in ANR state.
- if (topErrorWindow && newTouchedWindow != topErrorWindow) {
+ if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) {
#if DEBUG_FOCUS
LOGD("Waiting because system error window is pending.");
#endif
@@ -1333,26 +1334,26 @@
}
// Figure out whether splitting will be allowed for this window.
- if (newTouchedWindow && newTouchedWindow->supportsSplitTouch()) {
+ if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->supportsSplitTouch()) {
// New window supports splitting.
isSplit = true;
} else if (isSplit) {
// New window does not support splitting but we have already split events.
// Assign the pointer to the first foreground window we find.
// (May be NULL which is why we put this code block before the next check.)
- newTouchedWindow = mTempTouchState.getFirstForegroundWindow();
+ newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
}
// If we did not find a touched window then fail.
- if (! newTouchedWindow) {
- if (mFocusedApplication) {
+ if (newTouchedWindowHandle == NULL) {
+ if (mFocusedApplicationHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Waiting because there is no touched window but there is a "
"focused application that may eventually add a new window: %s.",
- getApplicationWindowLabelLocked(mFocusedApplication, NULL).string());
+ getApplicationWindowLabelLocked(mFocusedApplicationHandle, NULL).string());
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplication, NULL, nextWakeupTime);
+ mFocusedApplicationHandle, NULL, nextWakeupTime);
goto Unresponsive;
}
@@ -1366,20 +1367,20 @@
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
- if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+ if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
// Update hover state.
if (isHoverAction) {
- newHoverWindow = newTouchedWindow;
+ newHoverWindowHandle = newTouchedWindowHandle;
// Ensure all subsequent motion samples are also within the touched window.
// Set *outSplitBatchAfterSample to the sample before the first one that is not
// within the touched window.
if (!isTouchModal) {
while (sample->next) {
- if (!newHoverWindow->touchableRegionContainsPoint(
+ if (!newHoverWindowHandle->touchableRegionContainsPoint(
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
*outSplitBatchAfterSample = sample;
@@ -1389,7 +1390,7 @@
}
}
} else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
- newHoverWindow = mLastHoverWindow;
+ newHoverWindowHandle = mLastHoverWindowHandle;
}
// Update the temporary touch state.
@@ -1398,7 +1399,7 @@
uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
pointerIds.markBit(pointerId);
}
- mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
+ mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -1420,19 +1421,22 @@
int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- const InputWindow* oldTouchedWindow = mTempTouchState.getFirstForegroundWindow();
- const InputWindow* newTouchedWindow = findTouchedWindowAtLocked(x, y);
- if (oldTouchedWindow != newTouchedWindow && newTouchedWindow) {
+ sp<InputWindowHandle> oldTouchedWindowHandle =
+ mTempTouchState.getFirstForegroundWindowHandle();
+ sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(x, y);
+ if (oldTouchedWindowHandle != newTouchedWindowHandle
+ && newTouchedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Touch is slipping out of window %s into window %s.",
- oldTouchedWindow->name.string(), newTouchedWindow->name.string());
+ oldTouchedWindowHandle->name.string(),
+ newTouchedWindowHandle->name.string());
#endif
// Make a slippery exit from the old window.
- mTempTouchState.addOrUpdateWindow(oldTouchedWindow,
+ mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));
// Make a slippery entrance into the new window.
- if (newTouchedWindow->supportsSplitTouch()) {
+ if (newTouchedWindowHandle->supportsSplitTouch()) {
isSplit = true;
}
@@ -1441,7 +1445,7 @@
if (isSplit) {
targetFlags |= InputTarget::FLAG_SPLIT;
}
- if (isWindowObscuredAtPointLocked(newTouchedWindow, x, y)) {
+ if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
}
@@ -1449,7 +1453,7 @@
if (isSplit) {
pointerIds.markBit(entry->pointerProperties[0].id);
}
- mTempTouchState.addOrUpdateWindow(newTouchedWindow, targetFlags, pointerIds);
+ mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
// Split the batch here so we send exactly one sample.
*outSplitBatchAfterSample = &entry->firstSample;
@@ -1457,25 +1461,25 @@
}
}
- if (newHoverWindow != mLastHoverWindow) {
+ if (newHoverWindowHandle != mLastHoverWindowHandle) {
// Split the batch here so we send exactly one sample as part of ENTER or EXIT.
*outSplitBatchAfterSample = &entry->firstSample;
// Let the previous window know that the hover sequence is over.
- if (mLastHoverWindow) {
+ if (mLastHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover exit event to window %s.", mLastHoverWindow->name.string());
+ LOGD("Sending hover exit event to window %s.", mLastHoverWindowHandle->name.string());
#endif
- mTempTouchState.addOrUpdateWindow(mLastHoverWindow,
+ mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
}
// Let the new window know that the hover sequence is starting.
- if (newHoverWindow) {
+ if (newHoverWindowHandle != NULL) {
#if DEBUG_HOVER
- LOGD("Sending hover enter event to window %s.", newHoverWindow->name.string());
+ LOGD("Sending hover enter event to window %s.", newHoverWindowHandle->name.string());
#endif
- mTempTouchState.addOrUpdateWindow(newHoverWindow,
+ mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
}
}
@@ -1488,7 +1492,8 @@
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
haveForegroundWindow = true;
- if (! checkInjectionPermission(touchedWindow.window, entry->injectionState)) {
+ if (! checkInjectionPermission(touchedWindow.windowHandle,
+ entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
injectionPermission = INJECTION_PERMISSION_DENIED;
goto Failed;
@@ -1510,14 +1515,15 @@
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
- const int32_t foregroundWindowUid = foregroundWindow->ownerUid;
+ sp<InputWindowHandle> foregroundWindowHandle =
+ mTempTouchState.getFirstForegroundWindowHandle();
+ const int32_t foregroundWindowUid = foregroundWindowHandle->ownerUid;
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
- const InputWindow* inputWindow = touchedWindow.window;
- if (inputWindow->ownerUid != foregroundWindowUid) {
- mTempTouchState.addOrUpdateWindow(inputWindow,
+ sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
+ if (inputWindowHandle->ownerUid != foregroundWindowUid) {
+ mTempTouchState.addOrUpdateWindow(inputWindowHandle,
InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
}
}
@@ -1529,22 +1535,22 @@
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
// If the touched window is paused then keep waiting.
- if (touchedWindow.window->paused) {
+ if (touchedWindow.windowHandle->paused) {
#if DEBUG_FOCUS
LOGD("Waiting because touched window is paused.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- NULL, touchedWindow.window, nextWakeupTime);
+ NULL, touchedWindow.windowHandle, nextWakeupTime);
goto Unresponsive;
}
// If the touched window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.window)) {
+ if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
LOGD("Waiting because touched window still processing previous input.");
#endif
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- NULL, touchedWindow.window, nextWakeupTime);
+ NULL, touchedWindow.windowHandle, nextWakeupTime);
goto Unresponsive;
}
}
@@ -1557,12 +1563,13 @@
// engine only supports touch events. We would need to add a mechanism similar
// to View.onGenericMotionEvent to enable wallpapers to handle these events.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- const InputWindow* foregroundWindow = mTempTouchState.getFirstForegroundWindow();
- if (foregroundWindow->hasWallpaper) {
- for (size_t i = 0; i < mWindows.size(); i++) {
- const InputWindow* window = & mWindows[i];
- if (window->layoutParamsType == InputWindow::TYPE_WALLPAPER) {
- mTempTouchState.addOrUpdateWindow(window,
+ sp<InputWindowHandle> foregroundWindowHandle =
+ mTempTouchState.getFirstForegroundWindowHandle();
+ if (foregroundWindowHandle->hasWallpaper) {
+ for (size_t i = 0; i < mWindowHandles.size(); i++) {
+ sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+ if (windowHandle->layoutParamsType == InputWindowHandle::TYPE_WALLPAPER) {
+ mTempTouchState.addOrUpdateWindow(windowHandle,
InputTarget::FLAG_WINDOW_IS_OBSCURED
| InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0));
@@ -1576,7 +1583,7 @@
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
- addWindowTargetLocked(touchedWindow.window, touchedWindow.targetFlags,
+ addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds);
}
@@ -1658,7 +1665,7 @@
}
// Update hover state.
- mLastHoverWindow = newHoverWindow;
+ mLastHoverWindowHandle = newHoverWindowHandle;
}
} else {
#if DEBUG_FOCUS
@@ -1681,16 +1688,16 @@
return injectionResult;
}
-void InputDispatcher::addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
- BitSet32 pointerIds) {
+void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds) {
mCurrentInputTargets.push();
InputTarget& target = mCurrentInputTargets.editTop();
- target.inputChannel = window->inputChannel;
+ target.inputChannel = windowHandle->inputChannel;
target.flags = targetFlags;
- target.xOffset = - window->frameLeft;
- target.yOffset = - window->frameTop;
- target.scaleFactor = window->scaleFactor;
+ target.xOffset = - windowHandle->frameLeft;
+ target.yOffset = - windowHandle->frameTop;
+ target.scaleFactor = windowHandle->scaleFactor;
target.pointerIds = pointerIds;
}
@@ -1708,17 +1715,17 @@
}
}
-bool InputDispatcher::checkInjectionPermission(const InputWindow* window,
+bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState) {
if (injectionState
- && (window == NULL || window->ownerUid != injectionState->injectorUid)
+ && (windowHandle == NULL || windowHandle->ownerUid != injectionState->injectorUid)
&& !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
- if (window) {
- LOGW("Permission denied: injecting event from pid %d uid %d to window "
- "with input channel %s owned by uid %d",
+ if (windowHandle != NULL) {
+ LOGW("Permission denied: injecting event from pid %d uid %d to window %s "
+ "owned by uid %d",
injectionState->injectorPid, injectionState->injectorUid,
- window->inputChannel->getName().string(),
- window->ownerUid);
+ windowHandle->name.string(),
+ windowHandle->ownerUid);
} else {
LOGW("Permission denied: injecting event from pid %d uid %d",
injectionState->injectorPid, injectionState->injectorUid);
@@ -1729,22 +1736,24 @@
}
bool InputDispatcher::isWindowObscuredAtPointLocked(
- const InputWindow* window, int32_t x, int32_t y) const {
- size_t numWindows = mWindows.size();
+ const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
+ size_t numWindows = mWindowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* other = & mWindows.itemAt(i);
- if (other == window) {
+ sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+ if (otherHandle == windowHandle) {
break;
}
- if (other->visible && ! other->isTrustedOverlay() && other->frameContainsPoint(x, y)) {
+ if (otherHandle->visible && ! otherHandle->isTrustedOverlay()
+ && otherHandle->frameContainsPoint(x, y)) {
return true;
}
}
return false;
}
-bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(const InputWindow* window) {
- ssize_t connectionIndex = getConnectionIndexLocked(window->inputChannel);
+bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
+ const sp<InputWindowHandle>& windowHandle) {
+ ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
return connection->outboundQueue.isEmpty();
@@ -1753,19 +1762,20 @@
}
}
-String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication* application,
- const InputWindow* window) {
- if (application) {
- if (window) {
- String8 label(application->name);
+String8 InputDispatcher::getApplicationWindowLabelLocked(
+ const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle) {
+ if (applicationHandle != NULL) {
+ if (windowHandle != NULL) {
+ String8 label(applicationHandle->name);
label.append(" - ");
- label.append(window->name);
+ label.append(windowHandle->name);
return label;
} else {
- return application->name;
+ return applicationHandle->name;
}
- } else if (window) {
- return window->name;
+ } else if (windowHandle != NULL) {
+ return windowHandle->name;
} else {
return String8("<unknown application or window>");
}
@@ -2422,11 +2432,11 @@
}
InputTarget target;
- const InputWindow* window = getWindowLocked(connection->inputChannel);
- if (window) {
- target.xOffset = -window->frameLeft;
- target.yOffset = -window->frameTop;
- target.scaleFactor = window->scaleFactor;
+ sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
+ if (windowHandle != NULL) {
+ target.xOffset = -windowHandle->frameLeft;
+ target.yOffset = -windowHandle->frameTop;
+ target.scaleFactor = windowHandle->scaleFactor;
} else {
target.xOffset = 0;
target.yOffset = 0;
@@ -2809,7 +2819,7 @@
}
if (action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- if (!mLastHoverWindow) {
+ if (mLastHoverWindowHandle == NULL) {
#if DEBUG_BATCHING
LOGD("Not streaming hover move because there is no "
"last hovered window.");
@@ -2817,15 +2827,16 @@
goto NoBatchingOrStreaming;
}
- const InputWindow* hoverWindow = findTouchedWindowAtLocked(
+ sp<InputWindowHandle> hoverWindowHandle = findTouchedWindowAtLocked(
pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- if (mLastHoverWindow != hoverWindow) {
+ if (mLastHoverWindowHandle != hoverWindowHandle) {
#if DEBUG_BATCHING
LOGD("Not streaming hover move because the last hovered window "
"is '%s' but the currently hovered window is '%s'.",
- mLastHoverWindow->name.string(),
- hoverWindow ? hoverWindow->name.string() : "<null>");
+ mLastHoverWindowHandle->name.string(),
+ hoverWindowHandle != NULL
+ ? hoverWindowHandle->name.string() : "<null>");
#endif
goto NoBatchingOrStreaming;
}
@@ -3125,113 +3136,109 @@
}
}
-const InputWindow* InputDispatcher::getWindowLocked(const sp<InputChannel>& inputChannel) {
- for (size_t i = 0; i < mWindows.size(); i++) {
- const InputWindow* window = & mWindows[i];
- if (window->inputChannel == inputChannel) {
- return window;
+sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
+ const sp<InputChannel>& inputChannel) const {
+ size_t numWindows = mWindowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+ if (windowHandle->inputChannel == inputChannel) {
+ return windowHandle;
}
}
return NULL;
}
-void InputDispatcher::setInputWindows(const Vector<InputWindow>& inputWindows) {
+bool InputDispatcher::hasWindowHandleLocked(
+ const sp<InputWindowHandle>& windowHandle) const {
+ size_t numWindows = mWindowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ if (mWindowHandles.itemAt(i) == windowHandle) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
#if DEBUG_FOCUS
LOGD("setInputWindows");
#endif
{ // acquire lock
AutoMutex _l(mLock);
- // Clear old window pointers.
- sp<InputChannel> oldFocusedWindowChannel;
- if (mFocusedWindow) {
- oldFocusedWindowChannel = mFocusedWindow->inputChannel;
- mFocusedWindow = NULL;
- }
- sp<InputChannel> oldLastHoverWindowChannel;
- if (mLastHoverWindow) {
- oldLastHoverWindowChannel = mLastHoverWindow->inputChannel;
- mLastHoverWindow = NULL;
- }
+ mWindowHandles = inputWindowHandles;
- mWindows.clear();
-
- // Loop over new windows and rebuild the necessary window pointers for
- // tracking focus and touch.
- mWindows.appendVector(inputWindows);
-
- size_t numWindows = mWindows.size();
- for (size_t i = 0; i < numWindows; i++) {
- const InputWindow* window = & mWindows.itemAt(i);
- if (window->hasFocus) {
- mFocusedWindow = window;
- break;
+ sp<InputWindowHandle> newFocusedWindowHandle;
+ bool foundHoveredWindow = false;
+ for (size_t i = 0; i < mWindowHandles.size(); i++) {
+ const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
+ if (!windowHandle->update() || windowHandle->inputChannel == NULL) {
+ mWindowHandles.removeAt(i--);
+ continue;
+ }
+ if (windowHandle->hasFocus) {
+ newFocusedWindowHandle = windowHandle;
+ }
+ if (windowHandle == mLastHoverWindowHandle) {
+ foundHoveredWindow = true;
}
}
- if (oldFocusedWindowChannel != NULL) {
- if (!mFocusedWindow || oldFocusedWindowChannel != mFocusedWindow->inputChannel) {
+ if (!foundHoveredWindow) {
+ mLastHoverWindowHandle = NULL;
+ }
+
+ if (mFocusedWindowHandle != newFocusedWindowHandle) {
+ if (mFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
LOGD("Focus left window: %s",
- oldFocusedWindowChannel->getName().string());
+ mFocusedWindowHandle->name.string());
#endif
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
- synthesizeCancelationEventsForInputChannelLocked(oldFocusedWindowChannel, options);
- oldFocusedWindowChannel.clear();
+ synthesizeCancelationEventsForInputChannelLocked(
+ mFocusedWindowHandle->inputChannel, options);
}
- }
- if (mFocusedWindow && oldFocusedWindowChannel == NULL) {
+ if (newFocusedWindowHandle != NULL) {
#if DEBUG_FOCUS
- LOGD("Focus entered window: %s",
- mFocusedWindow->inputChannel->getName().string());
+ LOGD("Focus entered window: %s",
+ newFocusedWindowHandle->name.string());
#endif
+ }
+ mFocusedWindowHandle = newFocusedWindowHandle;
}
- for (size_t i = 0; i < mTouchState.windows.size(); ) {
+ for (size_t i = 0; i < mTouchState.windows.size(); i++) {
TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i);
- const InputWindow* window = getWindowLocked(touchedWindow.channel);
- if (window) {
- touchedWindow.window = window;
- i += 1;
- } else {
+ if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
- LOGD("Touched window was removed: %s", touchedWindow.channel->getName().string());
+ LOGD("Touched window was removed: %s", touchedWindow.windowHandle->name.string());
#endif
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"touched window was removed");
- synthesizeCancelationEventsForInputChannelLocked(touchedWindow.channel, options);
- mTouchState.windows.removeAt(i);
+ synthesizeCancelationEventsForInputChannelLocked(
+ touchedWindow.windowHandle->inputChannel, options);
+ mTouchState.windows.removeAt(i--);
}
}
-
- // Recover the last hovered window.
- if (oldLastHoverWindowChannel != NULL) {
- mLastHoverWindow = getWindowLocked(oldLastHoverWindowChannel);
- oldLastHoverWindowChannel.clear();
- }
-
-#if DEBUG_FOCUS
- //logDispatchStateLocked();
-#endif
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
-void InputDispatcher::setFocusedApplication(const InputApplication* inputApplication) {
+void InputDispatcher::setFocusedApplication(
+ const sp<InputApplicationHandle>& inputApplicationHandle) {
#if DEBUG_FOCUS
LOGD("setFocusedApplication");
#endif
{ // acquire lock
AutoMutex _l(mLock);
- releaseFocusedApplicationLocked();
-
- if (inputApplication) {
- mFocusedApplicationStorage = *inputApplication;
- mFocusedApplication = & mFocusedApplicationStorage;
+ if (inputApplicationHandle != NULL && inputApplicationHandle->update()) {
+ mFocusedApplicationHandle = inputApplicationHandle;
+ } else {
+ mFocusedApplicationHandle.clear();
}
#if DEBUG_FOCUS
@@ -3243,13 +3250,6 @@
mLooper->wake();
}
-void InputDispatcher::releaseFocusedApplicationLocked() {
- if (mFocusedApplication) {
- mFocusedApplication = NULL;
- mFocusedApplicationStorage.inputApplicationHandle.clear();
- }
-}
-
void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
#if DEBUG_FOCUS
LOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
@@ -3315,15 +3315,15 @@
{ // acquire lock
AutoMutex _l(mLock);
- const InputWindow* fromWindow = getWindowLocked(fromChannel);
- const InputWindow* toWindow = getWindowLocked(toChannel);
- if (! fromWindow || ! toWindow) {
+ sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
+ sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
+ if (fromWindowHandle == NULL || toWindowHandle == NULL) {
#if DEBUG_FOCUS
LOGD("Cannot transfer focus because from or to window not found.");
#endif
return false;
}
- if (fromWindow == toWindow) {
+ if (fromWindowHandle == toWindowHandle) {
#if DEBUG_FOCUS
LOGD("Trivial transfer to same window.");
#endif
@@ -3333,7 +3333,7 @@
bool found = false;
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTouchState.windows[i];
- if (touchedWindow.window == fromWindow) {
+ if (touchedWindow.windowHandle == fromWindowHandle) {
int32_t oldTargetFlags = touchedWindow.targetFlags;
BitSet32 pointerIds = touchedWindow.pointerIds;
@@ -3342,7 +3342,7 @@
int32_t newTargetFlags = oldTargetFlags
& (InputTarget::FLAG_FOREGROUND
| InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
- mTouchState.addOrUpdateWindow(toWindow, newTargetFlags, pointerIds);
+ mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds);
found = true;
break;
@@ -3392,7 +3392,7 @@
resetTargetsLocked();
mTouchState.reset();
- mLastHoverWindow = NULL;
+ mLastHoverWindowHandle.clear();
}
void InputDispatcher::logDispatchStateLocked() {
@@ -3415,15 +3415,15 @@
dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
- if (mFocusedApplication) {
+ if (mFocusedApplicationHandle != NULL) {
dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
- mFocusedApplication->name.string(),
- mFocusedApplication->dispatchingTimeout / 1000000.0);
+ mFocusedApplicationHandle->name.string(),
+ mFocusedApplicationHandle->dispatchingTimeout / 1000000.0);
} else {
dump.append(INDENT "FocusedApplication: <null>\n");
}
dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
- mFocusedWindow != NULL ? mFocusedWindow->name.string() : "<null>");
+ mFocusedWindowHandle != NULL ? mFocusedWindowHandle->name.string() : "<null>");
dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down));
dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split));
@@ -3434,37 +3434,37 @@
for (size_t i = 0; i < mTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTouchState.windows[i];
dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
- i, touchedWindow.window->name.string(), touchedWindow.pointerIds.value,
+ i, touchedWindow.windowHandle->name.string(), touchedWindow.pointerIds.value,
touchedWindow.targetFlags);
}
} else {
dump.append(INDENT "TouchedWindows: <none>\n");
}
- if (!mWindows.isEmpty()) {
+ if (!mWindowHandles.isEmpty()) {
dump.append(INDENT "Windows:\n");
- for (size_t i = 0; i < mWindows.size(); i++) {
- const InputWindow& window = mWindows[i];
+ for (size_t i = 0; i < mWindowHandles.size(); i++) {
+ const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
dump.appendFormat(INDENT2 "%d: name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], scale=%f, "
"touchableRegion=",
- i, window.name.string(),
- toString(window.paused),
- toString(window.hasFocus),
- toString(window.hasWallpaper),
- toString(window.visible),
- toString(window.canReceiveKeys),
- window.layoutParamsFlags, window.layoutParamsType,
- window.layer,
- window.frameLeft, window.frameTop,
- window.frameRight, window.frameBottom,
- window.scaleFactor);
- dumpRegion(dump, window.touchableRegion);
- dump.appendFormat(", inputFeatures=0x%08x", window.inputFeatures);
+ i, windowHandle->name.string(),
+ toString(windowHandle->paused),
+ toString(windowHandle->hasFocus),
+ toString(windowHandle->hasWallpaper),
+ toString(windowHandle->visible),
+ toString(windowHandle->canReceiveKeys),
+ windowHandle->layoutParamsFlags, windowHandle->layoutParamsType,
+ windowHandle->layer,
+ windowHandle->frameLeft, windowHandle->frameTop,
+ windowHandle->frameRight, windowHandle->frameBottom,
+ windowHandle->scaleFactor);
+ dumpRegion(dump, windowHandle->touchableRegion);
+ dump.appendFormat(", inputFeatures=0x%08x", windowHandle->inputFeatures);
dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
- window.ownerPid, window.ownerUid,
- window.dispatchingTimeout / 1000000.0);
+ windowHandle->ownerPid, windowHandle->ownerUid,
+ windowHandle->dispatchingTimeout / 1000000.0);
}
} else {
dump.append(INDENT "Windows: <none>\n");
@@ -3636,23 +3636,19 @@
}
void InputDispatcher::onANRLocked(
- nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+ nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t eventTime, nsecs_t waitStartTime) {
LOGI("Application is not responding: %s. "
"%01.1fms since event, %01.1fms since wait started",
- getApplicationWindowLabelLocked(application, window).string(),
+ getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
(currentTime - eventTime) / 1000000.0,
(currentTime - waitStartTime) / 1000000.0);
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
- if (application) {
- commandEntry->inputApplicationHandle = application->inputApplicationHandle;
- }
- if (window) {
- commandEntry->inputWindowHandle = window->inputWindowHandle;
- commandEntry->inputChannel = window->inputChannel;
- }
+ commandEntry->inputApplicationHandle = applicationHandle;
+ commandEntry->inputWindowHandle = windowHandle;
}
void InputDispatcher::doNotifyConfigurationChangedInterruptible(
@@ -3686,7 +3682,9 @@
mLock.lock();
- resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputChannel);
+ resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
+ commandEntry->inputWindowHandle != NULL
+ ? commandEntry->inputWindowHandle->inputChannel : NULL);
}
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -4560,11 +4558,10 @@
split = other.split;
deviceId = other.deviceId;
source = other.source;
- windows.clear();
- windows.appendVector(other.windows);
+ windows = other.windows;
}
-void InputDispatcher::TouchState::addOrUpdateWindow(const InputWindow* window,
+void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds) {
if (targetFlags & InputTarget::FLAG_SPLIT) {
split = true;
@@ -4572,7 +4569,7 @@
for (size_t i = 0; i < windows.size(); i++) {
TouchedWindow& touchedWindow = windows.editItemAt(i);
- if (touchedWindow.window == window) {
+ if (touchedWindow.windowHandle == windowHandle) {
touchedWindow.targetFlags |= targetFlags;
if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS;
@@ -4585,10 +4582,9 @@
windows.push();
TouchedWindow& touchedWindow = windows.editTop();
- touchedWindow.window = window;
+ touchedWindow.windowHandle = windowHandle;
touchedWindow.targetFlags = targetFlags;
touchedWindow.pointerIds = pointerIds;
- touchedWindow.channel = window->inputChannel;
}
void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
@@ -4605,11 +4601,11 @@
}
}
-const InputWindow* InputDispatcher::TouchState::getFirstForegroundWindow() const {
+sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows.itemAt(i);
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- return window.window;
+ return window.windowHandle;
}
}
return NULL;
@@ -4621,8 +4617,8 @@
for (size_t i = 0; i < windows.size(); i++) {
const TouchedWindow& window = windows.itemAt(i);
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
- if (haveSlipperyForegroundWindow
- || !(window.window->layoutParamsFlags & InputWindow::FLAG_SLIPPERY)) {
+ if (haveSlipperyForegroundWindow || !(window.windowHandle->layoutParamsFlags
+ & InputWindowHandle::FLAG_SLIPPERY)) {
return false;
}
haveSlipperyForegroundWindow = true;
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index bdd1922..15fd274 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -321,13 +321,14 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void setInputWindows(const Vector<InputWindow>& inputWindows) = 0;
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
/* Sets the focused application.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void setFocusedApplication(const InputApplication* inputApplication) = 0;
+ virtual void setFocusedApplication(
+ const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
/* Sets the input dispatching mode.
*
@@ -406,8 +407,8 @@
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags);
- virtual void setInputWindows(const Vector<InputWindow>& inputWindows);
- virtual void setFocusedApplication(const InputApplication* inputApplication);
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+ virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual void setInputFilterEnabled(bool enabled);
@@ -578,7 +579,6 @@
sp<Connection> connection;
nsecs_t eventTime;
KeyEntry* keyEntry;
- sp<InputChannel> inputChannel;
sp<InputApplicationHandle> inputApplicationHandle;
sp<InputWindowHandle> inputWindowHandle;
int32_t userActivityEventType;
@@ -894,7 +894,7 @@
// to transfer focus to a new application.
EventEntry* mNextUnblockedEvent;
- const InputWindow* findTouchedWindowAtLocked(int32_t x, int32_t y);
+ sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
// All registered connections mapped by receive pipe file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
@@ -953,19 +953,19 @@
bool mDispatchFrozen;
bool mInputFilterEnabled;
- Vector<InputWindow> mWindows;
+ Vector<sp<InputWindowHandle> > mWindowHandles;
- const InputWindow* getWindowLocked(const sp<InputChannel>& inputChannel);
+ sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
+ bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
// Focus tracking for keys, trackball, etc.
- const InputWindow* mFocusedWindow;
+ sp<InputWindowHandle> mFocusedWindowHandle;
// Focus tracking for touch.
struct TouchedWindow {
- const InputWindow* window;
+ sp<InputWindowHandle> windowHandle;
int32_t targetFlags;
BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
- sp<InputChannel> channel;
};
struct TouchState {
bool down;
@@ -978,9 +978,10 @@
~TouchState();
void reset();
void copyFrom(const TouchState& other);
- void addOrUpdateWindow(const InputWindow* window,int32_t targetFlags, BitSet32 pointerIds);
+ void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds);
void filterNonAsIsTouchWindows();
- const InputWindow* getFirstForegroundWindow() const;
+ sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
};
@@ -988,9 +989,7 @@
TouchState mTempTouchState;
// Focused application.
- InputApplication* mFocusedApplication;
- InputApplication mFocusedApplicationStorage; // preallocated storage for mFocusedApplication
- void releaseFocusedApplicationLocked();
+ sp<InputApplicationHandle> mFocusedApplicationHandle;
// Dispatch inbound events.
bool dispatchConfigurationChangedLocked(
@@ -1021,16 +1020,17 @@
nsecs_t mInputTargetWaitStartTime;
nsecs_t mInputTargetWaitTimeoutTime;
bool mInputTargetWaitTimeoutExpired;
- sp<InputApplicationHandle> mInputTargetWaitApplication;
+ sp<InputApplicationHandle> mInputTargetWaitApplicationHandle;
// Contains the last window which received a hover event.
- const InputWindow* mLastHoverWindow;
+ sp<InputWindowHandle> mLastHoverWindowHandle;
// Finding targets for input events.
void resetTargetsLocked();
void commitTargetsLocked();
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
- const InputApplication* application, const InputWindow* window,
+ const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime);
void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
const sp<InputChannel>& inputChannel);
@@ -1043,15 +1043,17 @@
nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
const MotionSample** outSplitBatchAfterSample);
- void addWindowTargetLocked(const InputWindow* window, int32_t targetFlags,
- BitSet32 pointerIds);
+ void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
+ int32_t targetFlags, BitSet32 pointerIds);
void addMonitoringTargetsLocked();
void pokeUserActivityLocked(const EventEntry* eventEntry);
- bool checkInjectionPermission(const InputWindow* window, const InjectionState* injectionState);
- bool isWindowObscuredAtPointLocked(const InputWindow* window, int32_t x, int32_t y) const;
- bool isWindowFinishedWithPreviousInputLocked(const InputWindow* window);
- String8 getApplicationWindowLabelLocked(const InputApplication* application,
- const InputWindow* window);
+ bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
+ const InjectionState* injectionState);
+ bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
+ int32_t x, int32_t y) const;
+ bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle);
+ String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle);
// Manage the dispatch cycle for a single connection.
// These methods are deliberately not Interruptible because doing all of the work
@@ -1100,7 +1102,8 @@
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onANRLocked(
- nsecs_t currentTime, const InputApplication* application, const InputWindow* window,
+ nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
+ const sp<InputWindowHandle>& windowHandle,
nsecs_t eventTime, nsecs_t waitStartTime);
// Outbound policy interactions.
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 49cb864..c9fac81 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -120,29 +120,31 @@
static const size_t keyCodeRotationMapSize =
sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
-int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
+static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
return rotateValueUsingRotationMap(keyCode, orientation,
keyCodeRotationMap, keyCodeRotationMapSize);
}
-static const int32_t edgeFlagRotationMap[][4] = {
- // edge flags enumerated counter-clockwise with the original (unrotated) edge flag first
- // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
- { AMOTION_EVENT_EDGE_FLAG_BOTTOM, AMOTION_EVENT_EDGE_FLAG_RIGHT,
- AMOTION_EVENT_EDGE_FLAG_TOP, AMOTION_EVENT_EDGE_FLAG_LEFT },
- { AMOTION_EVENT_EDGE_FLAG_RIGHT, AMOTION_EVENT_EDGE_FLAG_TOP,
- AMOTION_EVENT_EDGE_FLAG_LEFT, AMOTION_EVENT_EDGE_FLAG_BOTTOM },
- { AMOTION_EVENT_EDGE_FLAG_TOP, AMOTION_EVENT_EDGE_FLAG_LEFT,
- AMOTION_EVENT_EDGE_FLAG_BOTTOM, AMOTION_EVENT_EDGE_FLAG_RIGHT },
- { AMOTION_EVENT_EDGE_FLAG_LEFT, AMOTION_EVENT_EDGE_FLAG_BOTTOM,
- AMOTION_EVENT_EDGE_FLAG_RIGHT, AMOTION_EVENT_EDGE_FLAG_TOP },
-};
-static const size_t edgeFlagRotationMapSize =
- sizeof(edgeFlagRotationMap) / sizeof(edgeFlagRotationMap[0]);
+static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) {
+ float temp;
+ switch (orientation) {
+ case DISPLAY_ORIENTATION_90:
+ temp = *deltaX;
+ *deltaX = *deltaY;
+ *deltaY = -temp;
+ break;
-static int32_t rotateEdgeFlag(int32_t edgeFlag, int32_t orientation) {
- return rotateValueUsingRotationMap(edgeFlag, orientation,
- edgeFlagRotationMap, edgeFlagRotationMapSize);
+ case DISPLAY_ORIENTATION_180:
+ *deltaX = -*deltaX;
+ *deltaY = -*deltaY;
+ break;
+
+ case DISPLAY_ORIENTATION_270:
+ temp = *deltaX;
+ *deltaX = -*deltaY;
+ *deltaY = temp;
+ break;
+ }
}
static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
@@ -181,25 +183,6 @@
| AMOTION_EVENT_BUTTON_TERTIARY);
}
-static int32_t calculateEdgeFlagsUsingPointerBounds(
- const sp<PointerControllerInterface>& pointerController, float x, float y) {
- int32_t edgeFlags = 0;
- float minX, minY, maxX, maxY;
- if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) {
- if (x <= minX) {
- edgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
- } else if (x >= maxX) {
- edgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
- }
- if (y <= minY) {
- edgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
- } else if (y >= maxY) {
- edgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
- }
- }
- return edgeFlags;
-}
-
static float calculateCommonVector(float a, float b) {
if (a > 0 && b > 0) {
return a < b ? a : b;
@@ -1619,7 +1602,6 @@
}
int32_t motionEventAction;
- int32_t motionEventEdgeFlags;
int32_t lastButtonState, currentButtonState;
PointerProperties pointerProperties;
PointerCoords pointerCoords;
@@ -1676,29 +1658,9 @@
orientation = DISPLAY_ORIENTATION_0;
}
- float temp;
- switch (orientation) {
- case DISPLAY_ORIENTATION_90:
- temp = deltaX;
- deltaX = deltaY;
- deltaY = -temp;
- break;
-
- case DISPLAY_ORIENTATION_180:
- deltaX = -deltaX;
- deltaY = -deltaY;
- break;
-
- case DISPLAY_ORIENTATION_270:
- temp = deltaX;
- deltaX = -deltaY;
- deltaY = temp;
- break;
- }
+ rotateDelta(orientation, &deltaX, &deltaY);
}
- motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
-
pointerProperties.clear();
pointerProperties.id = 0;
pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;
@@ -1742,11 +1704,6 @@
mPointerController->getPosition(&x, &y);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-
- if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
- motionEventEdgeFlags = calculateEdgeFlagsUsingPointerBounds(
- mPointerController, x, y);
- }
} else {
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);
@@ -1771,7 +1728,7 @@
// Send motion event.
int32_t metaState = mContext->getGlobalMetaState();
getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags,
- motionEventAction, 0, metaState, currentButtonState, motionEventEdgeFlags,
+ motionEventAction, 0, metaState, currentButtonState, 0,
1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime);
// Send hover move after UP to tell the application that the mouse is hovering now.
@@ -3168,9 +3125,8 @@
}
// Update current touch coordinates.
- int32_t edgeFlags;
float xPrecision, yPrecision;
- prepareTouches(&edgeFlags, &xPrecision, &yPrecision);
+ prepareTouches(&xPrecision, &yPrecision);
// Dispatch motions.
BitSet32 currentIdBits = mCurrentTouch.idBits;
@@ -3239,13 +3195,10 @@
if (dispatchedIdBits.count() == 1) {
// First pointer is going down. Set down time.
mDownTime = when;
- } else {
- // Only send edge flags with first pointer down.
- edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
}
dispatchMotion(when, policyFlags, mTouchSource,
- AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, edgeFlags,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
mCurrentTouchProperties, mCurrentTouchCoords,
mCurrentTouch.idToIndex, dispatchedIdBits, downId,
xPrecision, yPrecision, mDownTime);
@@ -3259,8 +3212,7 @@
}
}
-void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags,
- float* outXPrecision, float* outYPrecision) {
+void TouchInputMapper::prepareTouches(float* outXPrecision, float* outYPrecision) {
uint32_t currentPointerCount = mCurrentTouch.pointerCount;
uint32_t lastPointerCount = mLastTouch.pointerCount;
@@ -3471,28 +3423,6 @@
properties.toolType = getTouchToolType(mCurrentTouch.pointers[i].isStylus);
}
- // Check edge flags by looking only at the first pointer since the flags are
- // global to the event.
- *outEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
- if (lastPointerCount == 0 && currentPointerCount > 0) {
- const PointerData& in = mCurrentTouch.pointers[0];
-
- if (in.x <= mRawAxes.x.minValue) {
- *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT,
- mLocked.surfaceOrientation);
- } else if (in.x >= mRawAxes.x.maxValue) {
- *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT,
- mLocked.surfaceOrientation);
- }
- if (in.y <= mRawAxes.y.minValue) {
- *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP,
- mLocked.surfaceOrientation);
- } else if (in.y >= mRawAxes.y.maxValue) {
- *outEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM,
- mLocked.surfaceOrientation);
- }
- }
-
*outXPrecision = mLocked.orientedXPrecision;
*outYPrecision = mLocked.orientedYPrecision;
}
@@ -3640,19 +3570,12 @@
downGestureIdBits.clearBit(id);
dispatchedGestureIdBits.markBit(id);
- int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE;
if (dispatchedGestureIdBits.count() == 1) {
- // First pointer is going down. Calculate edge flags and set down time.
- uint32_t index = mPointerGesture.currentGestureIdToIndex[id];
- const PointerCoords& downCoords = mPointerGesture.currentGestureCoords[index];
- edgeFlags = calculateEdgeFlagsUsingPointerBounds(mPointerController,
- downCoords.getAxisValue(AMOTION_EVENT_AXIS_X),
- downCoords.getAxisValue(AMOTION_EVENT_AXIS_Y));
mPointerGesture.downTime = when;
}
dispatchMotion(when, policyFlags, mPointerSource,
- AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, edgeFlags,
+ AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
dispatchedGestureIdBits, id,
@@ -3895,6 +3818,7 @@
float deltaY = (currentPointer.y - lastPointer.y)
* mLocked.pointerGestureYMovementScale;
+ rotateDelta(mLocked.surfaceOrientation, &deltaX, &deltaY);
mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY);
// Move the pointer using a relative motion.
@@ -4033,6 +3957,7 @@
float deltaY = (currentPointer.y - lastPointer.y)
* mLocked.pointerGestureYMovementScale;
+ rotateDelta(mLocked.surfaceOrientation, &deltaX, &deltaY);
mPointerGesture.pointerVelocityControl.move(when, &deltaX, &deltaY);
// Move the pointer using a relative motion.
@@ -4290,6 +4215,8 @@
commonDeltaX *= mLocked.pointerGestureXMovementScale;
commonDeltaY *= mLocked.pointerGestureYMovementScale;
+
+ rotateDelta(mLocked.surfaceOrientation, &commonDeltaX, &commonDeltaY);
mPointerGesture.pointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY);
mPointerGesture.referenceGestureX += commonDeltaX;
@@ -4297,32 +4224,11 @@
}
// Report gestures.
- if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) {
- // PRESS mode.
+ if (mPointerGesture.currentGestureMode == PointerGesture::PRESS
+ || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
+ // PRESS or SWIPE mode.
#if DEBUG_GESTURES
- LOGD("Gestures: PRESS activeTouchId=%d,"
- "activeGestureId=%d, currentTouchPointerCount=%d",
- activeTouchId, mPointerGesture.activeGestureId, mCurrentTouch.pointerCount);
-#endif
- LOG_ASSERT(mPointerGesture.activeGestureId >= 0);
-
- mPointerGesture.currentGestureIdBits.clear();
- mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
- mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
- mPointerGesture.currentGestureProperties[0].clear();
- mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
- mPointerGesture.currentGestureProperties[0].toolType =
- AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
- mPointerGesture.currentGestureCoords[0].clear();
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
- mPointerGesture.referenceGestureX);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y,
- mPointerGesture.referenceGestureY);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
- } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) {
- // SWIPE mode.
-#if DEBUG_GESTURES
- LOGD("Gestures: SWIPE activeTouchId=%d,"
+ LOGD("Gestures: PRESS or SWIPE activeTouchId=%d,"
"activeGestureId=%d, currentTouchPointerCount=%d",
activeTouchId, mPointerGesture.activeGestureId, mCurrentTouch.pointerCount);
#endif
@@ -4416,10 +4322,11 @@
mPointerGesture.currentGestureIdBits.markBit(gestureId);
mPointerGesture.currentGestureIdToIndex[gestureId] = i;
- float x = (mCurrentTouch.pointers[i].x - mPointerGesture.referenceTouchX)
- * mLocked.pointerGestureXZoomScale + mPointerGesture.referenceGestureX;
- float y = (mCurrentTouch.pointers[i].y - mPointerGesture.referenceTouchY)
- * mLocked.pointerGestureYZoomScale + mPointerGesture.referenceGestureY;
+ float deltaX = (mCurrentTouch.pointers[i].x - mPointerGesture.referenceTouchX)
+ * mLocked.pointerGestureXZoomScale;
+ float deltaY = (mCurrentTouch.pointers[i].y - mPointerGesture.referenceTouchY)
+ * mLocked.pointerGestureYZoomScale;
+ rotateDelta(mLocked.surfaceOrientation, &deltaX, &deltaY);
mPointerGesture.currentGestureProperties[i].clear();
mPointerGesture.currentGestureProperties[i].id = gestureId;
@@ -4427,9 +4334,9 @@
AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
mPointerGesture.currentGestureCoords[i].clear();
mPointerGesture.currentGestureCoords[i].setAxisValue(
- AMOTION_EVENT_AXIS_X, x);
+ AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX);
mPointerGesture.currentGestureCoords[i].setAxisValue(
- AMOTION_EVENT_AXIS_Y, y);
+ AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY);
mPointerGesture.currentGestureCoords[i].setAxisValue(
AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
}
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index 69fa6b4..b1fdcf2 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -1176,7 +1176,7 @@
TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
void dispatchTouches(nsecs_t when, uint32_t policyFlags);
- void prepareTouches(int32_t* outEdgeFlags, float* outXPrecision, float* outYPrecision);
+ void prepareTouches(float* outXPrecision, float* outYPrecision);
void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout);
bool preparePointerGestures(nsecs_t when,
bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout);
diff --git a/services/input/InputWindow.cpp b/services/input/InputWindow.cpp
index b552f6d..0ce8867 100644
--- a/services/input/InputWindow.cpp
+++ b/services/input/InputWindow.cpp
@@ -22,25 +22,25 @@
namespace android {
-// --- InputWindow ---
+// --- InputWindowHandle ---
-bool InputWindow::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowHandle::touchableRegionContainsPoint(int32_t x, int32_t y) const {
return touchableRegion.contains(x, y);
}
-bool InputWindow::frameContainsPoint(int32_t x, int32_t y) const {
+bool InputWindowHandle::frameContainsPoint(int32_t x, int32_t y) const {
return x >= frameLeft && x <= frameRight
&& y >= frameTop && y <= frameBottom;
}
-bool InputWindow::isTrustedOverlay() const {
+bool InputWindowHandle::isTrustedOverlay() const {
return layoutParamsType == TYPE_INPUT_METHOD
|| layoutParamsType == TYPE_INPUT_METHOD_DIALOG
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY;
}
-bool InputWindow::supportsSplitTouch() const {
- return layoutParamsFlags & InputWindow::FLAG_SPLIT_TOUCH;
+bool InputWindowHandle::supportsSplitTouch() const {
+ return layoutParamsFlags & FLAG_SPLIT_TOUCH;
}
} // namespace android
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index d166ad4..272081c 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -31,29 +31,14 @@
/*
* A handle to a window that can receive input.
+ *
* Used by the native input dispatcher to indirectly refer to the window manager objects
* that describe a window.
*/
class InputWindowHandle : public RefBase {
-protected:
- InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- mInputApplicationHandle(inputApplicationHandle) { }
- virtual ~InputWindowHandle() { }
-
public:
- inline sp<InputApplicationHandle> getInputApplicationHandle() {
- return mInputApplicationHandle;
- }
+ const sp<InputApplicationHandle> inputApplicationHandle;
-private:
- sp<InputApplicationHandle> mInputApplicationHandle;
-};
-
-
-/*
- * An input window describes the bounds of a window that can receive input.
- */
-struct InputWindow {
// Window flags from WindowManager.LayoutParams
enum {
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
@@ -164,6 +149,22 @@
bool isTrustedOverlay() const;
bool supportsSplitTouch() const;
+
+ /**
+ * Requests that the state of this object be updated to reflect
+ * the most current available information about the application.
+ *
+ * This method should only be called from within the input dispatcher's
+ * critical section.
+ *
+ * Returns true on success, or false if the handle is no longer valid.
+ */
+ virtual bool update() = 0;
+
+protected:
+ InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+ inputApplicationHandle(inputApplicationHandle) { }
+ virtual ~InputWindowHandle() { }
};
} // namespace android
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
index cabbccb..d92fc74 100644
--- a/services/input/tests/Android.mk
+++ b/services/input/tests/Android.mk
@@ -2,8 +2,6 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-ifneq ($(TARGET_SIMULATOR),true)
-
# Build the unit tests.
test_src_files := \
InputReader_test.cpp \
@@ -45,5 +43,3 @@
# Build the manual test programs.
include $(call all-subdir-makefiles)
-
-endif
\ No newline at end of file
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 67067de..131894a 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -369,11 +369,12 @@
return INPUT_EVENT_INJECTION_FAILED;
}
- virtual void setInputWindows(const Vector<InputWindow>& inputWindows) {
+ virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
ADD_FAILURE() << "Should never be called by input reader.";
}
- virtual void setFocusedApplication(const InputApplication* inputApplication) {
+ virtual void setFocusedApplication(
+ const sp<InputApplicationHandle>& inputApplicationHandle) {
ADD_FAILURE() << "Should never be called by input reader.";
}
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 158c778..0b15221 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -1072,7 +1072,7 @@
throw new IllegalArgumentException("packageName and uid don't match packageName="
+ packageName);
}
- if (callingUid != packageUid && Process.supportsProcesses()) {
+ if (callingUid != packageUid) {
throw new IllegalArgumentException("packageName and uid don't match packageName="
+ packageName);
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 786f2fa..e9e66cb 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -76,6 +76,7 @@
import com.android.internal.backup.LocalTransport;
import com.android.server.PackageManagerBackupAgent.Metadata;
+import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileDescriptor;
@@ -86,8 +87,10 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -96,6 +99,10 @@
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
class BackupManagerService extends IBackupManager.Stub {
private static final String TAG = "BackupManagerService";
@@ -104,6 +111,8 @@
// Name and current contents version of the full-backup manifest file
static final String BACKUP_MANIFEST_FILENAME = "_manifest";
static final int BACKUP_MANIFEST_VERSION = 1;
+ static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
+ static final int BACKUP_FILE_VERSION = 1;
// How often we perform a backup pass. Privileged external callers can
// trigger an immediate pass.
@@ -1679,6 +1688,7 @@
class PerformFullBackupTask implements Runnable {
ParcelFileDescriptor mOutputFile;
+ DeflaterOutputStream mDeflater;
IFullBackupRestoreObserver mObserver;
boolean mIncludeApks;
boolean mIncludeShared;
@@ -1688,6 +1698,55 @@
File mFilesDir;
File mManifestFile;
+ class FullBackupRunner implements Runnable {
+ PackageInfo mPackage;
+ IBackupAgent mAgent;
+ ParcelFileDescriptor mPipe;
+ int mToken;
+ boolean mSendApk;
+
+ FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
+ int token, boolean sendApk) throws IOException {
+ mPackage = pack;
+ mAgent = agent;
+ mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
+ mToken = token;
+ mSendApk = sendApk;
+ }
+
+ @Override
+ public void run() {
+ try {
+ BackupDataOutput output = new BackupDataOutput(
+ mPipe.getFileDescriptor());
+
+ if (DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
+ writeAppManifest(mPackage, mManifestFile, mSendApk);
+ FullBackup.backupToTar(mPackage.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+
+ if (mSendApk) {
+ writeApkToBackup(mPackage, output);
+ }
+
+ if (DEBUG) Slog.d(TAG, "Calling doFullBackup()");
+ prepareOperationTimeout(mToken, TIMEOUT_FULL_BACKUP_INTERVAL);
+ mAgent.doFullBackup(mPipe, mToken, mBackupManagerBinder);
+ } catch (IOException e) {
+ Slog.e(TAG, "Error running full backup for " + mPackage.packageName);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote agent vanished during full backup of "
+ + mPackage.packageName);
+ } finally {
+ try {
+ mPipe.close();
+ } catch (IOException e) {}
+ }
+ }
+ }
+
PerformFullBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
boolean includeApks, boolean includeShared,
boolean doAllApps, String[] packages, AtomicBoolean latch) {
@@ -1736,13 +1795,47 @@
}
}
+ FileOutputStream ofstream = new FileOutputStream(mOutputFile.getFileDescriptor());
+
+ // Set up the compression stage
+ Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);
+ DeflaterOutputStream out = new DeflaterOutputStream(ofstream, deflater, true);
+
PackageInfo pkg = null;
try {
+
+ // !!! TODO: if using encryption, set up the encryption stage
+ // and emit the tar header stating the password salt.
+
+ // Write the global file header. All strings are UTF-8 encoded; lines end
+ // with a '\n' byte. Actual backup data begins immediately following the
+ // final '\n'.
+ //
+ // line 1: "ANDROID BACKUP"
+ // line 2: backup file format version, currently "1"
+ // line 3: compressed? "0" if not compressed, "1" if compressed.
+ // line 4: encryption salt? "-" if not encrypted, otherwise this
+ // line contains the encryption salt with which the user-
+ // supplied password is to be expanded, in hexadecimal.
+ StringBuffer headerbuf = new StringBuffer(256);
+ // !!! TODO: programmatically build the compressed / encryption salt fields
+ headerbuf.append(BACKUP_FILE_HEADER_MAGIC);
+ headerbuf.append("1\n1\n-\n");
+
+ try {
+ byte[] header = headerbuf.toString().getBytes("UTF-8");
+ ofstream.write(header);
+ } catch (Exception e) {
+ // Should never happen!
+ Slog.e(TAG, "Unable to emit archive header", e);
+ return;
+ }
+
// Now back up the app data via the agent mechanism
int N = packagesToBackup.size();
for (int i = 0; i < N; i++) {
pkg = packagesToBackup.get(i);
- backupOnePackage(pkg);
+ backupOnePackage(pkg, out);
}
// Finally, shared storage if requested
@@ -1754,6 +1847,7 @@
} finally {
tearDown(pkg);
try {
+ out.close();
mOutputFile.close();
} catch (IOException e) {
/* nothing we can do about this */
@@ -1771,13 +1865,17 @@
}
}
- private void backupOnePackage(PackageInfo pkg) throws RemoteException {
+ private void backupOnePackage(PackageInfo pkg, DeflaterOutputStream out)
+ throws RemoteException {
Slog.d(TAG, "Binding to full backup agent : " + pkg.packageName);
IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
IApplicationThread.BACKUP_MODE_FULL);
if (agent != null) {
+ ParcelFileDescriptor[] pipes = null;
try {
+ pipes = ParcelFileDescriptor.createPipe();
+
ApplicationInfo app = pkg.applicationInfo;
final boolean sendApk = mIncludeApks
&& ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
@@ -1786,31 +1884,54 @@
sendOnBackupPackage(pkg.packageName);
- BackupDataOutput output = new BackupDataOutput(
- mOutputFile.getFileDescriptor());
+ final int token = generateToken();
+ FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
+ token, sendApk);
+ pipes[1].close(); // the runner has dup'd it
+ pipes[1] = null;
+ Thread t = new Thread(runner);
+ t.start();
- if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
- writeAppManifest(pkg, mManifestFile, sendApk);
- FullBackup.backupToTar(pkg.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+ // Now pull data from the app and stuff it into the compressor
+ try {
+ FileInputStream raw = new FileInputStream(pipes[0].getFileDescriptor());
+ DataInputStream in = new DataInputStream(raw);
- if (sendApk) {
- writeApkToBackup(pkg, output);
+ byte[] buffer = new byte[16 * 1024];
+ int chunkTotal;
+ while ((chunkTotal = in.readInt()) > 0) {
+ while (chunkTotal > 0) {
+ int toRead = (chunkTotal > buffer.length)
+ ? buffer.length : chunkTotal;
+ int nRead = in.read(buffer, 0, toRead);
+ out.write(buffer, 0, nRead);
+ chunkTotal -= nRead;
+ }
+ }
+ } catch (IOException e) {
+ Slog.i(TAG, "Caught exception reading from agent", e);
}
- if (DEBUG) Slog.d(TAG, "Calling doFullBackup()");
- final int token = generateToken();
- prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
- agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
} else {
- if (DEBUG) Slog.d(TAG, "Full backup success: " + pkg.packageName);
+ if (DEBUG) Slog.d(TAG, "Full package backup success: " + pkg.packageName);
}
+
} catch (IOException e) {
Slog.e(TAG, "Error backing up " + pkg.packageName, e);
+ } finally {
+ try {
+ if (pipes != null) {
+ if (pipes[0] != null) pipes[0].close();
+ if (pipes[1] != null) pipes[1].close();
+ }
+
+ // Apply a full sync/flush after each application's data
+ out.flush();
+ } catch (IOException e) {
+ Slog.w(TAG, "Error bringing down backup stack");
+ }
}
} else {
Slog.w(TAG, "Unable to bind to full agent for " + pkg.packageName);
@@ -2084,14 +2205,56 @@
try {
mBytes = 0;
byte[] buffer = new byte[32 * 1024];
- FileInputStream instream = new FileInputStream(mInputFile.getFileDescriptor());
+ FileInputStream rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
+
+ // First, parse out the unencrypted/uncompressed header
+ boolean compressed = false;
+ boolean encrypted = false;
+ final InputStream in;
+
+ boolean okay = false;
+ final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();
+ byte[] streamHeader = new byte[headerLen];
+ try {
+ int got;
+ if ((got = rawInStream.read(streamHeader, 0, headerLen)) == headerLen) {
+ byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes("UTF-8");
+ if (Arrays.equals(magicBytes, streamHeader)) {
+ // okay, header looks good. now parse out the rest of the fields.
+ String s = readHeaderLine(rawInStream);
+ if (Integer.parseInt(s) == BACKUP_FILE_VERSION) {
+ // okay, it's a version we recognize
+ s = readHeaderLine(rawInStream);
+ compressed = (Integer.parseInt(s) != 0);
+ s = readHeaderLine(rawInStream);
+ if (!s.startsWith("-")) {
+ encrypted = true;
+ // TODO: parse out the salt here and process with the user pw
+ }
+ okay = true;
+ } else Slog.e(TAG, "Wrong header version: " + s);
+ } else Slog.e(TAG, "Didn't read the right header magic");
+ } else Slog.e(TAG, "Only read " + got + " bytes of header");
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Can't parse restore data header");
+ }
+
+ if (!okay) {
+ Slog.e(TAG, "Invalid restore data; aborting.");
+ return;
+ }
+
+ // okay, use the right stream layer based on compression
+ in = (compressed) ? new InflaterInputStream(rawInStream) : rawInStream;
boolean didRestore;
do {
- didRestore = restoreOneFile(instream, buffer);
+ didRestore = restoreOneFile(in, buffer);
} while (didRestore);
if (DEBUG) Slog.v(TAG, "Done consuming input tarfile, total bytes=" + mBytes);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read restore input");
} finally {
tearDownPipes();
tearDownAgent(mTargetApp);
@@ -2115,6 +2278,16 @@
}
}
+ String readHeaderLine(InputStream in) throws IOException {
+ int c;
+ StringBuffer buffer = new StringBuffer(80);
+ while ((c = in.read()) >= 0) {
+ if (c == '\n') break; // consume and discard the newlines
+ buffer.append((char)c);
+ }
+ return buffer.toString();
+ }
+
boolean restoreOneFile(InputStream instream, byte[] buffer) {
FileMetadata info;
try {
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index b9ff8d0..6665614 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -17,7 +17,6 @@
package com.android.server;
import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -28,7 +27,6 @@
import android.os.FileUtils;
import android.os.RecoverySystem;
import android.os.SystemProperties;
-import android.provider.Settings;
import android.util.Slog;
import java.io.File;
@@ -59,17 +57,6 @@
@Override
public void onReceive(final Context context, Intent intent) {
- try {
- // Start the load average overlay, if activated
- ContentResolver res = context.getContentResolver();
- if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
- Intent loadavg = new Intent(context, com.android.server.LoadAverageService.class);
- context.startService(loadavg);
- }
- } catch (Exception e) {
- Slog.e(TAG, "Can't start load average service", e);
- }
-
// Log boot events in the background to avoid blocking the main thread with I/O
new Thread() {
@Override
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 41450d2..55c92e8 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -33,7 +33,9 @@
import android.net.IConnectivityManager;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.LinkProperties.CompareResult;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
@@ -76,6 +78,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
@@ -92,6 +96,7 @@
public class ConnectivityService extends IConnectivityManager.Stub {
private static final boolean DBG = true;
+ private static final boolean VDBG = true;
private static final String TAG = "ConnectivityService";
private static final boolean LOGD_RULES = false;
@@ -126,6 +131,11 @@
private NetworkStateTracker mNetTrackers[];
/**
+ * The link properties that define the current links
+ */
+ private LinkProperties mCurrentLinkProperties[];
+
+ /**
* A per Net list of the PID's that requested access to the net
* used both as a refcount and for per-PID DNS selection
*/
@@ -250,6 +260,10 @@
private InetAddress mDefaultDns;
+ // this collection is used to refcount the added routes - if there are none left
+ // it's time to remove the route from the route table
+ private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
+
// used in DBG mode to track inet condition reports
private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
private ArrayList mInetLog;
@@ -332,6 +346,7 @@
mNetTrackers = new NetworkStateTracker[
ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
mNetworkPreference = getPersistedNetworkPreference();
@@ -468,6 +483,7 @@
mNetConfigs[netType].radio);
continue;
}
+ mCurrentLinkProperties[netType] = null;
}
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1041,62 +1057,71 @@
}
try {
InetAddress addr = InetAddress.getByAddress(hostAddress);
- return addHostRoute(tracker, addr, 0);
+ LinkProperties lp = tracker.getLinkProperties();
+ return addRoute(lp, RouteInfo.makeHostRoute(addr));
} catch (UnknownHostException e) {}
return false;
}
- /**
- * Ensure that a network route exists to deliver traffic to the specified
- * host via the mobile data network.
- * @param hostAddress the IP address of the host to which the route is desired,
- * in network byte order.
- * TODO - deprecate
- * @return {@code true} on success, {@code false} on failure
- */
- private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress, int cycleCount) {
- LinkProperties lp = nt.getLinkProperties();
- if ((lp == null) || (hostAddress == null)) return false;
-
- String interfaceName = lp.getInterfaceName();
- if (DBG) {
- log("Requested host route to " + hostAddress + "(" + interfaceName + "), cycleCount=" +
- cycleCount);
- }
- if (interfaceName == null) {
- if (DBG) loge("addHostRoute failed due to null interface name");
- return false;
- }
-
- RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), hostAddress);
- InetAddress gatewayAddress = null;
- if (bestRoute != null) {
- gatewayAddress = bestRoute.getGateway();
- // if the best route is ourself, don't relf-reference, just add the host route
- if (hostAddress.equals(gatewayAddress)) gatewayAddress = null;
- }
- if (gatewayAddress != null) {
- if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
- loge("Error adding hostroute - too much recursion");
- return false;
- }
- if (!addHostRoute(nt, gatewayAddress, cycleCount+1)) return false;
- }
-
- RouteInfo route = RouteInfo.makeHostRoute(hostAddress, gatewayAddress);
-
- try {
- mNetd.addRoute(interfaceName, route);
- return true;
- } catch (Exception ex) {
- return false;
- }
+ private boolean addRoute(LinkProperties p, RouteInfo r) {
+ return modifyRoute(p.getInterfaceName(), p, r, 0, true);
}
- // TODO support the removal of single host routes. Keep a ref count of them so we
- // aren't over-zealous
- private boolean removeHostRoute(NetworkStateTracker nt, InetAddress hostAddress) {
- return false;
+ private boolean removeRoute(LinkProperties p, RouteInfo r) {
+ return modifyRoute(p.getInterfaceName(), p, r, 0, false);
+ }
+
+ private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
+ boolean doAdd) {
+ if ((ifaceName == null) || (lp == null) || (r == null)) return false;
+
+ if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
+ loge("Error adding route - too much recursion");
+ return false;
+ }
+
+ if (r.isHostRoute() == false) {
+ RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway());
+ if (bestRoute != null) {
+ if (bestRoute.getGateway().equals(r.getGateway())) {
+ // if there is no better route, add the implied hostroute for our gateway
+ bestRoute = RouteInfo.makeHostRoute(r.getGateway());
+ } else {
+ // if we will connect to our gateway through another route, add a direct
+ // route to it's gateway
+ bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
+ }
+ modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd);
+ }
+ }
+ if (doAdd) {
+ if (DBG) log("Adding " + r + " for interface " + ifaceName);
+ mAddedRoutes.add(r);
+ try {
+ mNetd.addRoute(ifaceName, r);
+ } catch (Exception e) {
+ // never crash - catch them all
+ loge("Exception trying to add a route: " + e);
+ return false;
+ }
+ } else {
+ // if we remove this one and there are no more like it, then refcount==0 and
+ // we can remove it from the table
+ mAddedRoutes.remove(r);
+ if (mAddedRoutes.contains(r) == false) {
+ if (DBG) log("Removing " + r + " for interface " + ifaceName);
+ try {
+ mNetd.removeRoute(ifaceName, r);
+ } catch (Exception e) {
+ // never crash - catch them all
+ loge("Exception trying to remove a route: " + e);
+ return false;
+ }
+ } else {
+ if (DBG) log("not removing " + r + " as it's still in use");
+ }
+ }
+ return true;
}
/**
@@ -1145,9 +1170,6 @@
public void setDataDependency(int networkType, boolean met) {
enforceConnectivityInternalPermission();
- if (DBG) {
- log("setDataDependency(" + networkType + ", " + met + ")");
- }
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET,
(met ? ENABLED : DISABLED), networkType));
}
@@ -1563,49 +1585,78 @@
* right routing table entries exist.
*/
private void handleConnectivityChange(int netType, boolean doReset) {
+ int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+
/*
* If a non-default network is enabled, add the host routes that
* will allow it's DNS servers to be accessed.
*/
handleDnsConfigurationChange(netType);
+ LinkProperties curLp = mCurrentLinkProperties[netType];
+ LinkProperties newLp = null;
+
if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
+ newLp = mNetTrackers[netType].getLinkProperties();
+ if (VDBG) {
+ log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
+ " doReset=" + doReset + " resetMask=" + resetMask +
+ "\n curLp=" + curLp +
+ "\n newLp=" + newLp);
+ }
+
+ if (curLp != null) {
+ if (curLp.isIdenticalInterfaceName(newLp)) {
+ CompareResult<LinkAddress> car = curLp.compareAddresses(newLp);
+ if ((car.removed.size() != 0) || (car.added.size() != 0)) {
+ for (LinkAddress linkAddr : car.removed) {
+ if (linkAddr.getAddress() instanceof Inet4Address) {
+ resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES;
+ }
+ if (linkAddr.getAddress() instanceof Inet6Address) {
+ resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES;
+ }
+ }
+ if (DBG) {
+ log("handleConnectivityChange: addresses changed" +
+ " linkProperty[" + netType + "]:" + " resetMask=" + resetMask +
+ "\n car=" + car);
+ }
+ } else {
+ if (DBG) {
+ log("handleConnectivityChange: address are the same reset per doReset" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
+ }
+ }
+ } else {
+ resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
+ log("handleConnectivityChange: interface not not equivalent reset both" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
+ }
+ }
if (mNetConfigs[netType].isDefault()) {
handleApplyDefaultProxy(netType);
- addDefaultRoute(mNetTrackers[netType]);
- } else {
- // many radios add a default route even when we don't want one.
- // remove the default route unless we need it for our active network
- if (mActiveDefaultNetwork != -1) {
- LinkProperties defaultLinkProperties =
- mNetTrackers[mActiveDefaultNetwork].getLinkProperties();
- LinkProperties newLinkProperties =
- mNetTrackers[netType].getLinkProperties();
- String defaultIface = defaultLinkProperties.getInterfaceName();
- if (defaultIface != null &&
- !defaultIface.equals(newLinkProperties.getInterfaceName())) {
- removeDefaultRoute(mNetTrackers[netType]);
- }
- }
- addPrivateDnsRoutes(mNetTrackers[netType]);
}
} else {
- if (mNetConfigs[netType].isDefault()) {
- removeDefaultRoute(mNetTrackers[netType]);
- } else {
- removePrivateDnsRoutes(mNetTrackers[netType]);
+ if (VDBG) {
+ log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
+ " doReset=" + doReset + " resetMask=" + resetMask +
+ "\n curLp=" + curLp +
+ "\n newLp= null");
}
}
+ mCurrentLinkProperties[netType] = newLp;
+ updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
- if (doReset) {
+ if (doReset || resetMask != 0) {
LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
if (linkProperties != null) {
String iface = linkProperties.getInterfaceName();
if (TextUtils.isEmpty(iface) == false) {
- if (DBG) {
- log("resetConnections(" + iface + ", NetworkUtils.RESET_ALL_ADDRESSES)");
- }
- NetworkUtils.resetConnections(iface, NetworkUtils.RESET_ALL_ADDRESSES);
+ if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
+ NetworkUtils.resetConnections(iface, resetMask);
}
}
}
@@ -1621,108 +1672,64 @@
}
}
- private void addPrivateDnsRoutes(NetworkStateTracker nt) {
- boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
- LinkProperties p = nt.getLinkProperties();
- if (p == null) return;
- String interfaceName = p.getInterfaceName();
+ /**
+ * Add and remove routes using the old properties (null if not previously connected),
+ * new properties (null if becoming disconnected). May even be double null, which
+ * is a noop.
+ * Uses isLinkDefault to determine if default routes should be set or conversely if
+ * host routes should be set to the dns servers
+ */
+ private void updateRoutes(LinkProperties newLp, LinkProperties curLp, boolean isLinkDefault) {
+ Collection<RouteInfo> routesToAdd = null;
+ CompareResult<InetAddress> dnsDiff = null;
- if (DBG) {
- log("addPrivateDnsRoutes for " + nt +
- "(" + interfaceName + ") - mPrivateDnsRouteSet = " + privateDnsRouteSet);
- }
- if (interfaceName != null && !privateDnsRouteSet) {
- Collection<InetAddress> dnsList = p.getDnses();
- for (InetAddress dns : dnsList) {
- addHostRoute(nt, dns, 0);
- }
- nt.privateDnsRouteSet(true);
- }
- }
+ if (curLp != null) {
+ // check for the delta between the current set and the new
+ CompareResult<RouteInfo> routeDiff = curLp.compareRoutes(newLp);
+ dnsDiff = curLp.compareDnses(newLp);
- private void removePrivateDnsRoutes(NetworkStateTracker nt) {
- LinkProperties p = nt.getLinkProperties();
- if (p == null) return;
- String interfaceName = p.getInterfaceName();
- boolean privateDnsRouteSet = nt.isPrivateDnsRouteSet();
- if (interfaceName != null && privateDnsRouteSet) {
- if (DBG) {
- log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
- " (" + interfaceName + ")");
- }
-
- Collection<InetAddress> dnsList = p.getDnses();
- for (InetAddress dns : dnsList) {
- if (DBG) log(" removing " + dns);
- RouteInfo route = RouteInfo.makeHostRoute(dns);
- try {
- mNetd.removeRoute(interfaceName, route);
- } catch (Exception ex) {
- loge("error (" + ex + ") removing dns route " + route);
+ for (RouteInfo r : routeDiff.removed) {
+ if (isLinkDefault || ! r.isDefaultRoute()) {
+ removeRoute(curLp, r);
}
}
- nt.privateDnsRouteSet(false);
+ routesToAdd = routeDiff.added;
}
- }
+ if (newLp != null) {
+ // if we didn't get a diff from cur -> new, then just use the new
+ if (routesToAdd == null) {
+ routesToAdd = newLp.getRoutes();
+ }
- private void addDefaultRoute(NetworkStateTracker nt) {
- LinkProperties p = nt.getLinkProperties();
- if (p == null) return;
- String interfaceName = p.getInterfaceName();
- if (TextUtils.isEmpty(interfaceName)) return;
+ for (RouteInfo r : routesToAdd) {
+ if (isLinkDefault || ! r.isDefaultRoute()) {
+ addRoute(newLp, r);
+ }
+ }
+ }
- for (RouteInfo route : p.getRoutes()) {
- //TODO - handle non-default routes
- if (route.isDefaultRoute()) {
- if (DBG) log("adding default route " + route);
- InetAddress gateway = route.getGateway();
- if (addHostRoute(nt, gateway, 0)) {
- try {
- mNetd.addRoute(interfaceName, route);
- } catch (Exception e) {
- loge("error adding default route " + route);
- continue;
- }
- if (DBG) {
- NetworkInfo networkInfo = nt.getNetworkInfo();
- log("addDefaultRoute for " + networkInfo.getTypeName() +
- " (" + interfaceName + "), GatewayAddr=" +
- gateway.getHostAddress());
- }
- } else {
- loge("error adding host route for default route " + route);
+ if (!isLinkDefault) {
+ // handle DNS routes
+ Collection<InetAddress> dnsToAdd = null;
+ if (dnsDiff != null) {
+ dnsToAdd = dnsDiff.added;
+ for (InetAddress dnsAddress : dnsDiff.removed) {
+ removeRoute(curLp, RouteInfo.makeHostRoute(dnsAddress));
+ }
+ }
+ if (newLp != null) {
+ if (dnsToAdd == null) {
+ dnsToAdd = newLp.getDnses();
+ }
+ for(InetAddress dnsAddress : dnsToAdd) {
+ addRoute(newLp, RouteInfo.makeHostRoute(dnsAddress));
}
}
}
}
- public void removeDefaultRoute(NetworkStateTracker nt) {
- LinkProperties p = nt.getLinkProperties();
- if (p == null) return;
- String interfaceName = p.getInterfaceName();
-
- if (interfaceName == null) return;
-
- for (RouteInfo route : p.getRoutes()) {
- //TODO - handle non-default routes
- if (route.isDefaultRoute()) {
- try {
- mNetd.removeRoute(interfaceName, route);
- } catch (Exception ex) {
- loge("error (" + ex + ") removing default route " + route);
- continue;
- }
- if (DBG) {
- NetworkInfo networkInfo = nt.getNetworkInfo();
- log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
- interfaceName + ")");
- }
- }
- }
- }
-
/**
* Reads the network specific TCP buffer sizes from SystemProperties
* net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
@@ -2477,8 +2484,23 @@
* @hide
*/
@Override
- public void protectVpn(ParcelFileDescriptor socket) {
- mVpn.protect(socket, getDefaultInterface());
+ public boolean protectVpn(ParcelFileDescriptor socket) {
+ try {
+ int type = mActiveDefaultNetwork;
+ if (ConnectivityManager.isNetworkTypeValid(type)) {
+ mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName());
+ return true;
+ }
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ try {
+ socket.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ return false;
}
/**
@@ -2526,19 +2548,6 @@
return mVpn.getLegacyVpnInfo();
}
- private String getDefaultInterface() {
- if (ConnectivityManager.isNetworkTypeValid(mActiveDefaultNetwork)) {
- NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork];
- if (tracker != null) {
- LinkProperties properties = tracker.getLinkProperties();
- if (properties != null) {
- return properties.getInterfaceName();
- }
- }
- }
- throw new IllegalStateException("No default interface");
- }
-
/**
* Callback for VPN subsystem. Currently VPN is not adapted to the service
* through NetworkStateTracker since it works differently. For example, it
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 2d55433..18d393f 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -531,10 +531,7 @@
mImeSwitcherNotification.sound = null;
mImeSwitcherNotification.vibrate = null;
Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mImeSwitchPendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
+ mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
com.android.internal.R.bool.show_ongoing_ime_switcher);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 2e54c99..7f61c635 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1339,7 +1339,11 @@
String state = mVolumeStates.get(mountPoint);
if (state == null) {
Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
- throw new IllegalArgumentException();
+ if (SystemProperties.get("vold.encrypt_progress").length() != 0) {
+ state = Environment.MEDIA_REMOVED;
+ } else {
+ throw new IllegalArgumentException();
+ }
}
return state;
@@ -2361,6 +2365,19 @@
pw.print(" -> "); pw.println(e.getValue().toString());
}
}
+
+ pw.println("");
+
+ synchronized (mVolumes) {
+ pw.println(" mVolumes:");
+
+ final int N = mVolumes.size();
+ for (int i = 0; i < N; i++) {
+ final StorageVolume v = mVolumes.get(i);
+ pw.print(" ");
+ pw.println(v.toString());
+ }
+ }
}
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index da1bf83..41e8a31 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -77,11 +77,15 @@
/** Path to {@code /proc/uid_stat}. */
@Deprecated
- private final File mProcStatsUidstat;
+ private final File mStatsUid;
+ /** Path to {@code /proc/net/dev}. */
+ private final File mStatsIface;
/** Path to {@code /proc/net/xt_qtaguid/stats}. */
- private final File mProcStatsNetfilter;
+ private final File mStatsXtUid;
+ /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
+ private final File mStatsXtIface;
- /** {@link #mProcStatsNetfilter} headers. */
+ /** {@link #mStatsXtUid} headers. */
private static final String KEY_IFACE = "iface";
private static final String KEY_TAG_HEX = "acct_tag_hex";
private static final String KEY_UID = "uid_tag_int";
@@ -137,8 +141,10 @@
mContext = context;
mObservers = new ArrayList<INetworkManagementEventObserver>();
- mProcStatsUidstat = new File(procRoot, "uid_stat");
- mProcStatsNetfilter = new File(procRoot, "net/xt_qtaguid/stats");
+ mStatsUid = new File(procRoot, "uid_stat");
+ mStatsIface = new File(procRoot, "net/dev");
+ mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
+ mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
return;
@@ -161,9 +167,12 @@
}
// @VisibleForTesting
- public static NetworkManagementService createForTest(Context context, File procRoot) {
+ public static NetworkManagementService createForTest(
+ Context context, File procRoot, boolean bandwidthControlEnabled) {
// TODO: eventually connect with mock netd
- return new NetworkManagementService(context, procRoot);
+ final NetworkManagementService service = new NetworkManagementService(context, procRoot);
+ service.mBandwidthControlEnabled = bandwidthControlEnabled;
+ return service;
}
public void systemReady() {
@@ -187,6 +196,9 @@
} else {
Slog.d(TAG, "not enabling bandwidth control");
}
+
+ SystemProperties.set(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED,
+ mBandwidthControlEnabled ? "1" : "0");
}
public void registerObserver(INetworkManagementEventObserver obs) {
@@ -930,13 +942,68 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- final String[] ifaces = listInterfaces();
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
- for (String iface : ifaces) {
- final long rx = getInterfaceCounter(iface, true);
- final long tx = getInterfaceCounter(iface, false);
- stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx);
+ final HashSet<String> activeIfaces = Sets.newHashSet();
+ final ArrayList<String> values = Lists.newArrayList();
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(mStatsIface));
+
+ // skip first two header lines
+ reader.readLine();
+ reader.readLine();
+
+ // parse remaining lines
+ String line;
+ while ((line = reader.readLine()) != null) {
+ splitLine(line, values);
+
+ try {
+ entry.iface = values.get(0);
+ entry.uid = UID_ALL;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = Long.parseLong(values.get(1));
+ entry.rxPackets = Long.parseLong(values.get(2));
+ entry.txBytes = Long.parseLong(values.get(9));
+ entry.txPackets = Long.parseLong(values.get(10));
+
+ activeIfaces.add(entry.iface);
+ stats.addValues(entry);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
+ }
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "problem parsing stats: " + e);
+ } finally {
+ IoUtils.closeQuietly(reader);
+ }
+
+ if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);
+
+ // splice in stats from any disabled ifaces
+ if (mBandwidthControlEnabled) {
+ final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
+ xtIfaces.removeAll(activeIfaces);
+
+ for (String iface : xtIfaces) {
+ final File ifacePath = new File(mStatsXtIface, iface);
+
+ entry.iface = iface;
+ entry.uid = UID_ALL;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
+ entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
+ entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
+ entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
+
+ stats.addValues(entry);
+ }
+
+ if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
}
return stats;
@@ -1063,13 +1130,15 @@
*/
private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+
final ArrayList<String> keys = Lists.newArrayList();
final ArrayList<String> values = Lists.newArrayList();
final HashMap<String, String> parsed = Maps.newHashMap();
BufferedReader reader = null;
try {
- reader = new BufferedReader(new FileReader(mProcStatsNetfilter));
+ reader = new BufferedReader(new FileReader(mStatsXtUid));
// parse first line as header
String line = reader.readLine();
@@ -1081,15 +1150,16 @@
parseLine(keys, values, parsed);
try {
- final String iface = parsed.get(KEY_IFACE);
- final int tag = NetworkManagementSocketTagger.kernelToTag(
+ // TODO: add rxPackets/txPackets once kernel exports
+ entry.iface = parsed.get(KEY_IFACE);
+ entry.tag = NetworkManagementSocketTagger.kernelToTag(
parsed.get(KEY_TAG_HEX));
- final int uid = Integer.parseInt(parsed.get(KEY_UID));
- final long rx = Long.parseLong(parsed.get(KEY_RX));
- final long tx = Long.parseLong(parsed.get(KEY_TX));
+ entry.uid = Integer.parseInt(parsed.get(KEY_UID));
+ entry.rxBytes = Long.parseLong(parsed.get(KEY_RX));
+ entry.txBytes = Long.parseLong(parsed.get(KEY_TX));
- if (limitUid == UID_ALL || limitUid == uid) {
- stats.addEntry(iface, uid, tag, rx, tx);
+ if (limitUid == UID_ALL || limitUid == entry.uid) {
+ stats.addValues(entry);
}
} catch (NumberFormatException e) {
Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
@@ -1114,19 +1184,27 @@
private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
final String[] knownUids;
if (limitUid == UID_ALL) {
- knownUids = mProcStatsUidstat.list();
+ knownUids = fileListWithoutNull(mStatsUid);
} else {
knownUids = new String[] { String.valueOf(limitUid) };
}
final NetworkStats stats = new NetworkStats(
SystemClock.elapsedRealtime(), knownUids.length);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
for (String uid : knownUids) {
final int uidInt = Integer.parseInt(uid);
- final File uidPath = new File(mProcStatsUidstat, uid);
- final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
- final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
- stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
+ final File uidPath = new File(mStatsUid, uid);
+
+ entry.iface = IFACE_ALL;
+ entry.uid = uidInt;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
+ entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
+ entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
+ entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
+
+ stats.addValues(entry);
}
return stats;
@@ -1197,7 +1275,7 @@
private static void splitLine(String line, ArrayList<String> outSplit) {
outSplit.clear();
- final StringTokenizer t = new StringTokenizer(line);
+ final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
while (t.hasMoreTokens()) {
outSplit.add(t.nextToken());
}
@@ -1232,6 +1310,15 @@
}
}
+ /**
+ * Wrapper for {@link File#list()} that returns empty array instead of
+ * {@code null}.
+ */
+ private static String[] fileListWithoutNull(File file) {
+ final String[] list = file.list();
+ return list != null ? list : new String[0];
+ }
+
public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 24d4dd3..b8890aa 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -515,8 +515,9 @@
mIface, NetworkStats.UID_ALL, NetworkStats.TAG_NONE);
if (index != -1) {
- incRead = stats.rx[index] - mLastRead;
- incWrite = stats.tx[index] - mLastWrite;
+ final NetworkStats.Entry entry = stats.getValues(index, null);
+ incRead = entry.rxBytes - mLastRead;
+ incWrite = entry.txBytes - mLastWrite;
} else {
// missing iface, assume stats are 0
Slog.w(TAG, "unable to find stats for iface " + mIface);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 5f0922e..7112553 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -35,8 +35,8 @@
import android.net.wifi.WifiManager;
import android.net.wifi.WifiStateMachine;
import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiWatchdogStateMachine;
import android.net.wifi.WifiConfiguration.KeyMgmt;
-import android.net.wifi.WifiWatchdogService;
import android.net.wifi.WpsConfiguration;
import android.net.wifi.WpsResult;
import android.net.ConnectivityManager;
@@ -343,7 +343,7 @@
* Protected by mWifiStateTracker lock.
*/
private final WorkSource mTmpWorkSource = new WorkSource();
- private WifiWatchdogService mWifiWatchdogService;
+ private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
WifiService(Context context) {
mContext = context;
@@ -434,8 +434,9 @@
(wifiEnabled ? "enabled" : "disabled"));
setWifiEnabled(wifiEnabled);
- //TODO: as part of WWS refactor, create only when needed
- mWifiWatchdogService = new WifiWatchdogService(mContext);
+ mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
+ makeWifiWatchdogStateMachine(mContext);
+
}
private boolean testAndClearWifiSavedState() {
@@ -1162,8 +1163,8 @@
mLocks.dump(pw);
pw.println();
- pw.println("WifiWatchdogService dump");
- mWifiWatchdogService.dump(pw);
+ pw.println("WifiWatchdogStateMachine dump");
+ mWifiWatchdogStateMachine.dump(pw);
}
private class WifiLock extends DeathRecipient {
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 80cdf6b..bb9d15b 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -127,13 +127,15 @@
private int mHandledFeedbackTypes = 0;
- private boolean mIsEnabled;
+ private boolean mIsAccessibilityEnabled;
+
+ private boolean mIsTouchExplorationRequested;
private AccessibilityInputFilter mInputFilter;
private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>();
- private boolean mHasInputFilter;
+ private boolean mIsTouchExplorationEnabled;
private final WindowManagerService mWindowManagerService;
@@ -230,16 +232,21 @@
if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
synchronized (mLock) {
populateAccessibilityServiceListLocked();
- // get the accessibility enabled setting on boot
- mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ // get accessibility enabled setting on boot
+ mIsAccessibilityEnabled = Settings.Secure.getInt(
+ mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-
// if accessibility is enabled inform our clients we are on
- if (mIsEnabled) {
- updateClientsLocked();
+ if (mIsAccessibilityEnabled) {
+ sendAccessibilityEnabledToClientsLocked();
}
-
manageServicesLocked();
+
+ // get touch exploration enabled setting on boot
+ mIsTouchExplorationRequested = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
+ updateTouchExplorationEnabledLocked();
}
return;
@@ -264,29 +271,48 @@
private void registerSettingsContentObservers() {
ContentResolver contentResolver = mContext.getContentResolver();
- Uri enabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_ENABLED);
- contentResolver.registerContentObserver(enabledUri, false,
+ Uri accessibilityEnabledUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_ENABLED);
+ contentResolver.registerContentObserver(accessibilityEnabledUri, false,
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
synchronized (mLock) {
- mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
+ mIsAccessibilityEnabled = Settings.Secure.getInt(
+ mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
- if (mIsEnabled) {
+ if (mIsAccessibilityEnabled) {
manageServicesLocked();
} else {
unbindAllServicesLocked();
}
- updateClientsLocked();
+ sendAccessibilityEnabledToClientsLocked();
}
}
});
- Uri providersUri =
+ Uri touchExplorationRequestedUri = Settings.Secure.getUriFor(
+ Settings.Secure.TOUCH_EXPLORATION_REQUESTED);
+ contentResolver.registerContentObserver(touchExplorationRequestedUri, false,
+ new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+
+ synchronized (mLock) {
+ mIsTouchExplorationRequested = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.TOUCH_EXPLORATION_REQUESTED, 0) == 1;
+ updateTouchExplorationEnabledLocked();
+ }
+ }
+ });
+
+ Uri accessibilityServicesUri =
Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
- contentResolver.registerContentObserver(providersUri, false,
+ contentResolver.registerContentObserver(accessibilityServicesUri, false,
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
@@ -312,7 +338,7 @@
}
}
}, 0);
- return mIsEnabled;
+ return mIsAccessibilityEnabled;
}
}
@@ -602,7 +628,7 @@
service.linkToOwnDeath();
mServices.add(service);
mComponentNameToServiceMap.put(service.mComponentName, service);
- updateInputFilterLocked();
+ updateTouchExplorationEnabledLocked();
} catch (RemoteException e) {
/* do nothing */
}
@@ -622,7 +648,7 @@
mComponentNameToServiceMap.remove(service.mComponentName);
mHandler.removeMessages(service.mId);
service.unlinkToOwnDeath();
- updateInputFilterLocked();
+ updateTouchExplorationEnabledLocked();
return removed;
}
@@ -727,7 +753,7 @@
Set<ComponentName> enabledServices) {
Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap;
- boolean isEnabled = mIsEnabled;
+ boolean isEnabled = mIsAccessibilityEnabled;
for (int i = 0, count = installedServices.size(); i < count; i++) {
AccessibilityServiceInfo installedService = installedServices.get(i);
@@ -741,7 +767,7 @@
service = new Service(componentName, installedService, false);
}
service.bind();
- } else if (!enabledServices.contains(componentName)) {
+ } else {
if (service != null) {
service.unbind();
}
@@ -757,10 +783,10 @@
/**
* Updates the state of {@link android.view.accessibility.AccessibilityManager} clients.
*/
- private void updateClientsLocked() {
+ private void sendAccessibilityEnabledToClientsLocked() {
for (int i = 0, count = mClients.size(); i < count; i++) {
try {
- mClients.get(i).setEnabled(mIsEnabled);
+ mClients.get(i).setEnabled(mIsAccessibilityEnabled);
} catch (RemoteException re) {
mClients.remove(i);
count--;
@@ -770,29 +796,48 @@
}
/**
- * Updates the input filter state. The filter is enabled if accessibility
- * is enabled and there is at least one accessibility service providing
- * spoken feedback.
+ * Sends the touch exploration state to clients.
*/
- private void updateInputFilterLocked() {
- if (mIsEnabled) {
- final boolean hasSpokenFeedbackServices = !getEnabledAccessibilityServiceList(
- AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
- if (hasSpokenFeedbackServices) {
- if (mHasInputFilter) {
- return;
+ private void sendTouchExplorationEnabledToClientsLocked() {
+ for (int i = 0, count = mClients.size(); i < count; i++) {
+ try {
+ mClients.get(i).setTouchExplorationEnabled(mIsTouchExplorationEnabled);
+ } catch (RemoteException re) {
+ mClients.remove(i);
+ count--;
+ i--;
+ }
+ }
+ }
+
+ /**
+ * Updates the touch exploration state. Touch exploration is enabled if it
+ * is requested, accessibility is on and there is at least one enabled
+ * accessibility service providing spoken feedback.
+ */
+ private void updateTouchExplorationEnabledLocked() {
+ if (mIsAccessibilityEnabled && mIsTouchExplorationRequested) {
+ final boolean hasSpeakingServicesEnabled = !getEnabledAccessibilityServiceList(
+ AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty();
+ if (!mIsTouchExplorationEnabled) {
+ if (!hasSpeakingServicesEnabled) {
+ return;
}
if (mInputFilter == null) {
mInputFilter = new AccessibilityInputFilter(mContext);
}
mWindowManagerService.setInputFilter(mInputFilter);
- mHasInputFilter = true;
+ mIsTouchExplorationEnabled = true;
+ sendTouchExplorationEnabledToClientsLocked();
+ return;
+ } else if (hasSpeakingServicesEnabled) {
return;
}
}
- if (mHasInputFilter) {
+ if (mIsTouchExplorationEnabled) {
mWindowManagerService.setInputFilter(null);
- mHasInputFilter = false;
+ mIsTouchExplorationEnabled = false;
+ sendTouchExplorationEnabledToClientsLocked();
}
}
@@ -935,9 +980,11 @@
}
}
- public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId)
+ throws RemoteException {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
if (!permissionGranted) {
return null;
@@ -975,15 +1022,16 @@
}
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewTextInActiveWindow(
- String text) {
+ String text) throws RemoteException {
return findAccessibilityNodeInfosByViewText(text,
mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID);
}
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewText(String text,
- int accessibilityWindowId, int accessibilityViewId) {
+ int accessibilityWindowId, int accessibilityViewId) throws RemoteException {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
if (!permissionGranted) {
@@ -1026,9 +1074,10 @@
}
public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
- int accessibilityWindowId, int accessibilityViewId) {
+ int accessibilityWindowId, int accessibilityViewId) throws RemoteException {
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
+ mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
if (!permissionGranted) {
@@ -1155,9 +1204,7 @@
| AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
- AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END
- | AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START
- | AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
+ AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED
| AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
| AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
| AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED
@@ -1201,6 +1248,15 @@
return service.mCanRetrieveScreenContent;
}
+ public void enforceCanRetrieveWindowContent(Service service) throws RemoteException {
+ // This happens due to incorrect registration so make it apparent.
+ if (!canRetrieveWindowContent(service)) {
+ Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " +
+ "declare android:canRetrieveWindowContent.");
+ throw new RemoteException();
+ }
+ }
+
private boolean isRetrievalAllowingWindow(int windowId) {
return (mRetrievalAlowingWindowId == windowId);
}
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index 1af7015..5a3a55d 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -116,9 +116,6 @@
// which would perform a click and tapping and holding a long press.
private final int mTouchExplorationTapSlop;
- // Context handle for accessing resources.
- private final Context mContext;
-
// The InputFilter this tracker is associated with i.e. the filter
// which delegates event processing to this touch explorer.
private final InputFilter mInputFilter;
@@ -161,7 +158,6 @@
ViewConfiguration.get(context).getScaledTouchExplorationTapSlop();
mDraggingDistance = mTouchExplorationTapSlop * COEFFICIENT_DRAGGING_DISTANCE;
mPointerTracker = new PointerTracker(context);
- mContext = context;
mHandler = new Handler(context.getMainLooper());
mSendHoverDelayed = new SendHoverDelayed();
mAccessibilityManager = AccessibilityManager.getInstance(context);
@@ -216,7 +212,8 @@
// Send a hover for every finger down so the user gets feedback
// where she is currently touching.
mSendHoverDelayed.forceSendAndRemove();
- final int pointerIdBits = (1 << event.getActionIndex());
+ final int pointerIndex = event.getActionIndex();
+ final int pointerIdBits = (1 << event.getPointerId(pointerIndex));
mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits,
policyFlags, DELAY_SEND_HOVER_MOVE);
} break;
@@ -838,8 +835,6 @@
*/
private void sendAccessibilityEvent(int eventType) {
AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
- event.setPackageName(mContext.getPackageName());
- event.setClassName(getClass().getName());
mAccessibilityManager.sendAccessibilityEvent(event);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 62f0fea..94af46d 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -18,10 +18,10 @@
import com.android.internal.R;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.ProcessStats;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
import com.android.server.ProcessMap;
-import com.android.server.ProcessStats;
import com.android.server.SystemServer;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
@@ -45,7 +45,6 @@
import android.app.IProcessObserver;
import android.app.IServiceConnection;
import android.app.IThumbnailReceiver;
-import android.app.IThumbnailRetriever;
import android.app.Instrumentation;
import android.app.Notification;
import android.app.NotificationManager;
@@ -54,6 +53,7 @@
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
+import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -181,22 +181,8 @@
// The flags that are set for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
- private static final String SYSTEM_SECURE = "ro.secure";
private static final String SYSTEM_DEBUGGABLE = "ro.debuggable";
- // This is the maximum number of application processes we would like
- // to have running. Due to the asynchronous nature of things, we can
- // temporarily go beyond this limit.
- static final int MAX_PROCESSES = 2;
-
- // Set to false to leave processes running indefinitely, relying on
- // the kernel killing them as resources are required.
- static final boolean ENFORCE_PROCESS_LIMIT = false;
-
- // This is the maximum number of activities that we would like to have
- // running at a given time.
- static final int MAX_ACTIVITIES = 20;
-
// Maximum number of recent tasks that we can remember.
static final int MAX_RECENT_TASKS = 20;
@@ -208,6 +194,12 @@
// before we decide it's never going to come up for real.
static final int PROC_START_TIMEOUT = 10*1000;
+ // How long we wait for a launched process to attach to the activity manager
+ // before we decide it's never going to come up for real, when the process was
+ // started with a wrapper for instrumentation (such as Valgrind) because it
+ // could take much longer than usual.
+ static final int PROC_START_TIMEOUT_WITH_WRAPPER = 300*1000;
+
// How long to wait after going idle before forcing apps to GC.
static final int GC_TIMEOUT = 5*1000;
@@ -502,15 +494,6 @@
= new ArrayList<ProcessRecord>();
/**
- * List of records for processes that we have started and are waiting
- * for them to call back. This is really only needed when running in
- * single processes mode, in which case we do not have a unique pid for
- * each process.
- */
- final ArrayList<ProcessRecord> mStartingProcesses
- = new ArrayList<ProcessRecord>();
-
- /**
* List of persistent applications that are in the process
* of being started.
*/
@@ -917,7 +900,8 @@
*/
boolean mBooted = false;
- int mProcessLimit = 0;
+ int mProcessLimit = MAX_HIDDEN_APPS;
+ int mProcessLimitOverride = -1;
WindowManagerService mWindowManager;
@@ -1959,9 +1943,13 @@
if ("1".equals(SystemProperties.get("debug.assert"))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
- int pid = Process.start("android.app.ActivityThread",
+
+ // Start the process. It will either succeed and return a result containing
+ // the PID of the new process, or else throw a RuntimeException.
+ Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags,
app.info.targetSdkVersion, null);
+
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
synchronized (bs) {
if (bs.isOnBattery()) {
@@ -1969,12 +1957,12 @@
}
}
- EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
+ EventLog.writeEvent(EventLogTags.AM_PROC_START, startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
if (app.persistent) {
- Watchdog.getInstance().processStarted(app.processName, pid);
+ Watchdog.getInstance().processStarted(app.processName, startResult.pid);
}
StringBuilder buf = mStringBuilder;
@@ -1988,7 +1976,7 @@
buf.append(hostingNameStr);
}
buf.append(": pid=");
- buf.append(pid);
+ buf.append(startResult.pid);
buf.append(" uid=");
buf.append(uid);
buf.append(" gids={");
@@ -2001,26 +1989,15 @@
}
buf.append("}");
Slog.i(TAG, buf.toString());
- if (pid == 0 || pid == MY_PID) {
- // Processes are being emulated with threads.
- app.pid = MY_PID;
- app.removed = false;
- mStartingProcesses.add(app);
- } else if (pid > 0) {
- app.pid = pid;
- app.removed = false;
- synchronized (mPidsSelfLocked) {
- this.mPidsSelfLocked.put(pid, app);
- Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
- }
- } else {
- app.pid = 0;
- RuntimeException e = new RuntimeException(
- "Failure starting process " + app.processName
- + ": returned pid=" + pid);
- Slog.e(TAG, e.getMessage(), e);
+ app.pid = startResult.pid;
+ app.usingWrapper = startResult.usingWrapper;
+ app.removed = false;
+ synchronized (mPidsSelfLocked) {
+ this.mPidsSelfLocked.put(startResult.pid, app);
+ Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
+ msg.obj = app;
+ mHandler.sendMessageDelayed(msg, startResult.usingWrapper
+ ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
} catch (RuntimeException e) {
// XXX do better error recovery.
@@ -2301,11 +2278,10 @@
}
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(callingActivity);
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(callingActivity);
+ if (r == null) {
return false;
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
if (r.app == null || r.app.thread == null) {
// The caller is not running... d'oh!
return false;
@@ -2452,11 +2428,10 @@
public void setRequestedOrientation(IBinder token,
int requestedOrientation) {
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
return;
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
mWindowManager.setAppOrientation(r, requestedOrientation);
Configuration config = mWindowManager.updateOrientationFromAppTokens(
@@ -2474,11 +2449,10 @@
public int getRequestedOrientation(IBinder token) {
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return mWindowManager.getAppOrientation(r);
}
}
@@ -2619,11 +2593,10 @@
public final void finishSubActivity(IBinder token, String resultWho,
int requestCode) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord self = mMainStack.isInStackLocked(token);
+ if (self == null) {
return;
}
- ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
@@ -2662,11 +2635,10 @@
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ ActivityRecord self = mMainStack.isInStackLocked(token);
+ if (self == null) {
return;
}
- ActivityRecord self = (ActivityRecord)mMainStack.mHistory.get(index);
final long origId = Binder.clearCallingIdentity();
@@ -2745,8 +2717,7 @@
}
}
- r.stack.cleanUpActivityLocked(r, true);
- r.state = ActivityState.STOPPED;
+ r.stack.cleanUpActivityLocked(r, true, true);
}
atTop = false;
}
@@ -3606,9 +3577,6 @@
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
- } else if (mStartingProcesses.size() > 0) {
- app = mStartingProcesses.remove(0);
- app.setPid(pid);
} else {
app = null;
}
@@ -3642,8 +3610,10 @@
String processName = app.processName;
try {
- thread.asBinder().linkToDeath(new AppDeathRecipient(
- app, pid, thread), 0);
+ AppDeathRecipient adr = new AppDeathRecipient(
+ app, pid, thread);
+ thread.asBinder().linkToDeath(adr, 0);
+ app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList();
startProcessLocked(app, "link fail", processName);
@@ -3719,6 +3689,7 @@
Slog.w(TAG, "Exception thrown during bind!", e);
app.resetPackageList();
+ app.unlinkDeathRecipient();
startProcessLocked(app, "bind fail", processName);
return false;
}
@@ -3933,20 +3904,9 @@
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- r = (ActivityRecord)mMainStack.mHistory.get(index);
- r.icicle = icicle;
- r.haveState = true;
- r.updateThumbnail(thumbnail, description);
- r.stopped = true;
- r.state = ActivityState.STOPPED;
- if (!r.finishing) {
- if (r.configDestroy) {
- r.stack.destroyActivityLocked(r, true);
- r.stack.resumeTopActivityLocked(null);
- }
- }
+ r = mMainStack.isInStackLocked(token);
+ if (r != null) {
+ r.stack.activityStoppedLocked(r, icicle, thumbnail, description);
}
}
@@ -3979,35 +3939,30 @@
}
private ActivityRecord getCallingRecordLocked(IBinder token) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- if (r != null) {
- return r.resultTo;
- }
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
+ return null;
}
- return null;
+ return r.resultTo;
}
public ComponentName getActivityClassForToken(IBinder token) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- return r.intent.getComponent();
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
+ return null;
}
- return null;
+ return r.intent.getComponent();
}
}
public String getPackageForToken(IBinder token) {
synchronized(this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- return r.packageName;
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
+ return null;
}
- return null;
+ return r.packageName;
}
}
@@ -4042,8 +3997,7 @@
synchronized(this) {
int callingUid = Binder.getCallingUid();
try {
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
- Process.supportsProcesses()) {
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
int uid = AppGlobals.getPackageManager()
.getPackageUid(packageName);
if (uid != Binder.getCallingUid()) {
@@ -4071,11 +4025,10 @@
int requestCode, Intent[] intents, String[] resolvedTypes, int flags) {
ActivityRecord activity = null;
if (type == INTENT_SENDER_ACTIVITY_RESULT) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ activity = mMainStack.isInStackLocked(token);
+ if (activity == null) {
return null;
}
- activity = (ActivityRecord)mMainStack.mHistory.get(index);
if (activity.finishing) {
return null;
}
@@ -4197,11 +4150,17 @@
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
- mProcessLimit = max;
+ synchronized (this) {
+ mProcessLimit = max < 0 ? MAX_HIDDEN_APPS : max;
+ mProcessLimitOverride = max;
+ }
+ trimApplications();
}
public int getProcessLimit() {
- return mProcessLimit;
+ synchronized (this) {
+ return mProcessLimitOverride;
+ }
}
void foregroundTokenDied(ForegroundToken token) {
@@ -4302,8 +4261,7 @@
}
// Root, system server and our own process get to do everything.
- if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
- !Process.supportsProcesses()) {
+ if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
// If there is a uid that owns whatever is being accessed, it has
@@ -4447,7 +4405,7 @@
private final boolean checkUriPermissionLocked(Uri uri, int uid,
int modeFlags) {
// Root gets to do everything.
- if (uid == 0 || !Process.supportsProcesses()) {
+ if (uid == 0) {
return true;
}
HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
@@ -5466,11 +5424,10 @@
synchronized(this) {
if (r == null) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index < 0) {
+ r = mMainStack.isInStackLocked(token);
+ if (r == null) {
return;
}
- r = (ActivityRecord)mMainStack.mHistory.get(index);
}
if (thumbnail == null && r.thumbHolder != null) {
thumbnail = r.thumbHolder.lastThumbnail;
@@ -5528,8 +5485,8 @@
// CONTENT PROVIDERS
// =========================================================
- private final List generateApplicationProvidersLocked(ProcessRecord app) {
- List providers = null;
+ private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
+ List<ProviderInfo> providers = null;
try {
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
@@ -5967,7 +5924,7 @@
}
public static final void installSystemProviders() {
- List providers;
+ List<ProviderInfo> providers;
synchronized (mSelf) {
ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
providers = mSelf.generateApplicationProvidersLocked(app);
@@ -6184,9 +6141,8 @@
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- int index = mMainStack.indexOfTokenLocked(token);
- if (index >= 0) {
- r = (ActivityRecord)mMainStack.mHistory.get(index);
+ r = mMainStack.isInStackLocked(token);
+ if (r != null) {
mMainStack.activitySleptLocked(r);
}
}
@@ -6337,22 +6293,20 @@
public void setImmersive(IBinder token, boolean immersive) {
synchronized(this) {
- int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
throw new IllegalArgumentException();
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
r.immersive = immersive;
}
}
public boolean isImmersive(IBinder token) {
synchronized (this) {
- int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
- if (index < 0) {
+ ActivityRecord r = mMainStack.isInStackLocked(token);
+ if (r == null) {
throw new IllegalArgumentException();
}
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
return r.immersive;
}
}
@@ -6585,13 +6539,6 @@
}
public void systemReady(final Runnable goingCallback) {
- // In the simulator, startRunning will never have been called, which
- // normally sets a few crucial variables. Do it here instead.
- if (!Process.supportsProcesses()) {
- mStartRunning = true;
- mTopAction = Intent.ACTION_MAIN;
- }
-
synchronized(this) {
if (mSystemReady) {
if (goingCallback != null) goingCallback.run();
@@ -7955,14 +7902,6 @@
"Starting Norm", "Restarting PERS");
}
- if (mStartingProcesses.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Processes that are starting:");
- dumpProcessList(pw, this, mStartingProcesses, " ",
- "Starting Norm", "Starting PERS");
- }
-
if (mRemovedProcesses.size() > 0) {
if (needSep) pw.println(" ");
needSep = true;
@@ -8830,9 +8769,10 @@
} else {
foreground = " ";
}
- pw.println(String.format("%s%s #%2d: adj=%s/%s%s %s (%s)",
+ pw.println(String.format("%s%s #%2d: adj=%s/%s%s trm=%2d %s (%s)",
prefix, (r.persistent ? persistentLabel : normalLabel),
- N-i, oomAdj, schedGroup, foreground, r.toShortString(), r.adjType));
+ N-i, oomAdj, schedGroup, foreground, r.trimMemoryLevel,
+ r.toShortString(), r.adjType));
if (r.adjSource != null || r.adjTarget != null) {
pw.print(prefix);
pw.print(" ");
@@ -8948,25 +8888,59 @@
pw.println("Applications Graphics Acceleration Info:");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
- String callArgs[] = {"graphics"};
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
pw.println("\n** Graphics info for pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
try {
- TransferPipe.goDump(r.thread.asBinder(), fd, callArgs);
+ TransferPipe tp = new TransferPipe();
+ try {
+ r.thread.dumpGfxInfo(tp.getWriteFd().getFileDescriptor(), args);
+ tp.go(fd);
+ } finally {
+ tp.kill();
+ }
} catch (IOException e) {
- pw.println("Failure: " + e);
+ pw.println("Failure while dumping the app: " + r);
pw.flush();
} catch (RemoteException e) {
- pw.println("Got RemoteException!");
+ pw.println("Got a RemoteException while dumping the app " + r);
pw.flush();
}
}
}
}
+ final static class MemItem {
+ final String label;
+ final long pss;
+
+ public MemItem(String _label, long _pss) {
+ label = _label;
+ pss = _pss;
+ }
+ }
+
+ final void dumpMemItems(PrintWriter pw, String prefix, ArrayList<MemItem> items) {
+ Collections.sort(items, new Comparator<MemItem>() {
+ @Override
+ public int compare(MemItem lhs, MemItem rhs) {
+ if (lhs.pss < rhs.pss) {
+ return 1;
+ } else if (lhs.pss > rhs.pss) {
+ return -1;
+ }
+ return 0;
+ }
+ });
+
+ for (int i=0; i<items.size(); i++) {
+ MemItem mi = items.get(i);
+ pw.print(prefix); pw.printf("%8d Kb: ", mi.pss); pw.println(mi.label);
+ }
+ }
+
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args) {
ArrayList<ProcessRecord> procs = collectProcesses(pw, args);
@@ -8986,6 +8960,11 @@
pw.println("Applications Memory Usage (kB):");
pw.println("Uptime: " + uptime + " Realtime: " + realtime);
}
+
+ ArrayList<MemItem> procMems = new ArrayList<MemItem>();
+ long nativePss=0, dalvikPss=0, otherPss=0;
+ long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+
for (int i = procs.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = procs.get(i);
if (r.thread != null) {
@@ -8993,19 +8972,48 @@
pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
pw.flush();
}
+ Debug.MemoryInfo mi = null;
try {
- TransferPipe.goDump(r.thread.asBinder(), fd, args);
- } catch (IOException e) {
- pw.println("Failure: " + e);
- pw.flush();
+ mi = r.thread.dumpMemInfo(fd, args);
} catch (RemoteException e) {
if (!isCheckinRequest) {
pw.println("Got RemoteException!");
pw.flush();
}
}
+ if (!isCheckinRequest && mi != null) {
+ procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")",
+ mi.getTotalPss()));
+
+ nativePss += mi.nativePss;
+ dalvikPss += mi.dalvikPss;
+ otherPss += mi.otherPss;
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ long mem = mi.getOtherPss(j);
+ miscPss[j] += mem;
+ otherPss -= mem;
+ }
+ }
}
}
+
+ if (!isCheckinRequest && procs.size() > 1) {
+ ArrayList<MemItem> catMems = new ArrayList<MemItem>();
+
+ catMems.add(new MemItem("Native", nativePss));
+ catMems.add(new MemItem("Dalvik", dalvikPss));
+ catMems.add(new MemItem("Unknown", otherPss));
+ for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
+ catMems.add(new MemItem(Debug.MemoryInfo.getOtherLabel(j), miscPss[j]));
+ }
+
+ pw.println();
+ pw.println("Total PSS by process:");
+ dumpMemItems(pw, " ", procMems);
+ pw.println();
+ pw.println("Total PSS by category:");
+ dumpMemItems(pw, " ", catMems);
+ }
}
/**
@@ -9205,6 +9213,7 @@
app.notResponding = false;
app.resetPackageList();
+ app.unlinkDeathRecipient();
app.thread = null;
app.forcingToForeground = null;
app.foregroundServices = false;
@@ -9322,7 +9331,6 @@
// This app is persistent, so we need to keep its record around.
// If it is not already on the pending app list, add it there
// and start a new process for it.
- app.thread = null;
app.forcingToForeground = null;
app.foregroundServices = false;
if (mPersistentStartingProcesses.indexOf(app) < 0) {
@@ -10367,12 +10375,11 @@
ActivityRecord activity = null;
if (token != null) {
- int aindex = mMainStack.indexOfTokenLocked(token);
- if (aindex < 0) {
+ activity = mMainStack.isInStackLocked(token);
+ if (activity == null) {
Slog.w(TAG, "Binding with unknown activity: " + token);
return 0;
}
- activity = (ActivityRecord)mMainStack.mHistory.get(aindex);
}
int clientLabel = 0;
@@ -11586,8 +11593,8 @@
return false;
}
int state = r.state;
- r.state = r.IDLE;
- if (state == r.IDLE) {
+ r.state = BroadcastRecord.IDLE;
+ if (state == BroadcastRecord.IDLE) {
if (explicit) {
Slog.w(TAG, "finishReceiver called but state is IDLE");
}
@@ -12971,7 +12978,7 @@
ProcessRecord proc = mProcessesToGc.get(0);
Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
- long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
+ long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
long now = SystemClock.uptimeMillis();
if (when < (now+GC_TIMEOUT)) {
when = now + GC_TIMEOUT;
@@ -13114,95 +13121,88 @@
}
}
- private final boolean updateOomAdjLocked(
+ private final void updateOomAdjLocked(
ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
app.hiddenAdj = hiddenAdj;
if (app.thread == null) {
- return true;
+ return;
}
- boolean success = true;
-
final boolean wasKeeping = app.keeping;
int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
- if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
- if (app.curRawAdj != app.setRawAdj) {
- if (app.curRawAdj > FOREGROUND_APP_ADJ
- && app.setRawAdj <= FOREGROUND_APP_ADJ) {
- // If this app is transitioning from foreground to
- // non-foreground, have it do a gc.
- scheduleAppGcLocked(app);
- } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
- && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
- // Likewise do a gc when an app is moving in to the
- // background (such as a service stopping).
- scheduleAppGcLocked(app);
- }
+ if (app.curRawAdj != app.setRawAdj) {
+ if (app.curRawAdj > FOREGROUND_APP_ADJ
+ && app.setRawAdj <= FOREGROUND_APP_ADJ) {
+ // If this app is transitioning from foreground to
+ // non-foreground, have it do a gc.
+ scheduleAppGcLocked(app);
+ } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
+ && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
+ // Likewise do a gc when an app is moving in to the
+ // background (such as a service stopping).
+ scheduleAppGcLocked(app);
+ }
- if (wasKeeping && !app.keeping) {
- // This app is no longer something we want to keep. Note
- // its current wake lock time to later know to kill it if
- // it is not behaving well.
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
- app.pid, SystemClock.elapsedRealtime());
+ if (wasKeeping && !app.keeping) {
+ // This app is no longer something we want to keep. Note
+ // its current wake lock time to later know to kill it if
+ // it is not behaving well.
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
+ app.pid, SystemClock.elapsedRealtime());
+ }
+ app.lastCpuTime = app.curCpuTime;
+ }
+
+ app.setRawAdj = app.curRawAdj;
+ }
+ if (adj != app.setAdj) {
+ if (Process.setOomAdj(app.pid, adj)) {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
+ TAG, "Set app " + app.processName +
+ " oom adj to " + adj + " because " + app.adjType);
+ app.setAdj = adj;
+ } else {
+ Slog.w(TAG, "Failed setting oom adj of " + app + " to " + adj);
+ }
+ }
+ if (app.setSchedGroup != app.curSchedGroup) {
+ app.setSchedGroup = app.curSchedGroup;
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Setting process group of " + app.processName
+ + " to " + app.curSchedGroup);
+ if (app.waitingToKill != null &&
+ app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, app.waitingToKill);
+ Process.killProcessQuiet(app.pid);
+ } else {
+ if (true) {
+ long oldId = Binder.clearCallingIdentity();
+ try {
+ Process.setProcessGroup(app.pid, app.curSchedGroup);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed setting process group of " + app.pid
+ + " to " + app.curSchedGroup);
+ e.printStackTrace();
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- app.lastCpuTime = app.curCpuTime;
- }
-
- app.setRawAdj = app.curRawAdj;
- }
- if (adj != app.setAdj) {
- if (Process.setOomAdj(app.pid, adj)) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
- TAG, "Set app " + app.processName +
- " oom adj to " + adj);
- app.setAdj = adj;
} else {
- success = false;
- }
- }
- if (app.setSchedGroup != app.curSchedGroup) {
- app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
- "Setting process group of " + app.processName
- + " to " + app.curSchedGroup);
- if (app.waitingToKill != null &&
- app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, app.waitingToKill);
- Process.killProcessQuiet(app.pid);
- } else {
- if (true) {
- long oldId = Binder.clearCallingIdentity();
+ if (app.thread != null) {
try {
- Process.setProcessGroup(app.pid, app.curSchedGroup);
- } catch (Exception e) {
- Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
- e.printStackTrace();
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
- if (false) {
- if (app.thread != null) {
- try {
- app.thread.setSchedulingGroup(app.curSchedGroup);
- } catch (RemoteException e) {
- }
+ app.thread.setSchedulingGroup(app.curSchedGroup);
+ } catch (RemoteException e) {
}
}
}
}
}
-
- return success;
}
private final ActivityRecord resumedAppLocked() {
@@ -13216,30 +13216,26 @@
return resumedActivity;
}
- private final boolean updateOomAdjLocked(ProcessRecord app) {
+ private final void updateOomAdjLocked(ProcessRecord app) {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
int curAdj = app.curAdj;
- final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
- && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+ final boolean wasHidden = curAdj >= HIDDEN_APP_MIN_ADJ
+ && curAdj <= HIDDEN_APP_MAX_ADJ;
mAdjSeq++;
- final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
- if (res) {
- final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
- && app.curAdj <= HIDDEN_APP_MAX_ADJ;
- if (nowHidden != wasHidden) {
- // Changed to/from hidden state, so apps after it in the LRU
- // list may also be changed.
- updateOomAdjLocked();
- }
+ updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
+ final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
+ && app.curAdj <= HIDDEN_APP_MAX_ADJ;
+ if (nowHidden != wasHidden) {
+ // Changed to/from hidden state, so apps after it in the LRU
+ // list may also be changed.
+ updateOomAdjLocked();
}
- return res;
}
- final boolean updateOomAdjLocked() {
- boolean didOomAdj = true;
+ final void updateOomAdjLocked() {
final ActivityRecord TOP_ACT = resumedAppLocked();
final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -13261,45 +13257,104 @@
int step = 0;
int numHidden = 0;
- // First try updating the OOM adjustment for each of the
+ // First update the OOM adjustment for each of the
// application processes based on their current state.
int i = mLruProcesses.size();
int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
+ int numBg = 0;
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
//Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
- if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
- if (curHiddenAdj < EMPTY_APP_ADJ
- && app.curAdj == curHiddenAdj) {
- step++;
- if (step >= factor) {
- step = 0;
- curHiddenAdj++;
- }
+ updateOomAdjLocked(app, curHiddenAdj, TOP_APP);
+ if (curHiddenAdj < EMPTY_APP_ADJ
+ && app.curAdj == curHiddenAdj) {
+ step++;
+ if (step >= factor) {
+ step = 0;
+ curHiddenAdj++;
}
+ }
+ if (!app.killedBackground) {
if (app.curAdj >= HIDDEN_APP_MIN_ADJ) {
- if (!app.killedBackground) {
- numHidden++;
- if (numHidden > MAX_HIDDEN_APPS) {
- Slog.i(TAG, "No longer want " + app.processName
- + " (pid " + app.pid + "): hidden #" + numHidden);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "too many background");
- app.killedBackground = true;
- Process.killProcessQuiet(app.pid);
- }
+ numHidden++;
+ if (numHidden > mProcessLimit) {
+ Slog.i(TAG, "No longer want " + app.processName
+ + " (pid " + app.pid + "): hidden #" + numHidden);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "too many background");
+ app.killedBackground = true;
+ Process.killProcessQuiet(app.pid);
+ } else {
+ numBg++;
}
+ } else if (app.curAdj >= HOME_APP_ADJ) {
+ numBg++;
}
- } else {
- didOomAdj = false;
}
}
- // If we return false, we will fall back on killing processes to
- // have a fixed limit. Do this if a limit has been requested; else
- // only return false if one of the adjustments failed.
- return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
+ // Now determine the memory trimming level of background processes.
+ // Unfortunately we need to start at the back of the list to do this
+ // properly. We only do this if the number of background apps we
+ // are managing to keep around is less than half the maximum we desire;
+ // if we are keeping a good number around, we'll let them use whatever
+ // memory they want.
+ if (numHidden <= (MAX_HIDDEN_APPS/2)) {
+ final int N = mLruProcesses.size();
+ factor = numBg/3;
+ step = 0;
+ int curLevel = ComponentCallbacks.TRIM_MEMORY_COMPLETE;
+ for (i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ if (app.curAdj >= HIDDEN_APP_MIN_ADJ && !app.killedBackground) {
+ if (app.trimMemoryLevel < curLevel && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(curLevel);
+ } catch (RemoteException e) {
+ }
+ if (curLevel >= ComponentCallbacks.TRIM_MEMORY_COMPLETE) {
+ // For these apps we will also finish their activities
+ // to help them free memory.
+ mMainStack.destroyActivitiesLocked(app, false);
+ }
+ }
+ app.trimMemoryLevel = curLevel;
+ step++;
+ if (step >= factor) {
+ switch (curLevel) {
+ case ComponentCallbacks.TRIM_MEMORY_COMPLETE:
+ curLevel = ComponentCallbacks.TRIM_MEMORY_MODERATE;
+ break;
+ case ComponentCallbacks.TRIM_MEMORY_MODERATE:
+ curLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND;
+ break;
+ }
+ }
+ } else if (app.curAdj >= PERCEPTIBLE_APP_ADJ) {
+ if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_INVISIBLE
+ && app.thread != null) {
+ try {
+ app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_INVISIBLE);
+ } catch (RemoteException e) {
+ }
+ }
+ app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_INVISIBLE;
+ } else {
+ app.trimMemoryLevel = 0;
+ }
+ }
+ } else {
+ final int N = mLruProcesses.size();
+ for (i=0; i<N; i++) {
+ ProcessRecord app = mLruProcesses.get(i);
+ app.trimMemoryLevel = 0;
+ }
+ }
+
+ if (mAlwaysFinishActivities) {
+ mMainStack.destroyActivitiesLocked(null, false);
+ }
}
final void trimApplications() {
@@ -13339,165 +13394,8 @@
}
}
- // Now try updating the OOM adjustment for each of the
- // application processes based on their current state.
- // If the setOomAdj() API is not supported, then go with our
- // back-up plan...
- if (!updateOomAdjLocked()) {
-
- // Count how many processes are running services.
- int numServiceProcs = 0;
- for (i=mLruProcesses.size()-1; i>=0; i--) {
- final ProcessRecord app = mLruProcesses.get(i);
-
- if (app.persistent || app.services.size() != 0
- || app.curReceiver != null) {
- // Don't count processes holding services against our
- // maximum process count.
- if (localLOGV) Slog.v(
- TAG, "Not trimming app " + app + " with services: "
- + app.services);
- numServiceProcs++;
- }
- }
-
- int curMaxProcs = mProcessLimit;
- if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
- if (mAlwaysFinishActivities) {
- curMaxProcs = 1;
- }
- curMaxProcs += numServiceProcs;
-
- // Quit as many processes as we can to get down to the desired
- // process count. First remove any processes that no longer
- // have activites running in them.
- for ( i=0;
- i<mLruProcesses.size()
- && mLruProcesses.size() > curMaxProcs;
- i++) {
- final ProcessRecord app = mLruProcesses.get(i);
- // Quit an application only if it is not currently
- // running any activities.
- if (!app.persistent && app.activities.size() == 0
- && app.curReceiver == null && app.services.size() == 0) {
- Slog.i(
- TAG, "Exiting empty application process "
- + app.processName + " ("
- + (app.thread != null ? app.thread.asBinder() : null)
- + ")\n");
- if (app.pid > 0 && app.pid != MY_PID) {
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "empty");
- Process.killProcessQuiet(app.pid);
- } else {
- try {
- app.thread.scheduleExit();
- } catch (Exception e) {
- // Ignore exceptions.
- }
- }
- // todo: For now we assume the application is not buggy
- // or evil, and will quit as a result of our request.
- // Eventually we need to drive this off of the death
- // notification, and kill the process if it takes too long.
- cleanUpApplicationRecordLocked(app, false, i);
- i--;
- }
- }
-
- // If we still have too many processes, now from the least
- // recently used process we start finishing activities.
- if (false) Slog.v(
- TAG, "*** NOW HAVE " + mLruProcesses.size() +
- " of " + curMaxProcs + " processes");
- for ( i=0;
- i<mLruProcesses.size()
- && mLruProcesses.size() > curMaxProcs;
- i++) {
- final ProcessRecord app = mLruProcesses.get(i);
- // Quit the application only if we have a state saved for
- // all of its activities.
- boolean canQuit = !app.persistent && app.curReceiver == null
- && app.services.size() == 0;
- int NUMA = app.activities.size();
- int j;
- if (false) Slog.v(
- TAG, "Looking to quit " + app.processName);
- for (j=0; j<NUMA && canQuit; j++) {
- ActivityRecord r = app.activities.get(j);
- if (false) Slog.v(
- TAG, " " + r.intent.getComponent().flattenToShortString()
- + ": frozen=" + r.haveState + ", visible=" + r.visible);
- canQuit = (r.haveState || !r.stateNotNeeded)
- && !r.visible && r.stopped;
- }
- if (canQuit) {
- // Finish all of the activities, and then the app itself.
- for (j=0; j<NUMA; j++) {
- ActivityRecord r = app.activities.get(j);
- if (!r.finishing) {
- r.stack.destroyActivityLocked(r, false);
- }
- r.resultTo = null;
- }
- Slog.i(TAG, "Exiting application process "
- + app.processName + " ("
- + (app.thread != null ? app.thread.asBinder() : null)
- + ")\n");
- if (app.pid > 0 && app.pid != MY_PID) {
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, "old background");
- Process.killProcessQuiet(app.pid);
- } else {
- try {
- app.thread.scheduleExit();
- } catch (Exception e) {
- // Ignore exceptions.
- }
- }
- // todo: For now we assume the application is not buggy
- // or evil, and will quit as a result of our request.
- // Eventually we need to drive this off of the death
- // notification, and kill the process if it takes too long.
- cleanUpApplicationRecordLocked(app, false, i);
- i--;
- //dump();
- }
- }
-
- }
-
- int curMaxActivities = MAX_ACTIVITIES;
- if (mAlwaysFinishActivities) {
- curMaxActivities = 1;
- }
-
- // Finally, if there are too many activities now running, try to
- // finish as many as we can to get back down to the limit.
- for ( i=0;
- i<mMainStack.mLRUActivities.size()
- && mMainStack.mLRUActivities.size() > curMaxActivities;
- i++) {
- final ActivityRecord r
- = (ActivityRecord)mMainStack.mLRUActivities.get(i);
-
- // We can finish this one if we have its icicle saved and
- // it is not persistent.
- if ((r.haveState || !r.stateNotNeeded) && !r.visible
- && r.stopped && !r.finishing) {
- final int origSize = mMainStack.mLRUActivities.size();
- r.stack.destroyActivityLocked(r, true);
-
- // This will remove it from the LRU list, so keep
- // our index at the same value. Note that this check to
- // see if the size changes is just paranoia -- if
- // something unexpected happens, we don't want to end up
- // in an infinite loop.
- if (origSize > mMainStack.mLRUActivities.size()) {
- i--;
- }
- }
- }
+ // Now update the oom adj for all processes.
+ updateOomAdjLocked();
}
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 090e26b..73ffafb 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -658,12 +658,12 @@
public long getKeyDispatchingTimeout() {
synchronized(service) {
ActivityRecord r = getWaitingHistoryRecordLocked();
- if (r == null || r.app == null
- || r.app.instrumentationClass == null) {
- return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
+ if (r != null && r.app != null
+ && (r.app.instrumentationClass != null || r.app.usingWrapper)) {
+ return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
}
-
- return ActivityManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
+
+ return ActivityManagerService.KEY_DISPATCHING_TIMEOUT;
}
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b1da69f..93d8164 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -52,6 +52,7 @@
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -83,6 +84,8 @@
static final boolean DEBUG_CONFIGURATION = ActivityManagerService.DEBUG_CONFIGURATION;
static final boolean DEBUG_TASKS = ActivityManagerService.DEBUG_TASKS;
+ static final boolean DEBUG_STATES = false;
+
static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
// How long we wait until giving up on the last activity telling us it
@@ -392,19 +395,25 @@
}
final int indexOfTokenLocked(IBinder token) {
- int count = mHistory.size();
-
- // convert the token to an entry in the history.
- int index = -1;
- for (int i=count-1; i>=0; i--) {
- Object o = mHistory.get(i);
- if (o == token) {
- index = i;
- break;
- }
+ try {
+ ActivityRecord r = (ActivityRecord)token;
+ return mHistory.indexOf(r);
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Bad activity token: " + token, e);
+ return -1;
}
+ }
- return index;
+ final ActivityRecord isInStackLocked(IBinder token) {
+ try {
+ ActivityRecord r = (ActivityRecord)token;
+ if (mHistory.contains(r)) {
+ return r;
+ }
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Bad activity token: " + token, e);
+ }
+ return null;
}
private final boolean updateLRUListLocked(ActivityRecord r) {
@@ -604,6 +613,8 @@
// As part of the process of launching, ActivityThread also performs
// a resume.
r.state = ActivityState.RESUMED;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + r
+ + " (starting new instance)");
r.stopped = false;
mResumedActivity = r;
r.task.touchActiveTime();
@@ -617,6 +628,8 @@
// should look like we asked it to pause+stop (but remain visible),
// and it has done so and reported back the current icicle and
// other state.
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
+ + " (starting in stopped state)");
r.state = ActivityState.STOPPED;
r.stopped = true;
}
@@ -797,7 +810,8 @@
resumeTopActivityLocked(null);
return;
}
- if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
+ else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
mResumedActivity = null;
mPausingActivity = prev;
mLastPausedActivity = prev;
@@ -879,6 +893,8 @@
r = mHistory.get(index);
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+ + (timeout ? " (due to timeout)" : " (pause complete)"));
r.state = ActivityState.PAUSED;
completePauseLocked();
} else {
@@ -891,6 +907,22 @@
}
}
+ final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
+ CharSequence description) {
+ r.icicle = icicle;
+ r.haveState = true;
+ r.updateThumbnail(thumbnail, description);
+ r.stopped = true;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
+ r.state = ActivityState.STOPPED;
+ if (!r.finishing) {
+ if (r.configDestroy) {
+ destroyActivityLocked(r, true, false);
+ resumeTopActivityLocked(null);
+ }
+ }
+ }
+
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
@@ -914,7 +946,7 @@
// instance right now, we need to first completely stop
// the current instance before starting the new one.
if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
- destroyActivityLocked(prev, true);
+ destroyActivityLocked(prev, true, false);
} else {
mStoppingActivities.add(prev);
if (mStoppingActivities.size() > 3) {
@@ -1371,6 +1403,7 @@
mService.updateCpuStats();
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
next.state = ActivityState.RESUMED;
mResumedActivity = next;
next.task.touchActiveTime();
@@ -1447,6 +1480,8 @@
} catch (Exception e) {
// Whoops, need to restart this activity!
+ if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to "
+ + lastState + ": " + next);
next.state = lastState;
mResumedActivity = lastResumedActivity;
Slog.i(TAG, "Restarting because process died: " + next);
@@ -2960,6 +2995,8 @@
r.resumeKeyDispatchingLocked();
try {
r.stopped = false;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
+ + " (stop requested)");
r.state = ActivityState.STOPPING;
if (DEBUG_VISBILITY) Slog.v(
TAG, "Stopping visible=" + r.visible + " for " + r);
@@ -2977,9 +3014,10 @@
Slog.w(TAG, "Exception thrown during pause", e);
// Just in case, assume it to be stopped.
r.stopped = true;
+ if (DEBUG_STATES) Slog.v(TAG, "Stop failed; moving to STOPPED: " + r);
r.state = ActivityState.STOPPED;
if (r.configDestroy) {
- destroyActivityLocked(r, true);
+ destroyActivityLocked(r, true, false);
}
}
}
@@ -3145,7 +3183,7 @@
for (i=0; i<NF; i++) {
ActivityRecord r = (ActivityRecord)finishes.get(i);
synchronized (mService) {
- destroyActivityLocked(r, true);
+ destroyActivityLocked(r, true, false);
}
}
@@ -3340,6 +3378,8 @@
checkReadyForSleepLocked();
}
}
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
+ + " (finish requested)");
r.state = ActivityState.STOPPING;
mService.updateOomAdjLocked();
return r;
@@ -3353,6 +3393,7 @@
mResumedActivity = null;
}
final ActivityState prevState = r.state;
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to FINISHING: " + r);
r.state = ActivityState.FINISHING;
if (mode == FINISH_IMMEDIATELY
@@ -3360,7 +3401,7 @@
|| prevState == ActivityState.INITIALIZING) {
// If this activity is already stopped, we can just finish
// it right now.
- return destroyActivityLocked(r, true) ? null : r;
+ return destroyActivityLocked(r, true, true) ? null : r;
} else {
// Need to go through the full pause cycle to get this
// activity into the stopped state and then finish it.
@@ -3378,7 +3419,8 @@
* processing going away, in which case there is no remaining client-side
* state to destroy so only the cleanup here is needed.
*/
- final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices) {
+ final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
+ boolean setState) {
if (mResumedActivity == r) {
mResumedActivity = null;
}
@@ -3389,6 +3431,11 @@
r.configDestroy = false;
r.frozenBeforeDestroy = false;
+ if (setState) {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r + " (cleaning up)");
+ r.state = ActivityState.DESTROYED;
+ }
+
// Make sure this record is no longer in the pending finishes list.
// This could happen, for example, if we are trimming activities
// down to the max limit while they are still waiting to finish.
@@ -3428,6 +3475,8 @@
r.makeFinishing();
mHistory.remove(r);
r.takeFromHistory();
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ + " (removed from history)");
r.state = ActivityState.DESTROYED;
mService.mWindowManager.removeAppToken(r);
if (VALIDATE_TOKENS) {
@@ -3453,6 +3502,22 @@
}
}
+ final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj) {
+ for (int i=mHistory.size()-1; i>=0; i--) {
+ ActivityRecord r = mHistory.get(i);
+ if (owner != null && r.app != owner) {
+ continue;
+ }
+ // We can destroy this one if we have its icicle saved and
+ // it is not in the process of pausing/stopping/finishing.
+ if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing
+ && r.state != ActivityState.DESTROYING
+ && r.state != ActivityState.DESTROYED) {
+ destroyActivityLocked(r, true, oomAdj);
+ }
+ }
+ }
+
/**
* Destroy the current CLIENT SIDE instance of an activity. This may be
* called both when actually finishing an activity, or when performing
@@ -3460,7 +3525,7 @@
* but then create a new client-side object for this same HistoryRecord.
*/
final boolean destroyActivityLocked(ActivityRecord r,
- boolean removeFromApp) {
+ boolean removeFromApp, boolean oomAdj) {
if (DEBUG_SWITCH) Slog.v(
TAG, "Removing activity: token=" + r
+ ", app=" + (r.app != null ? r.app.processName : "(null)"));
@@ -3470,7 +3535,7 @@
boolean removedFromHistory = false;
- cleanUpActivityLocked(r, false);
+ cleanUpActivityLocked(r, false, false);
final boolean hadApp = r.app != null;
@@ -3488,7 +3553,7 @@
if (r.app.activities.size() == 0) {
// No longer have activities, so update location in
// LRU list.
- mService.updateLruProcessLocked(r.app, true, false);
+ mService.updateLruProcessLocked(r.app, oomAdj, false);
}
}
@@ -3513,12 +3578,23 @@
r.app = null;
r.nowVisible = false;
+ // If the activity is finishing, we need to wait on removing it
+ // from the list to give it a chance to do its cleanup. During
+ // that time it may make calls back with its token so we need to
+ // be able to find it on the list and so we don't want to remove
+ // it from the list yet. Otherwise, we can just immediately put
+ // it in the destroyed state since we are not removing it from the
+ // list.
if (r.finishing && !skipDestroy) {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYING: " + r
+ + " (destroy requested)");
r.state = ActivityState.DESTROYING;
Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
msg.obj = r;
mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
} else {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ + " (destroy skipped)");
r.state = ActivityState.DESTROYED;
}
} else {
@@ -3527,6 +3603,8 @@
removeActivityFromHistoryLocked(r);
removedFromHistory = true;
} else {
+ if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ + " (no app)");
r.state = ActivityState.DESTROYED;
}
}
@@ -3919,7 +3997,7 @@
if (r.app == null || r.app.thread == null) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
"Switch is destroying non-running " + r);
- destroyActivityLocked(r, true);
+ destroyActivityLocked(r, true, false);
} else if (r.state == ActivityState.PAUSING) {
// A little annoying: we are waiting for this activity to
// finish pausing. Let's not do anything now, but just
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 3968f66..9e597aa 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -61,6 +61,7 @@
int setAdj; // Last set OOM adjustment for this process
int curSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
+ int trimMemoryLevel; // Last selected memory trimming level
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
boolean foregroundServices; // Running any services that are foreground?
@@ -72,12 +73,14 @@
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
int lruSeq; // Sequence id for identifying LRU update cycles
CompatibilityInfo compat; // last used compatibility mode
+ IBinder.DeathRecipient deathRecipient; // Who is watching for the death.
ComponentName instrumentationClass;// class installed to instrument app
ApplicationInfo instrumentationInfo; // the application being instrumented
String instrumentationProfileFile; // where to save profiling
IInstrumentationWatcher instrumentationWatcher; // who is waiting
Bundle instrumentationArguments;// as given to us
ComponentName instrumentationResultClass;// copy of instrumentationClass
+ boolean usingWrapper; // Set to true when process was launched with a wrapper attached
BroadcastRecord curReceiver;// receiver currently running in the app
long lastWakeTime; // How long proc held wake lock at last check
long lastCpuTime; // How long proc has run CPU at last check
@@ -180,7 +183,8 @@
pw.print(" cur="); pw.print(curAdj);
pw.print(" set="); pw.println(setAdj);
pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
- pw.print(" setSchedGroup="); pw.println(setSchedGroup);
+ pw.print(" setSchedGroup="); pw.print(setSchedGroup);
+ pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
pw.print(" foregroundServices="); pw.print(foregroundServices);
pw.print(" forcingToForeground="); pw.println(forcingToForeground);
@@ -294,6 +298,13 @@
}
}
+ public void unlinkDeathRecipient() {
+ if (deathRecipient != null && thread != null) {
+ thread.asBinder().unlinkToDeath(deathRecipient, 0);
+ }
+ deathRecipient = null;
+ }
+
public String toShortString() {
if (shortStringName != null) {
return shortStringName;
@@ -304,8 +315,6 @@
}
void toShortString(StringBuilder sb) {
- sb.append(Integer.toHexString(System.identityHashCode(this)));
- sb.append(' ');
sb.append(pid);
sb.append(':');
sb.append(processName);
@@ -319,6 +328,8 @@
}
StringBuilder sb = new StringBuilder(128);
sb.append("ProcessRecord{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
toShortString(sb);
sb.append('}');
return stringName = sb.toString();
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 6e8f248..12c8ccf 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -63,7 +63,7 @@
private static final String TAG = "UsageStats";
// Current on-disk Parcel version
- private static final int VERSION = 1005;
+ private static final int VERSION = 1006;
private static final int CHECKIN_VERSION = 4;
@@ -145,6 +145,8 @@
final HashMap<String, TimeStats> mLaunchTimes
= new HashMap<String, TimeStats>();
int mLaunchCount;
+ final HashMap<String, Long> mLastResumeTimes
+ = new HashMap<String, Long>();
long mUsageTime;
long mPausedTime;
long mResumedTime;
@@ -160,20 +162,28 @@
if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
+ ", Usage time:" + mUsageTime);
- final int N = in.readInt();
- if (localLOGV) Slog.v(TAG, "Reading comps: " + N);
- for (int i=0; i<N; i++) {
+ final int numTimeStats = in.readInt();
+ if (localLOGV) Slog.v(TAG, "Reading comps: " + numTimeStats);
+ for (int i=0; i<numTimeStats; i++) {
String comp = in.readString();
if (localLOGV) Slog.v(TAG, "Component: " + comp);
TimeStats times = new TimeStats(in);
mLaunchTimes.put(comp, times);
}
+ final int numResumeTimes = in.readInt();
+ if (localLOGV) Slog.v(TAG, "Reading last resume times: " + numResumeTimes);
+ for (int i=0; i<numResumeTimes; i++) {
+ String comp = in.readString();
+ if (localLOGV) Slog.v(TAG, "Component: " + comp);
+ mLastResumeTimes.put(comp, in.readLong());
+ }
}
-
- void updateResume(boolean launched) {
+
+ void updateResume(String comp, boolean launched) {
if (launched) {
mLaunchCount ++;
}
+ mLastResumeTimes.put(comp, System.currentTimeMillis());
mResumedTime = SystemClock.elapsedRealtime();
}
@@ -203,20 +213,29 @@
void writeToParcel(Parcel out) {
out.writeInt(mLaunchCount);
out.writeLong(mUsageTime);
- final int N = mLaunchTimes.size();
- out.writeInt(N);
- if (N > 0) {
+ final int numTimeStats = mLaunchTimes.size();
+ out.writeInt(numTimeStats);
+ if (numTimeStats > 0) {
for (Map.Entry<String, TimeStats> ent : mLaunchTimes.entrySet()) {
out.writeString(ent.getKey());
TimeStats times = ent.getValue();
times.writeToParcel(out);
}
}
+ final int numResumeTimes = mLastResumeTimes.size();
+ out.writeInt(numResumeTimes);
+ if (numResumeTimes > 0) {
+ for (Map.Entry<String, Long> ent : mLastResumeTimes.entrySet()) {
+ out.writeString(ent.getKey());
+ out.writeLong(ent.getValue());
+ }
+ }
}
void clear() {
mLaunchTimes.clear();
mLaunchCount = 0;
+ mLastResumeTimes.clear();
mUsageTime = 0;
}
}
@@ -546,7 +565,7 @@
pus = new PkgUsageStatsExtended();
mStats.put(pkgName, pus);
}
- pus.updateResume(!samePackage);
+ pus.updateResume(mLastResumedComp, !samePackage);
if (!sameComp) {
pus.addLaunchCount(mLastResumedComp);
}
@@ -624,7 +643,8 @@
if (pus == null) {
return null;
}
- return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
+ return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime,
+ pus.mLastResumeTimes);
}
}
@@ -641,7 +661,8 @@
int i = 0;
for (String key: keys) {
PkgUsageStatsExtended pus = mStats.get(key);
- retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime);
+ retArr[i] = new PkgUsageStats(key, pus.mLaunchCount, pus.mUsageTime,
+ pus.mLastResumeTimes);
i++;
}
return retArr;
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 6bb7949..d7d4b03 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -221,8 +221,6 @@
}
public void interfaceLinkStateChanged(String iface, boolean up) {
- if (DEBUG) Log.d(TAG, "interfaceLinkStateChanged " + iface + ", " + up);
- interfaceStatusChanged(iface, up);
}
private boolean isUsb(String iface) {
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index c185012..05e95a7 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -41,6 +41,9 @@
import com.android.internal.net.VpnConfig;
import com.android.server.ConnectivityService.VpnCallback;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charsets;
import java.util.Arrays;
@@ -67,22 +70,14 @@
/**
* Protect a socket from routing changes by binding it to the given
- * interface. The socket IS closed by this method.
+ * interface. The socket is NOT closed by this method.
*
* @param socket The socket to be bound.
* @param name The name of the interface.
*/
public void protect(ParcelFileDescriptor socket, String interfaze) {
- try {
- mContext.enforceCallingPermission(VPN, "protect");
- jniProtect(socket.getFd(), interfaze);
- } finally {
- try {
- socket.close();
- } catch (Exception e) {
- // ignore
- }
- }
+ mContext.enforceCallingPermission(VPN, "protect");
+ jniProtect(socket.getFd(), interfaze);
}
/**
@@ -192,10 +187,15 @@
}
// Configure the interface. Abort if any of these steps fails.
- ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(
- jniConfigure(config.mtu, config.addresses, config.routes));
+ ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
try {
String interfaze = jniGetName(tun.getFd());
+ if (jniSetAddresses(interfaze, config.addresses) < 1) {
+ throw new IllegalArgumentException("At least one address must be specified");
+ }
+ if (config.routes != null) {
+ jniSetRoutes(interfaze, config.routes);
+ }
if (mInterface != null && !mInterface.equals(interfaze)) {
jniReset(mInterface);
}
@@ -222,18 +222,24 @@
}
// INetworkManagementEventObserver.Stub
- public void interfaceStatusChanged(String interfaze, boolean up) {
- }
-
- // INetworkManagementEventObserver.Stub
- public void interfaceLinkStateChanged(String interfaze, boolean up) {
- }
-
- // INetworkManagementEventObserver.Stub
public void interfaceAdded(String interfaze) {
}
// INetworkManagementEventObserver.Stub
+ public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
+ if (!up && mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.check(interfaze);
+ }
+ }
+
+ // INetworkManagementEventObserver.Stub
+ public synchronized void interfaceLinkStateChanged(String interfaze, boolean up) {
+ if (!up && mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.check(interfaze);
+ }
+ }
+
+ // INetworkManagementEventObserver.Stub
public synchronized void interfaceRemoved(String interfaze) {
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
mCallback.restore();
@@ -279,8 +285,10 @@
}
}
- private native int jniConfigure(int mtu, String addresses, String routes);
+ private native int jniCreate(int mtu);
private native String jniGetName(int tun);
+ private native int jniSetAddresses(String interfaze, String addresses);
+ private native int jniSetRoutes(String interfaze, String routes);
private native void jniReset(String interfaze);
private native int jniCheck(String interfaze);
private native void jniProtect(int socket, String interfaze);
@@ -323,11 +331,11 @@
*/
private class LegacyVpnRunner extends Thread {
private static final String TAG = "LegacyVpnRunner";
- private static final String NONE = "--";
private final VpnConfig mConfig;
private final String[] mDaemons;
private final String[][] mArguments;
+ private final String mOuterInterface;
private final LegacyVpnInfo mInfo;
private long mTimer = -1;
@@ -339,17 +347,27 @@
mArguments = new String[][] {racoon, mtpd};
mInfo = new LegacyVpnInfo();
+ // This is the interface which VPN is running on.
+ mOuterInterface = mConfig.interfaze;
+
// Legacy VPN is not a real package, so we use it to carry the key.
mInfo.key = mConfig.packagz;
mConfig.packagz = VpnConfig.LEGACY_VPN;
}
+ public void check(String interfaze) {
+ if (interfaze.equals(mOuterInterface)) {
+ Log.i(TAG, "Legacy VPN is going down with " + interfaze);
+ exit();
+ }
+ }
+
public void exit() {
// We assume that everything is reset after the daemons die.
+ interrupt();
for (String daemon : mDaemons) {
SystemProperties.set("ctl.stop", daemon);
}
- interrupt();
}
public LegacyVpnInfo getInfo() {
@@ -380,7 +398,7 @@
Thread.sleep(yield ? 200 : 1);
} else {
mInfo.state = LegacyVpnInfo.STATE_TIMEOUT;
- throw new IllegalStateException("time is up");
+ throw new IllegalStateException("Time is up");
}
}
@@ -404,12 +422,11 @@
}
}
- // Reset the properties.
- SystemProperties.set("vpn.dns", NONE);
- SystemProperties.set("vpn.via", NONE);
- while (!NONE.equals(SystemProperties.get("vpn.dns")) ||
- !NONE.equals(SystemProperties.get("vpn.via"))) {
- checkpoint(true);
+ // Clear the previous state.
+ File state = new File("/data/misc/vpn/state");
+ state.delete();
+ if (state.exists()) {
+ throw new IllegalStateException("Cannot delete the state");
}
// Check if we need to restart any of the daemons.
@@ -461,29 +478,34 @@
OutputStream out = socket.getOutputStream();
for (String argument : arguments) {
byte[] bytes = argument.getBytes(Charsets.UTF_8);
- if (bytes.length >= 0xFFFF) {
- throw new IllegalArgumentException("argument is too large");
+ if (bytes.length > 0xFFFF) {
+ throw new IllegalArgumentException("Argument is too large");
}
out.write(bytes.length >> 8);
out.write(bytes.length);
out.write(bytes);
checkpoint(false);
}
-
- // Send End-Of-Arguments.
- out.write(0xFF);
- out.write(0xFF);
out.flush();
+ socket.shutdownOutput();
+
+ // Wait for End-of-File.
+ InputStream in = socket.getInputStream();
+ while (true) {
+ try {
+ if (in.read() == -1) {
+ break;
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ checkpoint(true);
+ }
socket.close();
}
- // Now here is the beast from the old days. We check few
- // properties to figure out the current status. Ideally we
- // can read things back from the sockets and get rid of the
- // properties, but we have no time...
- while (NONE.equals(SystemProperties.get("vpn.dns")) ||
- NONE.equals(SystemProperties.get("vpn.via"))) {
-
+ // Wait for the daemons to create the new state.
+ while (!state.exists()) {
// Check if a running daemon is dead.
for (int i = 0; i < mDaemons.length; ++i) {
String daemon = mDaemons[i];
@@ -495,20 +517,45 @@
checkpoint(true);
}
- // Now we are connected. Get the interface.
- mConfig.interfaze = SystemProperties.get("vpn.via");
+ // Now we are connected. Read and parse the new state.
+ byte[] buffer = new byte[(int) state.length()];
+ if (new FileInputStream(state).read(buffer) != buffer.length) {
+ throw new IllegalStateException("Cannot read the state");
+ }
+ String[] parameters = new String(buffer, Charsets.UTF_8).split("\n", -1);
+ if (parameters.length != 6) {
+ throw new IllegalStateException("Cannot parse the state");
+ }
- // Get the DNS servers if they are not set in config.
+ // Set the interface and the addresses in the config.
+ mConfig.interfaze = parameters[0].trim();
+ mConfig.addresses = parameters[1].trim();
+
+ // Set the routes if they are not set in the config.
+ if (mConfig.routes == null || mConfig.routes.isEmpty()) {
+ mConfig.routes = parameters[2].trim();
+ }
+
+ // Set the DNS servers if they are not set in the config.
if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
- String dnsServers = SystemProperties.get("vpn.dns").trim();
+ String dnsServers = parameters[3].trim();
if (!dnsServers.isEmpty()) {
mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
}
}
- // TODO: support search domains from ISAKMP mode config.
+ // Set the search domains if they are not set in the config.
+ if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) {
+ String searchDomains = parameters[4].trim();
+ if (!searchDomains.isEmpty()) {
+ mConfig.searchDomains = Arrays.asList(searchDomains.split(" "));
+ }
+ }
- // The final step must be synchronized.
+ // Set the routes.
+ jniSetRoutes(mConfig.interfaze, mConfig.routes);
+
+ // Here is the last step and it must be done synchronously.
synchronized (Vpn.this) {
// Check if the thread is interrupted while we are waiting.
checkpoint(false);
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index d23d0f4..435c394 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -22,10 +22,11 @@
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
+import static android.net.ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.*;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -42,7 +43,7 @@
import static android.net.NetworkPolicyManager.isUidValidForPolicy;
import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
import static android.net.NetworkTemplate.MATCH_MOBILE_4G;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
@@ -174,10 +175,12 @@
/** Current policy for network templates. */
private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
+ /** Current derived network rules for ifaces. */
+ private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap();
/** Current policy for each UID. */
private SparseIntArray mUidPolicy = new SparseIntArray();
- /** Current derived network rules for each UID. */
+ /** Current derived rules for each UID. */
private SparseIntArray mUidRules = new SparseIntArray();
/** Set of ifaces that are metered. */
@@ -199,8 +202,6 @@
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
- // TODO: watch for package added broadcast to catch new UIDs.
-
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
IPowerManager powerManager, INetworkStatsService networkStats,
INetworkManagementService networkManagement) {
@@ -242,7 +243,6 @@
synchronized (mRulesLock) {
// read policy from disk
readPolicyLocked();
- updateNotificationsLocked();
}
updateScreenOn();
@@ -268,9 +268,12 @@
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
- // listen for uid removal to clean policy
- final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
- mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
+ // listen for package/uid changes to update policy
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(ACTION_UID_REMOVED);
+ packageFilter.addDataScheme("package");
+ mContext.registerReceiver(mPackageReceiver, packageFilter, null, mHandler);
// listen for stats update events
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
@@ -331,17 +334,28 @@
}
};
- private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // on background handler thread, and UID_REMOVED is protected
- // broadcast.
+ // on background handler thread, and PACKAGE_ADDED and UID_REMOVED
+ // are protected broadcasts.
+
+ final String action = intent.getAction();
final int uid = intent.getIntExtra(EXTRA_UID, 0);
synchronized (mRulesLock) {
- // remove any policy and update rules to clean up
- mUidPolicy.delete(uid);
- updateRulesForUidLocked(uid);
- writePolicyLocked();
+ if (ACTION_PACKAGE_ADDED.equals(action)) {
+ // update rules for UID, since it might be subject to
+ // global background data policy.
+ if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid);
+ updateRulesForUidLocked(uid);
+
+ } else if (ACTION_UID_REMOVED.equals(action)) {
+ // remove any policy and update rules to clean up.
+ if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid);
+ mUidPolicy.delete(uid);
+ updateRulesForUidLocked(uid);
+ writePolicyLocked();
+ }
}
}
};
@@ -396,8 +410,8 @@
// TODO: when switching to kernel notifications, compute next future
// cycle boundary to recompute notifications.
- // examine stats for each policy defined
- for (NetworkPolicy policy : mNetworkPolicy) {
+ // examine stats for each active policy
+ for (NetworkPolicy policy : mNetworkRules.keySet()) {
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
@@ -405,7 +419,8 @@
try {
final NetworkStats stats = mNetworkStats.getSummaryForNetwork(
policy.template, start, end);
- total = stats.rx[0] + stats.tx[0];
+ final NetworkStats.Entry entry = stats.getValues(0, null);
+ total = entry.rxBytes + entry.txBytes;
} catch (RemoteException e) {
Slog.w(TAG, "problem reading summary for template " + policy.template);
continue;
@@ -423,6 +438,15 @@
cancelNotification(policy, TYPE_WARNING);
}
}
+
+ }
+
+ // clear notifications for non-active policies
+ for (NetworkPolicy policy : mNetworkPolicy) {
+ if (!mNetworkRules.containsKey(policy)) {
+ cancelNotification(policy, TYPE_WARNING);
+ cancelNotification(policy, TYPE_LIMIT);
+ }
}
}
@@ -530,7 +554,8 @@
// permission above.
synchronized (mRulesLock) {
ensureActiveMobilePolicyLocked();
- updateIfacesLocked();
+ updateNetworkRulesLocked();
+ updateNotificationsLocked();
}
}
};
@@ -540,7 +565,7 @@
* {@link NetworkPolicy} that need to be enforced. When matches found, set
* remaining quota based on usage cycle and historical stats.
*/
- private void updateIfacesLocked() {
+ private void updateNetworkRulesLocked() {
if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
final NetworkState[] states;
@@ -564,7 +589,7 @@
}
// build list of rules and ifaces to enforce them against
- final HashMap<NetworkPolicy, String[]> rules = Maps.newHashMap();
+ mNetworkRules.clear();
final ArrayList<String> ifaceList = Lists.newArrayList();
for (NetworkPolicy policy : mNetworkPolicy) {
@@ -579,7 +604,7 @@
if (ifaceList.size() > 0) {
final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
- rules.put(policy, ifaces);
+ mNetworkRules.put(policy, ifaces);
}
}
@@ -595,8 +620,8 @@
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
- for (NetworkPolicy policy : rules.keySet()) {
- final String[] ifaces = rules.get(policy);
+ for (NetworkPolicy policy : mNetworkRules.keySet()) {
+ final String[] ifaces = mNetworkRules.get(policy);
final long start = computeLastCycleBoundary(currentTime, policy);
final long end = currentTime;
@@ -605,7 +630,8 @@
final long total;
try {
stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end);
- total = stats.rx[0] + stats.tx[0];
+ final NetworkStats.Entry entry = stats.getValues(0, null);
+ total = entry.rxBytes + entry.txBytes;
} catch (RemoteException e) {
Slog.w(TAG, "problem reading summary for template " + policy.template);
continue;
@@ -668,17 +694,17 @@
if (!mobileDefined) {
Slog.i(TAG, "no policy for active mobile network; generating default policy");
- // default mobile policy has combined 4GB warning, and assume usage
- // cycle starts today today.
+ // build default mobile policy, and assume usage cycle starts today
+ final long warningBytes = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_networkPolicyDefaultWarning)
+ * MB_IN_BYTES;
- // TODO: move this policy definition to overlay or secure setting
final Time time = new Time(Time.TIMEZONE_UTC);
time.setToNow();
final int cycleDay = time.monthDay;
- final NetworkTemplate template = new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
- mNetworkPolicy.add(
- new NetworkPolicy(template, cycleDay, 4 * GB_IN_BYTES, LIMIT_DISABLED));
+ final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
+ mNetworkPolicy.add(new NetworkPolicy(template, cycleDay, warningBytes, LIMIT_DISABLED));
writePolicyLocked();
}
}
@@ -857,7 +883,7 @@
mNetworkPolicy.add(policy);
}
- updateIfacesLocked();
+ updateNetworkRulesLocked();
updateNotificationsLocked();
writePolicyLocked();
}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index b6834f6..6cc01f4 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -60,6 +60,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
@@ -73,11 +74,12 @@
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -111,6 +113,8 @@
private final TrustedTime mTime;
private final NetworkStatsSettings mSettings;
+ private final PowerManager.WakeLock mWakeLock;
+
private IConnectivityManager mConnManager;
// @VisibleForTesting
@@ -190,6 +194,10 @@
mTime = checkNotNull(time, "missing TrustedTime");
mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
+ final PowerManager powerManager = (PowerManager) context.getSystemService(
+ Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
@@ -313,22 +321,29 @@
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
synchronized (mStatsLock) {
- long rx = 0;
- long tx = 0;
- long[] networkTotal = new long[2];
+ // use system clock to be externally consistent
+ final long now = System.currentTimeMillis();
+
+ final NetworkStats stats = new NetworkStats(end - start, 1);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ NetworkStatsHistory.Entry historyEntry = null;
// combine total from all interfaces that match template
for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
if (templateMatches(template, ident)) {
final NetworkStatsHistory history = mNetworkStats.get(ident);
- networkTotal = history.getTotalData(start, end, networkTotal);
- rx += networkTotal[0];
- tx += networkTotal[1];
+ historyEntry = history.getValues(start, end, now, historyEntry);
+
+ entry.iface = IFACE_ALL;
+ entry.uid = UID_ALL;
+ entry.tag = TAG_NONE;
+ entry.rxBytes = historyEntry.rxBytes;
+ entry.txBytes = historyEntry.txBytes;
+
+ stats.combineValues(entry);
}
}
- final NetworkStats stats = new NetworkStats(end - start, 1);
- stats.addEntry(IFACE_ALL, UID_ALL, TAG_NONE, rx, tx);
return stats;
}
}
@@ -341,8 +356,12 @@
synchronized (mStatsLock) {
ensureUidStatsLoadedLocked();
+ // use system clock to be externally consistent
+ final long now = System.currentTimeMillis();
+
final NetworkStats stats = new NetworkStats(end - start, 24);
- long[] total = new long[2];
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ NetworkStatsHistory.Entry historyEntry = null;
for (NetworkIdentitySet ident : mUidStats.keySet()) {
if (templateMatches(template, ident)) {
@@ -356,11 +375,16 @@
// other tags when requested.
if (tag == TAG_NONE || includeTags) {
final NetworkStatsHistory history = uidStats.valueAt(i);
- total = history.getTotalData(start, end, total);
- final long rx = total[0];
- final long tx = total[1];
- if (rx > 0 || tx > 0) {
- stats.combineEntry(IFACE_ALL, uid, tag, rx, tx);
+ historyEntry = history.getValues(start, end, now, historyEntry);
+
+ entry.iface = IFACE_ALL;
+ entry.uid = uid;
+ entry.tag = tag;
+ entry.rxBytes = historyEntry.rxBytes;
+ entry.txBytes = historyEntry.txBytes;
+
+ if (entry.rxBytes > 0 || entry.txBytes > 0) {
+ stats.combineValues(entry);
}
}
}
@@ -391,7 +415,12 @@
// on background handler thread, and verified CONNECTIVITY_INTERNAL
// permission above.
synchronized (mStatsLock) {
- updateIfacesLocked();
+ mWakeLock.acquire();
+ try {
+ updateIfacesLocked();
+ } finally {
+ mWakeLock.release();
+ }
}
}
};
@@ -402,8 +431,12 @@
// on background handler thread, and verified UPDATE_DEVICE_STATS
// permission above.
synchronized (mStatsLock) {
- // TODO: acquire wakelock while performing poll
- performPollLocked(true, false);
+ mWakeLock.acquire();
+ try {
+ performPollLocked(true, false);
+ } finally {
+ mWakeLock.release();
+ }
}
}
};
@@ -415,7 +448,13 @@
// broadcast.
final int uid = intent.getIntExtra(EXTRA_UID, 0);
synchronized (mStatsLock) {
- removeUidLocked(uid);
+ // TODO: perform one last stats poll for UID
+ mWakeLock.acquire();
+ try {
+ removeUidLocked(uid);
+ } finally {
+ mWakeLock.release();
+ }
}
}
};
@@ -512,10 +551,13 @@
final NetworkStats persistDelta = computeStatsDelta(
mLastPersistNetworkSnapshot, networkSnapshot);
final long persistThreshold = mSettings.getPersistThreshold();
+
+ NetworkStats.Entry entry = null;
for (String iface : persistDelta.getUniqueIfaces()) {
final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE);
- if (forcePersist || persistDelta.rx[index] > persistThreshold
- || persistDelta.tx[index] > persistThreshold) {
+ entry = persistDelta.getValues(index, entry);
+ if (forcePersist || entry.rxBytes > persistThreshold
+ || entry.txBytes > persistThreshold) {
writeNetworkStatsLocked();
if (mUidStatsLoaded) {
writeUidStatsLocked();
@@ -538,20 +580,19 @@
final HashSet<String> unknownIface = Sets.newHashSet();
final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot);
- final long timeStart = currentTime - delta.elapsedRealtime;
- for (int i = 0; i < delta.size; i++) {
- final String iface = delta.iface[i];
- final NetworkIdentitySet ident = mActiveIfaces.get(iface);
+ final long timeStart = currentTime - delta.getElapsedRealtime();
+
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < delta.size(); i++) {
+ entry = delta.getValues(i, entry);
+ final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
if (ident == null) {
- unknownIface.add(iface);
+ unknownIface.add(entry.iface);
continue;
}
- final long rx = delta.rx[i];
- final long tx = delta.tx[i];
-
final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident);
- history.recordData(timeStart, currentTime, rx, tx);
+ history.recordData(timeStart, currentTime, entry.rxBytes, entry.txBytes);
}
// trim any history beyond max
@@ -574,22 +615,19 @@
ensureUidStatsLoadedLocked();
final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot);
- final long timeStart = currentTime - delta.elapsedRealtime;
+ final long timeStart = currentTime - delta.getElapsedRealtime();
- for (int i = 0; i < delta.size; i++) {
- final String iface = delta.iface[i];
- final NetworkIdentitySet ident = mActiveIfaces.get(iface);
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < delta.size(); i++) {
+ entry = delta.getValues(i, entry);
+ final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
if (ident == null) {
continue;
}
- final int uid = delta.uid[i];
- final int tag = delta.tag[i];
- final long rx = delta.rx[i];
- final long tx = delta.tx[i];
-
- final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid, tag);
- history.recordData(timeStart, currentTime, rx, tx);
+ final NetworkStatsHistory history = findOrCreateUidStatsLocked(
+ ident, entry.uid, entry.tag);
+ history.recordData(timeStart, currentTime, entry.rxBytes, entry.txBytes);
}
// trim any history beyond max
@@ -651,7 +689,7 @@
NetworkStatsHistory updated = null;
if (existing == null) {
updated = new NetworkStatsHistory(bucketDuration, 10);
- } else if (existing.bucketDuration != bucketDuration) {
+ } else if (existing.getBucketDuration() != bucketDuration) {
updated = new NetworkStatsHistory(
bucketDuration, estimateResizeBuckets(existing, bucketDuration));
updated.recordEntireHistory(existing);
@@ -683,7 +721,7 @@
NetworkStatsHistory updated = null;
if (existing == null) {
updated = new NetworkStatsHistory(bucketDuration, 10);
- } else if (existing.bucketDuration != bucketDuration) {
+ } else if (existing.getBucketDuration() != bucketDuration) {
updated = new NetworkStatsHistory(
bucketDuration, estimateResizeBuckets(existing, bucketDuration));
updated.recordEntireHistory(existing);
@@ -703,10 +741,9 @@
// clear any existing stats and read from disk
mNetworkStats.clear();
- FileInputStream fis = null;
+ DataInputStream in = null;
try {
- fis = mNetworkFile.openRead();
- final DataInputStream in = new DataInputStream(fis);
+ in = new DataInputStream(new BufferedInputStream(mNetworkFile.openRead()));
// verify file magic header intact
final int magic = in.readInt();
@@ -735,7 +772,7 @@
} catch (IOException e) {
Slog.e(TAG, "problem reading network stats", e);
} finally {
- IoUtils.closeQuietly(fis);
+ IoUtils.closeQuietly(in);
}
}
@@ -752,10 +789,9 @@
// clear any existing stats and read from disk
mUidStats.clear();
- FileInputStream fis = null;
+ DataInputStream in = null;
try {
- fis = mUidFile.openRead();
- final DataInputStream in = new DataInputStream(fis);
+ in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
// verify file magic header intact
final int magic = in.readInt();
@@ -810,7 +846,7 @@
} catch (IOException e) {
Slog.e(TAG, "problem reading uid stats", e);
} finally {
- IoUtils.closeQuietly(fis);
+ IoUtils.closeQuietly(in);
}
}
@@ -822,7 +858,7 @@
FileOutputStream fos = null;
try {
fos = mNetworkFile.startWrite();
- final DataOutputStream out = new DataOutputStream(fos);
+ final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
out.writeInt(FILE_MAGIC);
out.writeInt(VERSION_NETWORK_INIT);
@@ -834,6 +870,7 @@
history.writeToStream(out);
}
+ out.flush();
mNetworkFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
@@ -855,7 +892,7 @@
FileOutputStream fos = null;
try {
fos = mUidFile.startWrite();
- final DataOutputStream out = new DataOutputStream(fos);
+ final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
out.writeInt(FILE_MAGIC);
out.writeInt(VERSION_UID_WITH_TAG);
@@ -879,6 +916,7 @@
}
}
+ out.flush();
mUidFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
@@ -1003,7 +1041,7 @@
}
private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
- return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration);
+ return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration);
}
// @VisibleForTesting
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index ea5d26b..d6a15e6 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -778,16 +778,7 @@
mSeparateProcesses = null;
}
- Installer installer = new Installer();
- // Little hacky thing to check if installd is here, to determine
- // whether we are running on the simulator and thus need to take
- // care of building the /data file structure ourself.
- // (apparently the sim now has a working installer)
- if (installer.ping() && Process.supportsProcesses()) {
- mInstaller = installer;
- } else {
- mInstaller = null;
- }
+ mInstaller = new Installer();
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
@@ -806,17 +797,6 @@
mUserManager = new UserManager(mInstaller, mUserAppDataDir);
- if (mInstaller == null) {
- // Make sure these dirs exist, when we are running in
- // the simulator.
- // Make a wide-open directory for random misc stuff.
- File miscDir = new File(dataDir, "misc");
- miscDir.mkdirs();
- mAppDataDir.mkdirs();
- mUserAppDataDir.mkdirs();
- mDrmAppPrivateInstallDir.mkdirs();
- }
-
readPermissions();
mRestoredSettings = mSettings.readLPw();
@@ -838,104 +818,102 @@
mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
mDalvikCacheDir = new File(dataDir, "dalvik-cache");
- if (mInstaller != null) {
- boolean didDexOpt = false;
+ boolean didDexOpt = false;
- /**
- * Out of paranoia, ensure that everything in the boot class
- * path has been dexed.
- */
- String bootClassPath = System.getProperty("java.boot.class.path");
- if (bootClassPath != null) {
- String[] paths = splitString(bootClassPath, ':');
- for (int i=0; i<paths.length; i++) {
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
- libFiles.add(paths[i]);
- mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Boot class path not found: " + paths[i]);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
+ /**
+ * Out of paranoia, ensure that everything in the boot class
+ * path has been dexed.
+ */
+ String bootClassPath = System.getProperty("java.boot.class.path");
+ if (bootClassPath != null) {
+ String[] paths = splitString(bootClassPath, ':');
+ for (int i=0; i<paths.length; i++) {
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
+ libFiles.add(paths[i]);
+ mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
+ didDexOpt = true;
}
- }
- } else {
- Slog.w(TAG, "No BOOTCLASSPATH found!");
- }
-
- /**
- * Also ensure all external libraries have had dexopt run on them.
- */
- if (mSharedLibraries.size() > 0) {
- Iterator<String> libs = mSharedLibraries.values().iterator();
- while (libs.hasNext()) {
- String lib = libs.next();
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
- libFiles.add(lib);
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Library not found: " + lib);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading library: " + lib, e);
- }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Boot class path not found: " + paths[i]);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
}
}
+ } else {
+ Slog.w(TAG, "No BOOTCLASSPATH found!");
+ }
- // Gross hack for now: we know this file doesn't contain any
- // code, so don't dexopt it to avoid the resulting log spew.
- libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
-
- /**
- * And there are a number of commands implemented in Java, which
- * we currently need to do the dexopt on so that they can be
- * run from a non-root shell.
- */
- String[] frameworkFiles = mFrameworkDir.list();
- if (frameworkFiles != null) {
- for (int i=0; i<frameworkFiles.length; i++) {
- File libPath = new File(mFrameworkDir, frameworkFiles[i]);
- String path = libPath.getPath();
- // Skip the file if we alrady did it.
- if (libFiles.contains(path)) {
- continue;
+ /**
+ * Also ensure all external libraries have had dexopt run on them.
+ */
+ if (mSharedLibraries.size() > 0) {
+ Iterator<String> libs = mSharedLibraries.values().iterator();
+ while (libs.hasNext()) {
+ String lib = libs.next();
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
+ libFiles.add(lib);
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
+ didDexOpt = true;
}
- // Skip the file if it is not a type we want to dexopt.
- if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
- continue;
- }
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(path)) {
- mInstaller.dexopt(path, Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Jar not found: " + path);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading jar: " + path, e);
- }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Library not found: " + lib);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading library: " + lib, e);
}
}
+ }
- if (didDexOpt) {
- // If we had to do a dexopt of one of the previous
- // things, then something on the system has changed.
- // Consider this significant, and wipe away all other
- // existing dexopt files to ensure we don't leave any
- // dangling around.
- String[] files = mDalvikCacheDir.list();
- if (files != null) {
- for (int i=0; i<files.length; i++) {
- String fn = files[i];
- if (fn.startsWith("data@app@")
- || fn.startsWith("data@app-private@")) {
- Slog.i(TAG, "Pruning dalvik file: " + fn);
- (new File(mDalvikCacheDir, fn)).delete();
- }
+ // Gross hack for now: we know this file doesn't contain any
+ // code, so don't dexopt it to avoid the resulting log spew.
+ libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
+
+ /**
+ * And there are a number of commands implemented in Java, which
+ * we currently need to do the dexopt on so that they can be
+ * run from a non-root shell.
+ */
+ String[] frameworkFiles = mFrameworkDir.list();
+ if (frameworkFiles != null) {
+ for (int i=0; i<frameworkFiles.length; i++) {
+ File libPath = new File(mFrameworkDir, frameworkFiles[i]);
+ String path = libPath.getPath();
+ // Skip the file if we alrady did it.
+ if (libFiles.contains(path)) {
+ continue;
+ }
+ // Skip the file if it is not a type we want to dexopt.
+ if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
+ continue;
+ }
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(path)) {
+ mInstaller.dexopt(path, Process.SYSTEM_UID, true);
+ didDexOpt = true;
+ }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Jar not found: " + path);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading jar: " + path, e);
+ }
+ }
+ }
+
+ if (didDexOpt) {
+ // If we had to do a dexopt of one of the previous
+ // things, then something on the system has changed.
+ // Consider this significant, and wipe away all other
+ // existing dexopt files to ensure we don't leave any
+ // dangling around.
+ String[] files = mDalvikCacheDir.list();
+ if (files != null) {
+ for (int i=0; i<files.length; i++) {
+ String fn = files[i];
+ if (fn.startsWith("data@app@")
+ || fn.startsWith("data@app-private@")) {
+ Slog.i(TAG, "Pruning dalvik file: " + fn);
+ (new File(mDalvikCacheDir, fn)).delete();
}
}
}
@@ -965,11 +943,9 @@
scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
- if (mInstaller != null) {
- if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
- mInstaller.moveFiles();
- }
-
+ if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
+ mInstaller.moveFiles();
+
// Prune any system packages that no longer exist.
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
@@ -981,19 +957,12 @@
String msg = "System package " + ps.name
+ " no longer exists; wiping its data";
reportSettingsProblem(Log.WARN, msg);
- if (mInstaller != null) {
- mInstaller.remove(ps.name, 0);
- mUserManager.removePackageForAllUsers(ps.name);
- }
+ mInstaller.remove(ps.name, 0);
+ mUserManager.removePackageForAllUsers(ps.name);
}
}
mAppInstallDir = new File(dataDir, "app");
- if (mInstaller == null) {
- // Make sure these dirs exist, when we are running in
- // the simulator.
- mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
- }
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
@@ -1067,19 +1036,12 @@
void cleanupInstallFailedPackage(PackageSetting ps) {
Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
- if (mInstaller != null) {
- int retCode = mInstaller.remove(ps.name, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data directory for package: "
- + ps.name + ", retcode=" + retCode);
- } else {
- mUserManager.removePackageForAllUsers(ps.name);
- }
+ int retCode = mInstaller.remove(ps.name, 0);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove app data directory for package: "
+ + ps.name + ", retcode=" + retCode);
} else {
- //for emulator
- PackageParser.Package pkg = mPackages.get(ps.name);
- File dataDir = new File(pkg.applicationInfo.dataDir);
- dataDir.delete();
+ mUserManager.removePackageForAllUsers(ps.name);
}
if (ps.codePath != null) {
if (!ps.codePath.delete()) {
@@ -1562,12 +1524,10 @@
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- if (mInstaller != null) {
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
- }
- } //end if mInstaller
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
+ }
if (observer != null) {
try {
observer.onRemoveCompleted(null, (retCode >= 0));
@@ -1587,11 +1547,9 @@
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- if (mInstaller != null) {
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
- }
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
}
if(pi != null) {
try {
@@ -2850,7 +2808,7 @@
private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
boolean performed = false;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0 && mInstaller != null) {
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
String path = pkg.mScanPath;
int ret = 0;
try {
@@ -3235,42 +3193,39 @@
mOutPermissions[1] = 0;
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
- // If we have mismatched owners for the data path, we have a
- // problem (unless we're running in the simulator.)
- if (mOutPermissions[1] != pkg.applicationInfo.uid && Process.supportsProcesses()) {
+ // If we have mismatched owners for the data path, we have a problem.
+ if (mOutPermissions[1] != pkg.applicationInfo.uid) {
boolean recovered = false;
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
- if (mInstaller != null) {
- int ret = mInstaller.remove(pkgName, 0);
- if (ret >= 0) {
- // TODO: Kill the processes first
- // Remove the data directories for all users
- mUserManager.removePackageForAllUsers(pkgName);
- // Old data gone!
- String msg = "System package " + pkg.packageName
- + " has changed from uid: "
- + mOutPermissions[1] + " to "
- + pkg.applicationInfo.uid + "; old data erased";
- reportSettingsProblem(Log.WARN, msg);
- recovered = true;
+ int ret = mInstaller.remove(pkgName, 0);
+ if (ret >= 0) {
+ // TODO: Kill the processes first
+ // Remove the data directories for all users
+ mUserManager.removePackageForAllUsers(pkgName);
+ // Old data gone!
+ String msg = "System package " + pkg.packageName
+ + " has changed from uid: "
+ + mOutPermissions[1] + " to "
+ + pkg.applicationInfo.uid + "; old data erased";
+ reportSettingsProblem(Log.WARN, msg);
+ recovered = true;
- // And now re-install the app.
- ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- if (ret == -1) {
- // Ack should not happen!
- msg = "System package " + pkg.packageName
- + " could not have data directory re-created after delete.";
- reportSettingsProblem(Log.WARN, msg);
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
- // Create data directories for all users
- mUserManager.installPackageForAllUsers(pkgName,
- pkg.applicationInfo.uid);
+ // And now re-install the app.
+ ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
+ pkg.applicationInfo.uid);
+ if (ret == -1) {
+ // Ack should not happen!
+ msg = "System package " + pkg.packageName
+ + " could not have data directory re-created after delete.";
+ reportSettingsProblem(Log.WARN, msg);
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return null;
}
+ // Create data directories for all users
+ mUserManager.installPackageForAllUsers(pkgName,
+ pkg.applicationInfo.uid);
}
if (!recovered) {
mHasSystemUidErrors = true;
@@ -3303,25 +3258,16 @@
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
- if (mInstaller != null) {
- int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- if (ret < 0) {
- // Error from installer
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
- // Create data directories for all users
- mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
- } else {
- dataPath.mkdirs();
- if (dataPath.exists()) {
- FileUtils.setPermissions(
- dataPath.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
- pkg.applicationInfo.uid, pkg.applicationInfo.uid);
- }
+ int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
+ pkg.applicationInfo.uid);
+ if (ret < 0) {
+ // Error from installer
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return null;
}
+ // Create data directories for all users
+ mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
+
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
@@ -3352,65 +3298,62 @@
pkgSetting.uidError = uidError;
}
- // If we're running in the simulator, we don't need to unpack anything.
- if (mInstaller != null) {
- String path = scanFile.getPath();
- /* Note: We don't want to unpack the native binaries for
- * system applications, unless they have been updated
- * (the binaries are already under /system/lib).
- * Also, don't unpack libs for apps on the external card
- * since they should have their libraries in the ASEC
- * container already.
- *
- * In other words, we're going to unpack the binaries
- * only for non-system apps and system app upgrades.
- */
- if (pkg.applicationInfo.nativeLibraryDir != null) {
- try {
- final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- final String dataPathString = dataPath.getCanonicalFile().getPath();
+ String path = scanFile.getPath();
+ /* Note: We don't want to unpack the native binaries for
+ * system applications, unless they have been updated
+ * (the binaries are already under /system/lib).
+ * Also, don't unpack libs for apps on the external card
+ * since they should have their libraries in the ASEC
+ * container already.
+ *
+ * In other words, we're going to unpack the binaries
+ * only for non-system apps and system app upgrades.
+ */
+ if (pkg.applicationInfo.nativeLibraryDir != null) {
+ try {
+ final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+ final String dataPathString = dataPath.getCanonicalFile().getPath();
- if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
- /*
- * Upgrading from a previous version of the OS sometimes
- * leaves native libraries in the /data/data/<app>/lib
- * directory for system apps even when they shouldn't be.
- * Recent changes in the JNI library search path
- * necessitates we remove those to match previous behavior.
- */
- if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
- Log.i(TAG, "removed obsolete native libraries for system package "
- + path);
- }
- } else if (nativeLibraryDir.getCanonicalFile().getParent()
- .equals(dataPathString)) {
- /*
- * If this is an internal application or our
- * nativeLibraryPath points to our data directory, unpack
- * the libraries. The native library path pointing to the
- * data directory for an application in an ASEC container
- * can happen for older apps that existed before an OTA to
- * Gingerbread.
- */
- Slog.i(TAG, "Unpacking native libraries for " + path);
- mInstaller.unlinkNativeLibraryDirectory(dataPathString);
- NativeLibraryHelper.copyNativeBinariesLI(scanFile, nativeLibraryDir);
- } else {
- Slog.i(TAG, "Linking native library dir for " + path);
- mInstaller.linkNativeLibraryDirectory(dataPathString,
- pkg.applicationInfo.nativeLibraryDir);
+ if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
+ /*
+ * Upgrading from a previous version of the OS sometimes
+ * leaves native libraries in the /data/data/<app>/lib
+ * directory for system apps even when they shouldn't be.
+ * Recent changes in the JNI library search path
+ * necessitates we remove those to match previous behavior.
+ */
+ if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
+ Log.i(TAG, "removed obsolete native libraries for system package "
+ + path);
}
- } catch (IOException ioe) {
- Log.e(TAG, "Unable to get canonical file " + ioe.toString());
+ } else if (nativeLibraryDir.getCanonicalFile().getParent()
+ .equals(dataPathString)) {
+ /*
+ * If this is an internal application or our
+ * nativeLibraryPath points to our data directory, unpack
+ * the libraries. The native library path pointing to the
+ * data directory for an application in an ASEC container
+ * can happen for older apps that existed before an OTA to
+ * Gingerbread.
+ */
+ Slog.i(TAG, "Unpacking native libraries for " + path);
+ mInstaller.unlinkNativeLibraryDirectory(dataPathString);
+ NativeLibraryHelper.copyNativeBinariesLI(scanFile, nativeLibraryDir);
+ } else {
+ Slog.i(TAG, "Linking native library dir for " + path);
+ mInstaller.linkNativeLibraryDirectory(dataPathString,
+ pkg.applicationInfo.nativeLibraryDir);
}
+ } catch (IOException ioe) {
+ Log.e(TAG, "Unable to get canonical file " + ioe.toString());
}
- pkg.mScanPath = path;
+ }
+ pkg.mScanPath = path;
- if ((scanMode&SCAN_NO_DEX) == 0) {
- if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
- mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
- return null;
- }
+ if ((scanMode&SCAN_NO_DEX) == 0) {
+ if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
+ mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
+ return null;
}
}
@@ -5434,7 +5377,7 @@
void cleanUpResourcesLI() {
String sourceDir = getCodePath();
- if (cleanUp() && mInstaller != null) {
+ if (cleanUp()) {
int retCode = mInstaller.rmdex(sourceDir);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
@@ -5662,14 +5605,12 @@
void cleanUpResourcesLI() {
String sourceFile = getCodePath();
// Remove dex file
- if (mInstaller != null) {
- int retCode = mInstaller.rmdex(sourceFile);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location "
- + sourceFile.toString() + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
+ int retCode = mInstaller.rmdex(sourceFile);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location "
+ + sourceFile.toString() + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
}
cleanUp();
}
@@ -6077,9 +6018,7 @@
}
if((res.returnCode = setPermissionsLI(newPackage))
!= PackageManager.INSTALL_SUCCEEDED) {
- if (mInstaller != null) {
- mInstaller.rmdex(newPackage.mScanPath);
- }
+ mInstaller.rmdex(newPackage.mScanPath);
return;
} else {
Log.d(TAG, "New package installed in " + newPackage.mPath);
@@ -6207,15 +6146,8 @@
} finally {
//TODO clean up the extracted public files
}
- if (mInstaller != null) {
- retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
- newPackage.applicationInfo.uid);
- } else {
- final int filePermissions =
- FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
- retCode = FileUtils.setPermissions(newPackage.mPath, filePermissions, -1,
- newPackage.applicationInfo.uid);
- }
+ retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
+ newPackage.applicationInfo.uid);
} else {
// The permissions on the resource file was set when it was copied for
// non forward locked apps and apps on sdcard
@@ -6478,25 +6410,14 @@
deletedPs = mSettings.mPackages.get(packageName);
}
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
- if (mInstaller != null) {
- int retCode = mInstaller.remove(packageName, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
- + packageName + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- } else {
- // TODO: Kill the processes first
- mUserManager.removePackageForAllUsers(packageName);
- }
+ int retCode = mInstaller.remove(packageName, 0);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
+ + packageName + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
} else {
- // for simulator
- File dataDir;
- // reader
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- dataDir = new File(pkg.applicationInfo.dataDir);
- }
- dataDir.delete();
+ // TODO: Kill the processes first
+ mUserManager.removePackageForAllUsers(packageName);
}
schedulePackageCleaning(packageName);
}
@@ -6745,13 +6666,11 @@
return false;
}
}
- if (mInstaller != null) {
- int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
- + packageName);
- return false;
- }
+ int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ + packageName);
+ return false;
}
return true;
}
@@ -6797,13 +6716,11 @@
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- if (mInstaller != null) {
- int retCode = mInstaller.deleteCacheFiles(packageName);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
- + packageName);
- return false;
- }
+ int retCode = mInstaller.deleteCacheFiles(packageName);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ + packageName);
+ return false;
}
return true;
}
@@ -6867,14 +6784,10 @@
publicSrcDir = applicationInfo.publicSourceDir;
}
}
- if (mInstaller != null) {
- int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
- asecPath, pStats);
- if (res < 0) {
- return false;
- } else {
- return true;
- }
+ int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
+ asecPath, pStats);
+ if (res < 0) {
+ return false;
}
return true;
}
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 1ab570a..3139798 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -138,12 +138,9 @@
// create a thread for our Handler
HandlerThread thread = new HandlerThread("UsbDeviceManager",
- Process.THREAD_PRIORITY_BACKGROUND) {
- protected void onLooperPrepared() {
- mHandler = new UsbHandler();
- }
- };
+ Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
+ mHandler = new UsbHandler(thread.getLooper());
}
public void systemReady() {
@@ -249,21 +246,21 @@
private static final int NOTIFICATION_INSTALLER = 3;
private static final int NOTIFICATION_ADB = 4;
- public UsbHandler() {
+ public UsbHandler(Looper looper) {
+ super(looper);
try {
+ // persist.sys.usb.config should never be unset. But if it is, set it to "adb"
+ // so we have a chance of debugging what happened.
+ mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
// sanity check the sys.usb.config system property
// this may be necessary if we crashed while switching USB configurations
String config = SystemProperties.get("sys.usb.config", "none");
- if (config.equals("none")) {
- String persistConfig = SystemProperties.get("persist.sys.usb.config", "none");
- Slog.w(TAG, "resetting config to persistent property: " + persistConfig);
- SystemProperties.set("sys.usb.config", persistConfig);
+ if (!config.equals(mDefaultFunctions)) {
+ Slog.w(TAG, "resetting config to persistent property: " + mDefaultFunctions);
+ SystemProperties.set("sys.usb.config", mDefaultFunctions);
}
- // Read initial USB state
- mCurrentFunctions = FileUtils.readTextFile(
- new File(FUNCTIONS_PATH), 0, null).trim();
- mDefaultFunctions = mCurrentFunctions;
+ mCurrentFunctions = mDefaultFunctions;
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
@@ -621,6 +618,16 @@
pw.println(" mConnected: " + mConnected);
pw.println(" mConfigured: " + mConfigured);
pw.println(" mCurrentAccessory: " + mCurrentAccessory);
+ try {
+ pw.println(" Kernel state: "
+ + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
+ pw.println(" Kernel function list: "
+ + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim());
+ pw.println(" Mass storage backing file: "
+ + FileUtils.readTextFile(new File(MASS_STORAGE_FILE_PATH), 0, null).trim());
+ } catch (IOException e) {
+ pw.println("IOException: " + e);
+ }
}
}
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index d3d9df4..bfa2b39 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -101,7 +101,7 @@
boolean firstWindowDrawn;
// Input application handle used by the input dispatcher.
- InputApplicationHandle mInputApplicationHandle;
+ final InputApplicationHandle mInputApplicationHandle;
AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
super(_service, _token.asBinder(),
diff --git a/services/java/com/android/server/wm/InputApplication.java b/services/java/com/android/server/wm/InputApplication.java
deleted file mode 100644
index e04fd31..0000000
--- a/services/java/com/android/server/wm/InputApplication.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-
-/**
- * Describes input-related application properties for use by the input dispatcher.
- * @hide
- */
-public final class InputApplication {
- // Application handle.
- public InputApplicationHandle inputApplicationHandle;
-
- // Application name.
- public String name;
-
- // Dispatching timeout.
- public long dispatchingTimeoutNanos;
-
- public void recycle() {
- inputApplicationHandle = null;
- }
-}
diff --git a/services/java/com/android/server/wm/InputApplicationHandle.java b/services/java/com/android/server/wm/InputApplicationHandle.java
index 64c8e7e..d78b1d9 100644
--- a/services/java/com/android/server/wm/InputApplicationHandle.java
+++ b/services/java/com/android/server/wm/InputApplicationHandle.java
@@ -32,6 +32,12 @@
// The window manager's application window token.
public final AppWindowToken appWindowToken;
+ // Application name.
+ public String name;
+
+ // Dispatching timeout.
+ public long dispatchingTimeoutNanos;
+
private native void nativeDispose();
public InputApplicationHandle(AppWindowToken appWindowToken) {
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index 65007f9..3133a19 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -25,7 +25,6 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.os.Environment;
-import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.SystemProperties;
@@ -83,10 +82,10 @@
private static native int nativeInjectInputEvent(InputEvent event,
int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
int policyFlags);
- private static native void nativeSetInputWindows(InputWindow[] windows);
+ private static native void nativeSetInputWindows(InputWindowHandle[] windowHandles);
private static native void nativeSetInputDispatchMode(boolean enabled, boolean frozen);
private static native void nativeSetSystemUiVisibility(int visibility);
- private static native void nativeSetFocusedApplication(InputApplication application);
+ private static native void nativeSetFocusedApplication(InputApplicationHandle application);
private static native InputDevice nativeGetInputDevice(int deviceId);
private static native void nativeGetInputConfiguration(Configuration configuration);
private static native int[] nativeGetInputDeviceIds();
@@ -372,11 +371,11 @@
return nativeGetInputDeviceIds();
}
- public void setInputWindows(InputWindow[] windows) {
- nativeSetInputWindows(windows);
+ public void setInputWindows(InputWindowHandle[] windowHandles) {
+ nativeSetInputWindows(windowHandles);
}
- public void setFocusedApplication(InputApplication application) {
+ public void setFocusedApplication(InputApplicationHandle application) {
nativeSetFocusedApplication(application);
}
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index 6806634..08a3560 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import android.graphics.Rect;
-import android.os.Binder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -26,6 +25,7 @@
import android.view.WindowManager;
import java.util.ArrayList;
+import java.util.Arrays;
final class InputMonitor {
private final WindowManagerService mService;
@@ -42,12 +42,14 @@
// When true, need to call updateInputWindowsLw().
private boolean mUpdateInputWindowsNeeded = true;
- // Temporary list of windows information to provide to the input dispatcher.
- private InputWindowList mTempInputWindows = new InputWindowList();
-
- // Temporary input application object to provide to the input dispatcher.
- private InputApplication mTempInputApplication = new InputApplication();
-
+ // Fake handles for the drag surface, lazily initialized.
+ private InputApplicationHandle mDragApplicationHandle;
+ private InputWindowHandle mDragWindowHandle;
+
+ // Array of window handles to provide to the input dispatcher.
+ private InputWindowHandle[] mInputWindowHandles;
+ private int mInputWindowHandleCount;
+
// Set to true when the first input device configuration change notification
// is received to indicate that the input devices are ready.
private final Object mInputDevicesReadyMonitor = new Object();
@@ -68,8 +70,10 @@
synchronized (mService.mWindowMap) {
WindowState windowState = (WindowState) inputWindowHandle.windowState;
- Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState);
- mService.removeWindowLocked(windowState.mSession, windowState);
+ if (windowState != null) {
+ Slog.i(WindowManagerService.TAG, "WINDOW DIED " + windowState);
+ mService.removeWindowLocked(windowState.mSession, windowState);
+ }
}
}
@@ -94,8 +98,11 @@
if (appWindowToken == null && inputApplicationHandle != null) {
appWindowToken = inputApplicationHandle.appWindowToken;
- Slog.i(WindowManagerService.TAG, "Input event dispatching timed out sending to application "
- + appWindowToken.stringName);
+ if (appWindowToken != null) {
+ Slog.i(WindowManagerService.TAG,
+ "Input event dispatching timed out sending to application "
+ + appWindowToken.stringName);
+ }
}
if (appWindowToken != null && appWindowToken.appToken != null) {
@@ -114,32 +121,59 @@
return 0; // abort dispatching
}
- private void addDragInputWindowLw(InputWindowList windowList) {
- final InputWindow inputWindow = windowList.add();
- inputWindow.inputChannel = mService.mDragState.mServerChannel;
- inputWindow.name = "drag";
- inputWindow.layoutParamsFlags = 0;
- inputWindow.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- inputWindow.dispatchingTimeoutNanos = WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
- inputWindow.visible = true;
- inputWindow.canReceiveKeys = false;
- inputWindow.hasFocus = true;
- inputWindow.hasWallpaper = false;
- inputWindow.paused = false;
- inputWindow.layer = mService.mDragState.getDragLayerLw();
- inputWindow.ownerPid = Process.myPid();
- inputWindow.ownerUid = Process.myUid();
- inputWindow.inputFeatures = 0;
- inputWindow.scaleFactor = 1.0f;
+ private void addDragInputWindowLw() {
+ if (mDragWindowHandle == null) {
+ mDragApplicationHandle = new InputApplicationHandle(null);
+ mDragApplicationHandle.name = "drag";
+ mDragApplicationHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+
+ mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null);
+ mDragWindowHandle.name = "drag";
+ mDragWindowHandle.layoutParamsFlags = 0;
+ mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
+ mDragWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragWindowHandle.visible = true;
+ mDragWindowHandle.canReceiveKeys = false;
+ mDragWindowHandle.hasFocus = true;
+ mDragWindowHandle.hasWallpaper = false;
+ mDragWindowHandle.paused = false;
+ mDragWindowHandle.ownerPid = Process.myPid();
+ mDragWindowHandle.ownerUid = Process.myUid();
+ mDragWindowHandle.inputFeatures = 0;
+ mDragWindowHandle.scaleFactor = 1.0f;
+
+ // The drag window cannot receive new touches.
+ mDragWindowHandle.touchableRegion.setEmpty();
+ }
+
+ mDragWindowHandle.layer = mService.mDragState.getDragLayerLw();
// The drag window covers the entire display
- inputWindow.frameLeft = 0;
- inputWindow.frameTop = 0;
- inputWindow.frameRight = mService.mDisplay.getRealWidth();
- inputWindow.frameBottom = mService.mDisplay.getRealHeight();
+ mDragWindowHandle.frameLeft = 0;
+ mDragWindowHandle.frameTop = 0;
+ mDragWindowHandle.frameRight = mService.mDisplay.getRealWidth();
+ mDragWindowHandle.frameBottom = mService.mDisplay.getRealHeight();
- // The drag window cannot receive new touches.
- inputWindow.touchableRegion.setEmpty();
+ addInputWindowHandleLw(mDragWindowHandle);
+ }
+
+ private void addInputWindowHandleLw(InputWindowHandle windowHandle) {
+ if (mInputWindowHandles == null) {
+ mInputWindowHandles = new InputWindowHandle[16];
+ }
+ if (mInputWindowHandleCount >= mInputWindowHandles.length) {
+ mInputWindowHandles = Arrays.copyOf(mInputWindowHandles,
+ mInputWindowHandleCount * 2);
+ }
+ mInputWindowHandles[mInputWindowHandleCount++] = windowHandle;
+ }
+
+ private void clearInputWindowHandlesLw() {
+ while (mInputWindowHandleCount != 0) {
+ mInputWindowHandles[--mInputWindowHandleCount] = null;
+ }
}
public void setUpdateInputWindowsNeededLw() {
@@ -154,7 +188,7 @@
mUpdateInputWindowsNeeded = false;
if (false) Slog.d(WindowManagerService.TAG, ">>>>>> ENTERED updateInputWindowsLw");
-
+
// Populate the input window list with information about all of the windows that
// could potentially receive input.
// As an optimization, we could try to prune the list of windows but this turns
@@ -168,7 +202,7 @@
if (WindowManagerService.DEBUG_DRAG) {
Log.d(WindowManagerService.TAG, "Inserting drag window");
}
- addDragInputWindowLw(mTempInputWindows);
+ addDragInputWindowLw();
}
final int N = windows.size();
@@ -194,48 +228,48 @@
}
// Add a window to our list of input windows.
- final InputWindow inputWindow = mTempInputWindows.add();
- inputWindow.inputWindowHandle = child.mInputWindowHandle;
- inputWindow.inputChannel = child.mInputChannel;
- inputWindow.name = child.toString();
- inputWindow.layoutParamsFlags = flags;
- inputWindow.layoutParamsType = type;
- inputWindow.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
- inputWindow.visible = isVisible;
- inputWindow.canReceiveKeys = child.canReceiveKeys();
- inputWindow.hasFocus = hasFocus;
- inputWindow.hasWallpaper = hasWallpaper;
- inputWindow.paused = child.mAppToken != null ? child.mAppToken.paused : false;
- inputWindow.layer = child.mLayer;
- inputWindow.ownerPid = child.mSession.mPid;
- inputWindow.ownerUid = child.mSession.mUid;
- inputWindow.inputFeatures = child.mAttrs.inputFeatures;
+ final InputWindowHandle inputWindowHandle = child.mInputWindowHandle;
+ inputWindowHandle.inputChannel = child.mInputChannel;
+ inputWindowHandle.name = child.toString();
+ inputWindowHandle.layoutParamsFlags = flags;
+ inputWindowHandle.layoutParamsType = type;
+ inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
+ inputWindowHandle.visible = isVisible;
+ inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
+ inputWindowHandle.hasFocus = hasFocus;
+ inputWindowHandle.hasWallpaper = hasWallpaper;
+ inputWindowHandle.paused = child.mAppToken != null ? child.mAppToken.paused : false;
+ inputWindowHandle.layer = child.mLayer;
+ inputWindowHandle.ownerPid = child.mSession.mPid;
+ inputWindowHandle.ownerUid = child.mSession.mUid;
+ inputWindowHandle.inputFeatures = child.mAttrs.inputFeatures;
final Rect frame = child.mFrame;
- inputWindow.frameLeft = frame.left;
- inputWindow.frameTop = frame.top;
- inputWindow.frameRight = frame.right;
- inputWindow.frameBottom = frame.bottom;
+ inputWindowHandle.frameLeft = frame.left;
+ inputWindowHandle.frameTop = frame.top;
+ inputWindowHandle.frameRight = frame.right;
+ inputWindowHandle.frameBottom = frame.bottom;
if (child.mGlobalScale != 1) {
// If we are scaling the window, input coordinates need
// to be inversely scaled to map from what is on screen
// to what is actually being touched in the UI.
- inputWindow.scaleFactor = 1.0f/child.mGlobalScale;
+ inputWindowHandle.scaleFactor = 1.0f/child.mGlobalScale;
} else {
- inputWindow.scaleFactor = 1;
+ inputWindowHandle.scaleFactor = 1;
}
- child.getTouchableRegion(inputWindow.touchableRegion);
+ child.getTouchableRegion(inputWindowHandle.touchableRegion);
+
+ addInputWindowHandleLw(inputWindowHandle);
}
// Send windows to native code.
- mService.mInputManager.setInputWindows(mTempInputWindows.toNullTerminatedArray());
-
+ mService.mInputManager.setInputWindows(mInputWindowHandles);
+
// Clear the list in preparation for the next round.
- // Also avoids keeping InputChannel objects referenced unnecessarily.
- mTempInputWindows.clear();
-
+ clearInputWindowHandlesLw();
+
if (false) Slog.d(WindowManagerService.TAG, "<<<<<<< EXITED updateInputWindowsLw");
}
@@ -329,14 +363,11 @@
if (newApp == null) {
mService.mInputManager.setFocusedApplication(null);
} else {
- mTempInputApplication.inputApplicationHandle = newApp.mInputApplicationHandle;
- mTempInputApplication.name = newApp.toString();
- mTempInputApplication.dispatchingTimeoutNanos =
- newApp.inputDispatchingTimeoutNanos;
+ final InputApplicationHandle handle = newApp.mInputApplicationHandle;
+ handle.name = newApp.toString();
+ handle.dispatchingTimeoutNanos = newApp.inputDispatchingTimeoutNanos;
- mService.mInputManager.setFocusedApplication(mTempInputApplication);
-
- mTempInputApplication.recycle();
+ mService.mInputManager.setFocusedApplication(handle);
}
}
diff --git a/services/java/com/android/server/wm/InputWindow.java b/services/java/com/android/server/wm/InputWindow.java
deleted file mode 100644
index 655d734..0000000
--- a/services/java/com/android/server/wm/InputWindow.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import android.graphics.Region;
-import android.view.InputChannel;
-
-/**
- * Describes input-related window properties for use by the input dispatcher.
- * @hide
- */
-public final class InputWindow {
- // The window handle.
- public InputWindowHandle inputWindowHandle;
-
- // The input channel associated with the window.
- public InputChannel inputChannel;
-
- // The window name.
- public String name;
-
- // Window layout params attributes. (WindowManager.LayoutParams)
- public int layoutParamsFlags;
- public int layoutParamsType;
-
- // Dispatching timeout.
- public long dispatchingTimeoutNanos;
-
- // Window frame.
- public int frameLeft;
- public int frameTop;
- public int frameRight;
- public int frameBottom;
-
- // Global scaling factor applied to touch events when they are dispatched
- // to the window
- public float scaleFactor;
-
- // Window touchable region.
- public final Region touchableRegion = new Region();
-
- // Window is visible.
- public boolean visible;
-
- // Window can receive keys.
- public boolean canReceiveKeys;
-
- // Window has focus.
- public boolean hasFocus;
-
- // Window has wallpaper. (window is the current wallpaper target)
- public boolean hasWallpaper;
-
- // Input event dispatching is paused.
- public boolean paused;
-
- // Window layer.
- public int layer;
-
- // Id of process and user that owns the window.
- public int ownerPid;
- public int ownerUid;
-
- // Window input features.
- public int inputFeatures;
-
- public void recycle() {
- inputWindowHandle = null;
- inputChannel = null;
- }
-}
diff --git a/services/java/com/android/server/wm/InputWindowHandle.java b/services/java/com/android/server/wm/InputWindowHandle.java
index cc508c6..abf68d9 100644
--- a/services/java/com/android/server/wm/InputWindowHandle.java
+++ b/services/java/com/android/server/wm/InputWindowHandle.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import android.graphics.Region;
+import android.view.InputChannel;
import android.view.WindowManagerPolicy;
/**
@@ -35,6 +37,57 @@
// The window manager's window state.
public final WindowManagerPolicy.WindowState windowState;
+ // The input channel associated with the window.
+ public InputChannel inputChannel;
+
+ // The window name.
+ public String name;
+
+ // Window layout params attributes. (WindowManager.LayoutParams)
+ public int layoutParamsFlags;
+ public int layoutParamsType;
+
+ // Dispatching timeout.
+ public long dispatchingTimeoutNanos;
+
+ // Window frame.
+ public int frameLeft;
+ public int frameTop;
+ public int frameRight;
+ public int frameBottom;
+
+ // Global scaling factor applied to touch events when they are dispatched
+ // to the window
+ public float scaleFactor;
+
+ // Window touchable region.
+ public final Region touchableRegion = new Region();
+
+ // Window is visible.
+ public boolean visible;
+
+ // Window can receive keys.
+ public boolean canReceiveKeys;
+
+ // Window has focus.
+ public boolean hasFocus;
+
+ // Window has wallpaper. (window is the current wallpaper target)
+ public boolean hasWallpaper;
+
+ // Input event dispatching is paused.
+ public boolean paused;
+
+ // Window layer.
+ public int layer;
+
+ // Id of process and user that owns the window.
+ public int ownerPid;
+ public int ownerUid;
+
+ // Window input features.
+ public int inputFeatures;
+
private native void nativeDispose();
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
diff --git a/services/java/com/android/server/wm/InputWindowList.java b/services/java/com/android/server/wm/InputWindowList.java
deleted file mode 100644
index 6077337..0000000
--- a/services/java/com/android/server/wm/InputWindowList.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-
-/**
- * A specialized list of window information objects backed by an array.
- *
- * This class is part of an InputManager optimization to avoid allocating objects and arrays
- * unnecessarily. Internally, it keeps an array full of demand-allocated objects that it
- * recycles each time the list is cleared. The used portion of the array is padded with a null.
- *
- * The contents of the list are intended to be Z-ordered from top to bottom.
- *
- * @hide
- */
-public final class InputWindowList {
- private InputWindow[] mArray;
- private int mCount;
-
- /**
- * Creates an empty list.
- */
- public InputWindowList() {
- mArray = new InputWindow[8];
- }
-
- /**
- * Clears the list.
- */
- public void clear() {
- if (mCount == 0) {
- return;
- }
-
- int count = mCount;
- mCount = 0;
- mArray[count] = mArray[0];
- while (count > 0) {
- count -= 1;
- mArray[count].recycle();
- }
- mArray[0] = null;
- }
-
- /**
- * Adds an uninitialized input window object to the list and returns it.
- */
- public InputWindow add() {
- if (mCount + 1 == mArray.length) {
- InputWindow[] oldArray = mArray;
- mArray = new InputWindow[oldArray.length * 2];
- System.arraycopy(oldArray, 0, mArray, 0, mCount);
- }
-
- // Grab object from tail (after used section) if available.
- InputWindow item = mArray[mCount + 1];
- if (item == null) {
- item = new InputWindow();
- }
-
- mArray[mCount] = item;
- mCount += 1;
- mArray[mCount] = null;
- return item;
- }
-
- /**
- * Gets the input window objects as a null-terminated array.
- * @return The input window array.
- */
- public InputWindow[] toNullTerminatedArray() {
- return mArray;
- }
-}
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index b370ec9..d298ff7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -272,7 +272,7 @@
float mSurfaceAlpha;
// Input channel and input window handle used by the input dispatcher.
- InputWindowHandle mInputWindowHandle;
+ final InputWindowHandle mInputWindowHandle;
InputChannel mInputChannel;
// Used to improve performance of toString()
@@ -306,6 +306,7 @@
mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
+ mInputWindowHandle = null;
return;
}
mDeathRecipient = deathRecipient;
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index f33920d..6fa5dfa 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -4,10 +4,8 @@
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_BatteryService.cpp \
- com_android_server_InputApplication.cpp \
com_android_server_InputApplicationHandle.cpp \
com_android_server_InputManager.cpp \
- com_android_server_InputWindow.cpp \
com_android_server_InputWindowHandle.cpp \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
@@ -39,14 +37,6 @@
libgui \
libusbhost
-ifeq ($(TARGET_SIMULATOR),true)
-ifeq ($(TARGET_OS),linux)
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_LDLIBS += -lpthread -ldl -lrt
-endif
-endif
-endif
-
ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endif
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index c9a702a..e80dd04 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -32,17 +32,13 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
-
-#ifdef HAVE_ANDROID_OS
#include <linux/ioctl.h>
#include <linux/android_alarm.h>
-#endif
namespace android {
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
{
-#ifdef HAVE_ANDROID_OS
struct timezone tz;
tz.tz_minuteswest = minswest;
@@ -57,30 +53,20 @@
}
return 0;
-#else
- return -ENOSYS;
-#endif
}
static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
{
-#ifdef HAVE_ANDROID_OS
return open("/dev/alarm", O_RDWR);
-#else
- return -1;
-#endif
}
static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd)
{
-#ifdef HAVE_ANDROID_OS
close(fd);
-#endif
}
static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)
{
-#ifdef HAVE_ANDROID_OS
struct timespec ts;
ts.tv_sec = seconds;
ts.tv_nsec = nanoseconds;
@@ -90,12 +76,10 @@
{
LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
}
-#endif
}
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)
{
-#ifdef HAVE_ANDROID_OS
int result = 0;
do
@@ -110,7 +94,6 @@
}
return result;
-#endif
}
static JNINativeMethod sMethods[] = {
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index 98d0d92..b9f2c1f 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -32,10 +32,7 @@
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
-
-#ifdef HAVE_ANDROID_OS
#include <linux/ioctl.h>
-#endif
namespace android {
diff --git a/services/jni/com_android_server_InputApplication.cpp b/services/jni/com_android_server_InputApplication.cpp
deleted file mode 100644
index 1f80242..0000000
--- a/services/jni/com_android_server_InputApplication.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#define LOG_TAG "InputApplication"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
-
-#include "com_android_server_InputApplication.h"
-#include "com_android_server_InputApplicationHandle.h"
-
-namespace android {
-
-static struct {
- jfieldID inputApplicationHandle;
- jfieldID name;
- jfieldID dispatchingTimeoutNanos;
-} gInputApplicationClassInfo;
-
-
-// --- Global functions ---
-
-void android_server_InputApplication_toNative(
- JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication) {
- jobject inputApplicationHandleObj = env->GetObjectField(inputApplicationObj,
- gInputApplicationClassInfo.inputApplicationHandle);
- if (inputApplicationHandleObj) {
- outInputApplication->inputApplicationHandle =
- android_server_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
- env->DeleteLocalRef(inputApplicationHandleObj);
- } else {
- outInputApplication->inputApplicationHandle = NULL;
- }
-
- jstring nameObj = jstring(env->GetObjectField(inputApplicationObj,
- gInputApplicationClassInfo.name));
- if (nameObj) {
- const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- outInputApplication->name.setTo(nameStr);
- env->ReleaseStringUTFChars(nameObj, nameStr);
- env->DeleteLocalRef(nameObj);
- } else {
- LOGE("InputApplication.name should not be null.");
- outInputApplication->name.setTo("unknown");
- }
-
- outInputApplication->dispatchingTimeout = env->GetLongField(inputApplicationObj,
- gInputApplicationClassInfo.dispatchingTimeoutNanos);
-}
-
-
-// --- JNI ---
-
-#define FIND_CLASS(var, className) \
- var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
- var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
- LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
-int register_android_server_InputApplication(JNIEnv* env) {
- jclass clazz;
- FIND_CLASS(clazz, "com/android/server/wm/InputApplication");
-
- GET_FIELD_ID(gInputApplicationClassInfo.inputApplicationHandle,
- clazz,
- "inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
-
- GET_FIELD_ID(gInputApplicationClassInfo.name, clazz,
- "name", "Ljava/lang/String;");
-
- GET_FIELD_ID(gInputApplicationClassInfo.dispatchingTimeoutNanos,
- clazz,
- "dispatchingTimeoutNanos", "J");
- return 0;
-}
-
-} /* namespace android */
diff --git a/services/jni/com_android_server_InputApplication.h b/services/jni/com_android_server_InputApplication.h
deleted file mode 100644
index 85fb891..0000000
--- a/services/jni/com_android_server_InputApplication.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#ifndef _ANDROID_SERVER_INPUT_APPLICATION_H
-#define _ANDROID_SERVER_INPUT_APPLICATION_H
-
-#include <input/InputApplication.h>
-
-#include "JNIHelp.h"
-#include "jni.h"
-
-namespace android {
-
-extern void android_server_InputApplication_toNative(
- JNIEnv* env, jobject inputApplicationObj, InputApplication* outInputApplication);
-
-} // namespace android
-
-#endif // _ANDROID_SERVER_INPUT_APPLICATION_H
diff --git a/services/jni/com_android_server_InputApplicationHandle.cpp b/services/jni/com_android_server_InputApplicationHandle.cpp
index 9516964..7de67d9 100644
--- a/services/jni/com_android_server_InputApplicationHandle.cpp
+++ b/services/jni/com_android_server_InputApplicationHandle.cpp
@@ -27,6 +27,8 @@
static struct {
jfieldID ptr;
+ jfieldID name;
+ jfieldID dispatchingTimeoutNanos;
} gInputApplicationHandleClassInfo;
static Mutex gHandleMutex;
@@ -47,6 +49,31 @@
return env->NewLocalRef(mObjWeak);
}
+bool NativeInputApplicationHandle::update() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject obj = env->NewLocalRef(mObjWeak);
+ if (!obj) {
+ return false;
+ }
+
+ jstring nameObj = jstring(env->GetObjectField(obj,
+ gInputApplicationHandleClassInfo.name));
+ if (nameObj) {
+ const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+ name.setTo(nameStr);
+ env->ReleaseStringUTFChars(nameObj, nameStr);
+ env->DeleteLocalRef(nameObj);
+ } else {
+ name.setTo("<null>");
+ }
+
+ dispatchingTimeout = env->GetLongField(obj,
+ gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+
+ env->DeleteLocalRef(obj);
+ return true;
+}
+
// --- Global functions ---
@@ -113,6 +140,13 @@
GET_FIELD_ID(gInputApplicationHandleClassInfo.ptr, clazz,
"ptr", "I");
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz,
+ "name", "Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos,
+ clazz,
+ "dispatchingTimeoutNanos", "J");
+
return 0;
}
diff --git a/services/jni/com_android_server_InputApplicationHandle.h b/services/jni/com_android_server_InputApplicationHandle.h
index 9d18721..04cd9d6 100644
--- a/services/jni/com_android_server_InputApplicationHandle.h
+++ b/services/jni/com_android_server_InputApplicationHandle.h
@@ -31,6 +31,8 @@
jobject getInputApplicationHandleObjLocalRef(JNIEnv* env);
+ virtual bool update();
+
private:
jweak mObjWeak;
};
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 14a4109..de9c9d0 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -46,9 +46,7 @@
#include <android/graphics/GraphicsJNI.h>
#include "com_android_server_PowerManagerService.h"
-#include "com_android_server_InputApplication.h"
#include "com_android_server_InputApplicationHandle.h"
-#include "com_android_server_InputWindow.h"
#include "com_android_server_InputWindowHandle.h"
namespace android {
@@ -175,8 +173,8 @@
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
- void setInputWindows(JNIEnv* env, jobjectArray windowObjArray);
- void setFocusedApplication(JNIEnv* env, jobject applicationObj);
+ void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray);
+ void setFocusedApplication(JNIEnv* env, jobject applicationHandleObj);
void setInputDispatchMode(bool enabled, bool frozen);
void setSystemUiVisibility(int32_t visibility);
void setPointerSpeed(int32_t speed);
@@ -582,31 +580,38 @@
return isScreenOn();
}
-void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowObjArray) {
- Vector<InputWindow> windows;
+void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray) {
+ Vector<sp<InputWindowHandle> > windowHandles;
- bool newPointerGesturesEnabled = true;
- jsize length = env->GetArrayLength(windowObjArray);
- for (jsize i = 0; i < length; i++) {
- jobject windowObj = env->GetObjectArrayElement(windowObjArray, i);
- if (! windowObj) {
- break; // found null element indicating end of used portion of the array
- }
-
- windows.push();
- InputWindow& window = windows.editTop();
- android_server_InputWindow_toNative(env, windowObj, &window);
- if (window.inputChannel == NULL) {
- windows.pop();
- } else if (window.hasFocus) {
- if (window.inputFeatures & InputWindow::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES) {
- newPointerGesturesEnabled = false;
+ if (windowHandleObjArray) {
+ jsize length = env->GetArrayLength(windowHandleObjArray);
+ for (jsize i = 0; i < length; i++) {
+ jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
+ if (! windowHandleObj) {
+ break; // found null element indicating end of used portion of the array
}
+
+ sp<InputWindowHandle> windowHandle =
+ android_server_InputWindowHandle_getHandle(env, windowHandleObj);
+ if (windowHandle != NULL) {
+ windowHandles.push(windowHandle);
+ }
+ env->DeleteLocalRef(windowHandleObj);
}
- env->DeleteLocalRef(windowObj);
}
- mInputManager->getDispatcher()->setInputWindows(windows);
+ mInputManager->getDispatcher()->setInputWindows(windowHandles);
+
+ // Do this after the dispatcher has updated the window handle state.
+ bool newPointerGesturesEnabled = true;
+ size_t numWindows = windowHandles.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ if (windowHandle->hasFocus && (windowHandle->inputFeatures
+ & InputWindowHandle::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
+ newPointerGesturesEnabled = false;
+ }
+ }
uint32_t changes = 0;
{ // acquire lock
@@ -623,16 +628,10 @@
}
}
-void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationObj) {
- if (applicationObj) {
- InputApplication application;
- android_server_InputApplication_toNative(env, applicationObj, &application);
- if (application.inputApplicationHandle != NULL) {
- mInputManager->getDispatcher()->setFocusedApplication(&application);
- return;
- }
- }
- mInputManager->getDispatcher()->setFocusedApplication(NULL);
+void NativeInputManager::setFocusedApplication(JNIEnv* env, jobject applicationHandleObj) {
+ sp<InputApplicationHandle> applicationHandle =
+ android_server_InputApplicationHandle_getHandle(env, applicationHandleObj);
+ mInputManager->getDispatcher()->setFocusedApplication(applicationHandle);
}
void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
@@ -1137,21 +1136,21 @@
}
static void android_server_InputManager_nativeSetInputWindows(JNIEnv* env, jclass clazz,
- jobjectArray windowObjArray) {
+ jobjectArray windowHandleObjArray) {
if (checkInputManagerUnitialized(env)) {
return;
}
- gNativeInputManager->setInputWindows(env, windowObjArray);
+ gNativeInputManager->setInputWindows(env, windowHandleObjArray);
}
static void android_server_InputManager_nativeSetFocusedApplication(JNIEnv* env, jclass clazz,
- jobject applicationObj) {
+ jobject applicationHandleObj) {
if (checkInputManagerUnitialized(env)) {
return;
}
- gNativeInputManager->setFocusedApplication(env, applicationObj);
+ gNativeInputManager->setFocusedApplication(env, applicationHandleObj);
}
static void android_server_InputManager_nativeSetInputDispatchMode(JNIEnv* env,
@@ -1313,9 +1312,9 @@
(void*) android_server_InputManager_nativeSetInputFilterEnabled },
{ "nativeInjectInputEvent", "(Landroid/view/InputEvent;IIIII)I",
(void*) android_server_InputManager_nativeInjectInputEvent },
- { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindow;)V",
+ { "nativeSetInputWindows", "([Lcom/android/server/wm/InputWindowHandle;)V",
(void*) android_server_InputManager_nativeSetInputWindows },
- { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplication;)V",
+ { "nativeSetFocusedApplication", "(Lcom/android/server/wm/InputApplicationHandle;)V",
(void*) android_server_InputManager_nativeSetFocusedApplication },
{ "nativeSetInputDispatchMode", "(ZZ)V",
(void*) android_server_InputManager_nativeSetInputDispatchMode },
diff --git a/services/jni/com_android_server_InputWindow.cpp b/services/jni/com_android_server_InputWindow.cpp
deleted file mode 100644
index 0426f63..0000000
--- a/services/jni/com_android_server_InputWindow.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-#define LOG_TAG "InputWindow"
-
-#include "JNIHelp.h"
-#include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
-
-#include <android_view_InputChannel.h>
-#include <android/graphics/Region.h>
-#include "com_android_server_InputWindow.h"
-#include "com_android_server_InputWindowHandle.h"
-
-namespace android {
-
-static struct {
- jfieldID inputWindowHandle;
- jfieldID inputChannel;
- jfieldID name;
- jfieldID layoutParamsFlags;
- jfieldID layoutParamsType;
- jfieldID dispatchingTimeoutNanos;
- jfieldID frameLeft;
- jfieldID frameTop;
- jfieldID frameRight;
- jfieldID frameBottom;
- jfieldID scaleFactor;
- jfieldID touchableRegion;
- jfieldID visible;
- jfieldID canReceiveKeys;
- jfieldID hasFocus;
- jfieldID hasWallpaper;
- jfieldID paused;
- jfieldID layer;
- jfieldID ownerPid;
- jfieldID ownerUid;
- jfieldID inputFeatures;
-} gInputWindowClassInfo;
-
-
-// --- Global functions ---
-
-void android_server_InputWindow_toNative(
- JNIEnv* env, jobject inputWindowObj, InputWindow* outInputWindow) {
- jobject inputWindowHandleObj = env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.inputWindowHandle);
- if (inputWindowHandleObj) {
- outInputWindow->inputWindowHandle =
- android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
- env->DeleteLocalRef(inputWindowHandleObj);
- } else {
- outInputWindow->inputWindowHandle = NULL;
- }
-
- jobject inputChannelObj = env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.inputChannel);
- if (inputChannelObj) {
- outInputWindow->inputChannel =
- android_view_InputChannel_getInputChannel(env, inputChannelObj);
- env->DeleteLocalRef(inputChannelObj);
- } else {
- outInputWindow->inputChannel = NULL;
- }
-
- jstring nameObj = jstring(env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.name));
- if (nameObj) {
- const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
- outInputWindow->name.setTo(nameStr);
- env->ReleaseStringUTFChars(nameObj, nameStr);
- env->DeleteLocalRef(nameObj);
- } else {
- LOGE("InputWindow.name should not be null.");
- outInputWindow->name.setTo("unknown");
- }
-
- outInputWindow->layoutParamsFlags = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.layoutParamsFlags);
- outInputWindow->layoutParamsType = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.layoutParamsType);
- outInputWindow->dispatchingTimeout = env->GetLongField(inputWindowObj,
- gInputWindowClassInfo.dispatchingTimeoutNanos);
- outInputWindow->frameLeft = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameLeft);
- outInputWindow->frameTop = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameTop);
- outInputWindow->frameRight = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameRight);
- outInputWindow->frameBottom = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.frameBottom);
- outInputWindow->scaleFactor = env->GetFloatField(inputWindowObj,
- gInputWindowClassInfo.scaleFactor);
-
- jobject regionObj = env->GetObjectField(inputWindowObj,
- gInputWindowClassInfo.touchableRegion);
- if (regionObj) {
- SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
- outInputWindow->touchableRegion.set(*region);
- env->DeleteLocalRef(regionObj);
- } else {
- outInputWindow->touchableRegion.setEmpty();
- }
-
- outInputWindow->visible = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.visible);
- outInputWindow->canReceiveKeys = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.canReceiveKeys);
- outInputWindow->hasFocus = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.hasFocus);
- outInputWindow->hasWallpaper = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.hasWallpaper);
- outInputWindow->paused = env->GetBooleanField(inputWindowObj,
- gInputWindowClassInfo.paused);
- outInputWindow->layer = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.layer);
- outInputWindow->ownerPid = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.ownerPid);
- outInputWindow->ownerUid = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.ownerUid);
- outInputWindow->inputFeatures = env->GetIntField(inputWindowObj,
- gInputWindowClassInfo.inputFeatures);
-}
-
-
-// --- JNI ---
-
-#define FIND_CLASS(var, className) \
- var = env->FindClass(className); \
- LOG_FATAL_IF(! var, "Unable to find class " className);
-
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
- var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
- LOG_FATAL_IF(! var, "Unable to find field " fieldName);
-
-int register_android_server_InputWindow(JNIEnv* env) {
- jclass clazz;
- FIND_CLASS(clazz, "com/android/server/wm/InputWindow");
-
- GET_FIELD_ID(gInputWindowClassInfo.inputWindowHandle, clazz,
- "inputWindowHandle", "Lcom/android/server/wm/InputWindowHandle;");
-
- GET_FIELD_ID(gInputWindowClassInfo.inputChannel, clazz,
- "inputChannel", "Landroid/view/InputChannel;");
-
- GET_FIELD_ID(gInputWindowClassInfo.name, clazz,
- "name", "Ljava/lang/String;");
-
- GET_FIELD_ID(gInputWindowClassInfo.layoutParamsFlags, clazz,
- "layoutParamsFlags", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.layoutParamsType, clazz,
- "layoutParamsType", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.dispatchingTimeoutNanos, clazz,
- "dispatchingTimeoutNanos", "J");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameLeft, clazz,
- "frameLeft", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameTop, clazz,
- "frameTop", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameRight, clazz,
- "frameRight", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.frameBottom, clazz,
- "frameBottom", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.scaleFactor, clazz,
- "scaleFactor", "F");
-
- GET_FIELD_ID(gInputWindowClassInfo.touchableRegion, clazz,
- "touchableRegion", "Landroid/graphics/Region;");
-
- GET_FIELD_ID(gInputWindowClassInfo.visible, clazz,
- "visible", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.canReceiveKeys, clazz,
- "canReceiveKeys", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.hasFocus, clazz,
- "hasFocus", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.hasWallpaper, clazz,
- "hasWallpaper", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.paused, clazz,
- "paused", "Z");
-
- GET_FIELD_ID(gInputWindowClassInfo.layer, clazz,
- "layer", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.ownerPid, clazz,
- "ownerPid", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.ownerUid, clazz,
- "ownerUid", "I");
-
- GET_FIELD_ID(gInputWindowClassInfo.inputFeatures, clazz,
- "inputFeatures", "I");
- return 0;
-}
-
-} /* namespace android */
diff --git a/services/jni/com_android_server_InputWindowHandle.cpp b/services/jni/com_android_server_InputWindowHandle.cpp
index aaf679c..09be881 100644
--- a/services/jni/com_android_server_InputWindowHandle.cpp
+++ b/services/jni/com_android_server_InputWindowHandle.cpp
@@ -21,6 +21,9 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/threads.h>
+#include <android_view_InputChannel.h>
+#include <android/graphics/Region.h>
+
#include "com_android_server_InputWindowHandle.h"
#include "com_android_server_InputApplicationHandle.h"
@@ -29,6 +32,26 @@
static struct {
jfieldID ptr;
jfieldID inputApplicationHandle;
+ jfieldID inputChannel;
+ jfieldID name;
+ jfieldID layoutParamsFlags;
+ jfieldID layoutParamsType;
+ jfieldID dispatchingTimeoutNanos;
+ jfieldID frameLeft;
+ jfieldID frameTop;
+ jfieldID frameRight;
+ jfieldID frameBottom;
+ jfieldID scaleFactor;
+ jfieldID touchableRegion;
+ jfieldID visible;
+ jfieldID canReceiveKeys;
+ jfieldID hasFocus;
+ jfieldID hasWallpaper;
+ jfieldID paused;
+ jfieldID layer;
+ jfieldID ownerPid;
+ jfieldID ownerUid;
+ jfieldID inputFeatures;
} gInputWindowHandleClassInfo;
static Mutex gHandleMutex;
@@ -51,6 +74,83 @@
return env->NewLocalRef(mObjWeak);
}
+bool NativeInputWindowHandle::update() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject obj = env->NewLocalRef(mObjWeak);
+ if (!obj) {
+ return false;
+ }
+
+ jobject inputChannelObj = env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.inputChannel);
+ if (inputChannelObj) {
+ inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
+ env->DeleteLocalRef(inputChannelObj);
+ } else {
+ inputChannel = NULL;
+ }
+
+ jstring nameObj = jstring(env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.name));
+ if (nameObj) {
+ const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
+ name.setTo(nameStr);
+ env->ReleaseStringUTFChars(nameObj, nameStr);
+ env->DeleteLocalRef(nameObj);
+ } else {
+ name.setTo("<null>");
+ }
+
+ layoutParamsFlags = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layoutParamsFlags);
+ layoutParamsType = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layoutParamsType);
+ dispatchingTimeout = env->GetLongField(obj,
+ gInputWindowHandleClassInfo.dispatchingTimeoutNanos);
+ frameLeft = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameLeft);
+ frameTop = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameTop);
+ frameRight = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameRight);
+ frameBottom = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.frameBottom);
+ scaleFactor = env->GetFloatField(obj,
+ gInputWindowHandleClassInfo.scaleFactor);
+
+ jobject regionObj = env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.touchableRegion);
+ if (regionObj) {
+ SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
+ touchableRegion.set(*region);
+ env->DeleteLocalRef(regionObj);
+ } else {
+ touchableRegion.setEmpty();
+ }
+
+ visible = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.visible);
+ canReceiveKeys = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.canReceiveKeys);
+ hasFocus = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.hasFocus);
+ hasWallpaper = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.hasWallpaper);
+ paused = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.paused);
+ layer = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.layer);
+ ownerPid = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.ownerPid);
+ ownerUid = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.ownerUid);
+ inputFeatures = env->GetIntField(obj,
+ gInputWindowHandleClassInfo.inputFeatures);
+
+ env->DeleteLocalRef(obj);
+ return true;
+}
+
// --- Global functions ---
@@ -127,6 +227,65 @@
clazz,
"inputApplicationHandle", "Lcom/android/server/wm/InputApplicationHandle;");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputChannel, clazz,
+ "inputChannel", "Landroid/view/InputChannel;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.name, clazz,
+ "name", "Ljava/lang/String;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsFlags, clazz,
+ "layoutParamsFlags", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
+ "layoutParamsType", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
+ "dispatchingTimeoutNanos", "J");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
+ "frameLeft", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameTop, clazz,
+ "frameTop", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameRight, clazz,
+ "frameRight", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.frameBottom, clazz,
+ "frameBottom", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.scaleFactor, clazz,
+ "scaleFactor", "F");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegion, clazz,
+ "touchableRegion", "Landroid/graphics/Region;");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.visible, clazz,
+ "visible", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.canReceiveKeys, clazz,
+ "canReceiveKeys", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.hasFocus, clazz,
+ "hasFocus", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.hasWallpaper, clazz,
+ "hasWallpaper", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
+ "paused", "Z");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.layer, clazz,
+ "layer", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
+ "ownerPid", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.ownerUid, clazz,
+ "ownerUid", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.inputFeatures, clazz,
+ "inputFeatures", "I");
return 0;
}
diff --git a/services/jni/com_android_server_InputWindowHandle.h b/services/jni/com_android_server_InputWindowHandle.h
index 43f2a6b..913c3b1 100644
--- a/services/jni/com_android_server_InputWindowHandle.h
+++ b/services/jni/com_android_server_InputWindowHandle.h
@@ -32,6 +32,8 @@
jobject getInputWindowHandleObjLocalRef(JNIEnv* env);
+ virtual bool update();
+
private:
jweak mObjWeak;
};
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index 5f920f1..d28a6b4 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -18,7 +18,6 @@
#define LOG_TAG "VpnJni"
#include <cutils/log.h>
-#include <cutils/properties.h>
#include <stdio.h>
#include <string.h>
@@ -54,7 +53,7 @@
#define SYSTEM_ERROR -1
#define BAD_ARGUMENT -2
-static int create_interface(char *name, int *index, int mtu)
+static int create_interface(int mtu)
{
int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
@@ -82,14 +81,6 @@
goto error;
}
- // Get interface index.
- if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
- LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
- goto error;
- }
-
- strncpy(name, ifr4.ifr_name, IFNAMSIZ);
- *index = ifr4.ifr_ifindex;
return tun;
error:
@@ -97,12 +88,40 @@
return SYSTEM_ERROR;
}
-static int set_addresses(const char *name, int index, const char *addresses)
+static int get_interface_name(char *name, int tun)
{
ifreq ifr4;
+ if (ioctl(tun, TUNGETIFF, &ifr4)) {
+ LOGE("Cannot get interface name: %s", strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ strncpy(name, ifr4.ifr_name, IFNAMSIZ);
+ return 0;
+}
+
+static int get_interface_index(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
+ LOGE("Cannot get index of %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return ifr4.ifr_ifindex;
+}
+
+static int set_addresses(const char *name, const char *addresses)
+{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
+
+ ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
strncpy(ifr4.ifr_name, name, IFNAMSIZ);
ifr4.ifr_addr.sa_family = AF_INET;
+ ifr4.ifr_netmask.sa_family = AF_INET;
in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6));
@@ -146,7 +165,7 @@
}
in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
- *as_in_addr(&ifr4.ifr_addr) = htonl(mask);
+ *as_in_addr(&ifr4.ifr_netmask) = htonl(mask);
if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
@@ -168,8 +187,13 @@
return count;
}
-static int set_routes(const char *name, int index, const char *routes)
+static int set_routes(const char *name, const char *routes)
{
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
+
rtentry rt4;
memset(&rt4, 0, sizeof(rt4));
rt4.rt_dev = (char *)name;
@@ -253,17 +277,6 @@
return count;
}
-static int get_interface_name(char *name, int tun)
-{
- ifreq ifr4;
- if (ioctl(tun, TUNGETIFF, &ifr4)) {
- LOGE("Cannot get interface name: %s", strerror(errno));
- return SYSTEM_ERROR;
- }
- strncpy(name, ifr4.ifr_name, IFNAMSIZ);
- return 0;
-}
-
static int reset_interface(const char *name)
{
ifreq ifr4;
@@ -309,53 +322,14 @@
}
}
-static jint configure(JNIEnv *env, jobject thiz,
- jint mtu, jstring jAddresses, jstring jRoutes)
+static jint create(JNIEnv *env, jobject thiz, jint mtu)
{
- char name[IFNAMSIZ];
- int index;
- int tun = create_interface(name, &index, mtu);
+ int tun = create_interface(mtu);
if (tun < 0) {
throwException(env, tun, "Cannot create interface");
return -1;
}
-
- const char *addresses = NULL;
- const char *routes = NULL;
- int count;
-
- // At least one address must be set.
- addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
- if (!addresses) {
- jniThrowNullPointerException(env, "address");
- goto error;
- }
- count = set_addresses(name, index, addresses);
- env->ReleaseStringUTFChars(jAddresses, addresses);
- if (count <= 0) {
- throwException(env, count, "Cannot set address");
- goto error;
- }
- LOGD("Configured %d address(es) on %s", count, name);
-
- // On the contrary, routes are optional.
- routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
- if (routes) {
- count = set_routes(name, index, routes);
- env->ReleaseStringUTFChars(jRoutes, routes);
- if (count < 0) {
- throwException(env, count, "Cannot set route");
- goto error;
- }
- LOGD("Configured %d route(s) on %s", count, name);
- }
-
return tun;
-
-error:
- close(tun);
- LOGD("%s is destroyed", name);
- return -1;
}
static jstring getName(JNIEnv *env, jobject thiz, jint tun)
@@ -368,6 +342,72 @@
return env->NewStringUTF(name);
}
+static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jAddresses)
+{
+ const char *name = NULL;
+ const char *addresses = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
+ if (!addresses) {
+ jniThrowNullPointerException(env, "addresses");
+ goto error;
+ }
+ count = set_addresses(name, addresses);
+ if (count < 0) {
+ throwException(env, count, "Cannot set address");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (addresses) {
+ env->ReleaseStringUTFChars(jAddresses, addresses);
+ }
+ return count;
+}
+
+static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jRoutes)
+{
+ const char *name = NULL;
+ const char *routes = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
+ routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
+ if (!routes) {
+ jniThrowNullPointerException(env, "routes");
+ goto error;
+ }
+ count = set_routes(name, routes);
+ if (count < 0) {
+ throwException(env, count, "Cannot set route");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (routes) {
+ env->ReleaseStringUTFChars(jRoutes, routes);
+ }
+ return count;
+}
+
static void reset(JNIEnv *env, jobject thiz, jstring jName)
{
const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
@@ -409,8 +449,10 @@
//------------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"jniConfigure", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)configure},
+ {"jniCreate", "(I)I", (void *)create},
{"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
+ {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
+ {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
{"jniReset", "(Ljava/lang/String;)V", (void *)reset},
{"jniCheck", "(Ljava/lang/String;)I", (void *)check},
{"jniProtect", "(ILjava/lang/String;)V", (void *)protect},
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 9dff48b..4178039 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -22,9 +22,7 @@
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
int register_android_server_BatteryService(JNIEnv* env);
-int register_android_server_InputApplication(JNIEnv* env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
-int register_android_server_InputWindow(JNIEnv* env);
int register_android_server_InputWindowHandle(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
@@ -51,9 +49,7 @@
LOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_PowerManagerService(env);
- register_android_server_InputApplication(env);
register_android_server_InputApplicationHandle(env);
- register_android_server_InputWindow(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index ba3e6e5..6a302c0 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -16,13 +16,6 @@
LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
-# need "-lrt" on Linux simulator to pick up clock_gettime
-ifeq ($(TARGET_SIMULATOR),true)
- ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt -lpthread
- endif
-endif
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libhardware \
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 4ec0c8c..518a1bb7 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -28,23 +28,25 @@
mEnabled(false), mGyroTime(0)
{
sensor_t const* list;
- size_t count = mSensorDevice.getSensorList(&list);
- for (size_t i=0 ; i<count ; i++) {
- if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
- mAcc = Sensor(list + i);
+ ssize_t count = mSensorDevice.getSensorList(&list);
+ if (count > 0) {
+ for (size_t i=0 ; i<size_t(count) ; i++) {
+ if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
+ mAcc = Sensor(list + i);
+ }
+ if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
+ mMag = Sensor(list + i);
+ }
+ if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
+ mGyro = Sensor(list + i);
+ // 200 Hz for gyro events is a good compromise between precision
+ // and power/cpu usage.
+ mGyroRate = 200;
+ mTargetDelayNs = 1000000000LL/mGyroRate;
+ }
}
- if (list[i].type == SENSOR_TYPE_MAGNETIC_FIELD) {
- mMag = Sensor(list + i);
- }
- if (list[i].type == SENSOR_TYPE_GYROSCOPE) {
- mGyro = Sensor(list + i);
- // 200 Hz for gyro events is a good compromise between precision
- // and power/cpu usage.
- mGyroRate = 200;
- mTargetDelayNs = 1000000000LL/mGyroRate;
- }
+ mFusion.init();
}
- mFusion.init();
}
void SensorFusion::process(const sensors_event_t& event) {
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 64d214b..e0dce1f 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -70,73 +70,76 @@
SensorDevice& dev(SensorDevice::getInstance());
if (dev.initCheck() == NO_ERROR) {
- ssize_t orientationIndex = -1;
- bool hasGyro = false;
- uint32_t virtualSensorsNeeds =
- (1<<SENSOR_TYPE_GRAVITY) |
- (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
- (1<<SENSOR_TYPE_ROTATION_VECTOR);
sensor_t const* list;
- int count = dev.getSensorList(&list);
- mLastEventSeen.setCapacity(count);
- for (int i=0 ; i<count ; i++) {
- registerSensor( new HardwareSensor(list[i]) );
- switch (list[i].type) {
- case SENSOR_TYPE_ORIENTATION:
- orientationIndex = i;
- break;
- case SENSOR_TYPE_GYROSCOPE:
- hasGyro = true;
- break;
- case SENSOR_TYPE_GRAVITY:
- case SENSOR_TYPE_LINEAR_ACCELERATION:
- case SENSOR_TYPE_ROTATION_VECTOR:
- virtualSensorsNeeds &= ~(1<<list[i].type);
- break;
+ ssize_t count = dev.getSensorList(&list);
+ if (count > 0) {
+ ssize_t orientationIndex = -1;
+ bool hasGyro = false;
+ uint32_t virtualSensorsNeeds =
+ (1<<SENSOR_TYPE_GRAVITY) |
+ (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
+ (1<<SENSOR_TYPE_ROTATION_VECTOR);
+
+ mLastEventSeen.setCapacity(count);
+ for (ssize_t i=0 ; i<count ; i++) {
+ registerSensor( new HardwareSensor(list[i]) );
+ switch (list[i].type) {
+ case SENSOR_TYPE_ORIENTATION:
+ orientationIndex = i;
+ break;
+ case SENSOR_TYPE_GYROSCOPE:
+ hasGyro = true;
+ break;
+ case SENSOR_TYPE_GRAVITY:
+ case SENSOR_TYPE_LINEAR_ACCELERATION:
+ case SENSOR_TYPE_ROTATION_VECTOR:
+ virtualSensorsNeeds &= ~(1<<list[i].type);
+ break;
+ }
}
- }
- // it's safe to instantiate the SensorFusion object here
- // (it wants to be instantiated after h/w sensors have been
- // registered)
- const SensorFusion& fusion(SensorFusion::getInstance());
+ // it's safe to instantiate the SensorFusion object here
+ // (it wants to be instantiated after h/w sensors have been
+ // registered)
+ const SensorFusion& fusion(SensorFusion::getInstance());
- if (hasGyro) {
- // Always instantiate Android's virtual sensors. Since they are
- // instantiated behind sensors from the HAL, they won't
- // interfere with applications, unless they looks specifically
- // for them (by name).
+ if (hasGyro) {
+ // Always instantiate Android's virtual sensors. Since they are
+ // instantiated behind sensors from the HAL, they won't
+ // interfere with applications, unless they looks specifically
+ // for them (by name).
- registerVirtualSensor( new RotationVectorSensor() );
- registerVirtualSensor( new GravitySensor(list, count) );
- registerVirtualSensor( new LinearAccelerationSensor(list, count) );
+ registerVirtualSensor( new RotationVectorSensor() );
+ registerVirtualSensor( new GravitySensor(list, count) );
+ registerVirtualSensor( new LinearAccelerationSensor(list, count) );
- // these are optional
- registerVirtualSensor( new OrientationSensor() );
- registerVirtualSensor( new CorrectedGyroSensor(list, count) );
+ // these are optional
+ registerVirtualSensor( new OrientationSensor() );
+ registerVirtualSensor( new CorrectedGyroSensor(list, count) );
- // virtual debugging sensors...
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.sensors", value, "0");
- if (atoi(value)) {
- registerVirtualSensor( new GyroDriftSensor() );
+ // virtual debugging sensors...
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sensors", value, "0");
+ if (atoi(value)) {
+ registerVirtualSensor( new GyroDriftSensor() );
+ }
}
- }
- // build the sensor list returned to users
- mUserSensorList = mSensorList;
- if (hasGyro &&
- (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) {
- // if we have the fancy sensor fusion, and it's not provided by the
- // HAL, use our own (fused) orientation sensor by removing the
- // HAL supplied one form the user list.
- if (orientationIndex >= 0) {
- mUserSensorList.removeItemsAt(orientationIndex);
+ // build the sensor list returned to users
+ mUserSensorList = mSensorList;
+ if (hasGyro &&
+ (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) {
+ // if we have the fancy sensor fusion, and it's not provided by the
+ // HAL, use our own (fused) orientation sensor by removing the
+ // HAL supplied one form the user list.
+ if (orientationIndex >= 0) {
+ mUserSensorList.removeItemsAt(orientationIndex);
+ }
}
- }
- run("SensorService", PRIORITY_URGENT_DISPLAY);
- mInitCheck = NO_ERROR;
+ run("SensorService", PRIORITY_URGENT_DISPLAY);
+ mInitCheck = NO_ERROR;
+ }
}
}
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index c618263..f67c82e 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -26,13 +26,6 @@
endif
-# need "-lrt" on Linux simulator to pick up clock_gettime
-ifeq ($(TARGET_SIMULATOR),true)
- ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt -lpthread
- endif
-endif
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libhardware \
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 35e29a6..f3b6c4d 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -188,22 +188,37 @@
return;
}
+ /*
+ * Transformations are applied in this order:
+ * 1) buffer orientation/flip/mirror
+ * 2) state transformation (window manager)
+ * 3) layer orientation (screen orientation)
+ * (NOTE: the matrices are multiplied in reverse order)
+ */
+
+ const Transform bufferOrientation(mCurrentTransform);
+ const Transform& stateTransform(s.transform);
+ const Transform layerOrientation(mOrientation);
+
+ const Transform tr(layerOrientation * stateTransform * bufferOrientation);
+
+ // this gives us only the "orientation" component of the transform
+ const uint32_t finalTransform = tr.getOrientation();
+
// we can only handle simple transformation
- if (mOrientation & Transform::ROT_INVALID) {
+ if (finalTransform & Transform::ROT_INVALID) {
hwcl->flags = HWC_SKIP_LAYER;
return;
}
- // FIXME: shouldn't we take the state's transform into account here?
-
- Transform tr(Transform(mOrientation) * Transform(mCurrentTransform));
- hwcl->transform = tr.getOrientation();
+ hwcl->transform = finalTransform;
if (!isOpaque()) {
hwcl->blending = mPremultipliedAlpha ?
HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
}
+ // scaling is already applied in mTransformedBounds
hwcl->displayFrame.left = mTransformedBounds.left;
hwcl->displayFrame.top = mTransformedBounds.top;
hwcl->displayFrame.right = mTransformedBounds.right;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b0881a4..680814c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1551,8 +1551,18 @@
* Dump SurfaceFlinger global state
*/
- snprintf(buffer, SIZE, "SurfaceFlinger global state\n");
+ snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
result.append(buffer);
+
+ const GLExtensions& extensions(GLExtensions::getInstance());
+ snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
+ extensions.getVendor(),
+ extensions.getRenderer(),
+ extensions.getVersion());
+ result.append(buffer);
+ snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
+ result.append(buffer);
+
mWormholeRegion.dump(result, "WormholeRegion");
const DisplayHardware& hw(graphicPlane(0).displayHardware());
snprintf(buffer, SIZE,
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 0467a14..4cedcbf 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -308,6 +308,7 @@
scale = true;
}
} else {
+ // there is a skew component and/or a non 90 degrees rotation
flags = ROT_INVALID;
}
diff --git a/services/tests/servicestests/res/raw/net_dev_typical b/services/tests/servicestests/res/raw/net_dev_typical
new file mode 100644
index 0000000..290bf03
--- /dev/null
+++ b/services/tests/servicestests/res/raw/net_dev_typical
@@ -0,0 +1,8 @@
+Inter-| Receive | Transmit
+ face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
+ lo: 8308 116 0 0 0 0 0 0 8308 116 0 0 0 0 0 0
+rmnet0: 1507570 2205 0 0 0 0 0 0 489339 2237 0 0 0 0 0 0
+ ifb0: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
+ ifb1: 52454 151 0 151 0 0 0 0 0 0 0 0 0 0 0 0
+ sit0: 0 0 0 0 0 0 0 0 0 0 148 0 0 0 0 0
+ip6tnl0: 0 0 0 0 0 0 0 0 0 0 151 151 0 0 0 0
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
index 302a2d6..1234bfd 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -542,6 +542,9 @@
public void setEnabled(boolean enabled) {
mIsEnabled = enabled;
}
+
+ public void setTouchExplorationEnabled(boolean enabled) {
+ }
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index ac7cb5a..56ef995a 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
import static com.android.server.NetworkManagementSocketTagger.tagToKernel;
@@ -25,9 +27,11 @@
import android.test.suitebuilder.annotation.LargeTest;
import com.android.frameworks.servicestests.R;
+import com.google.common.io.Files;
import java.io.File;
import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStream;
@@ -46,14 +50,23 @@
public void setUp() throws Exception {
super.setUp();
- mTestProc = getContext().getFilesDir();
- mService = NetworkManagementService.createForTest(mContext, mTestProc);
+ final File canonicalFilesDir = getContext().getFilesDir().getCanonicalFile();
+ mTestProc = new File(canonicalFilesDir, "proc");
+ if (mTestProc.exists()) {
+ Files.deleteRecursively(mTestProc);
+ }
+
+ mService = NetworkManagementService.createForTest(mContext, mTestProc, true);
}
@Override
public void tearDown() throws Exception {
mService = null;
+ if (mTestProc.exists()) {
+ Files.deleteRecursively(mTestProc);
+ }
+
super.tearDown();
}
@@ -61,7 +74,7 @@
stageFile(R.raw.xt_qtaguid_typical, new File(mTestProc, "net/xt_qtaguid/stats"));
final NetworkStats stats = mService.getNetworkStatsDetail();
- assertEquals(31, stats.size);
+ assertEquals(31, stats.size());
assertStatsEntry(stats, "wlan0", 0, 0, 14615L, 4270L);
assertStatsEntry(stats, "wlan0", 10004, 0, 333821L, 53558L);
assertStatsEntry(stats, "wlan0", 10004, 1947740890, 18725L, 1066L);
@@ -73,11 +86,37 @@
stageFile(R.raw.xt_qtaguid_extended, new File(mTestProc, "net/xt_qtaguid/stats"));
final NetworkStats stats = mService.getNetworkStatsDetail();
- assertEquals(2, stats.size);
+ assertEquals(2, stats.size());
assertStatsEntry(stats, "test0", 1000, 0, 1024L, 2048L);
assertStatsEntry(stats, "test0", 1000, 0xF00D, 512L, 512L);
}
+ public void testNetworkStatsSummary() throws Exception {
+ stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+
+ final NetworkStats stats = mService.getNetworkStatsSummary();
+ assertEquals(6, stats.size());
+ assertStatsEntry(stats, "lo", UID_ALL, TAG_NONE, 8308L, 8308L);
+ assertStatsEntry(stats, "rmnet0", UID_ALL, TAG_NONE, 1507570L, 489339L);
+ assertStatsEntry(stats, "ifb0", UID_ALL, TAG_NONE, 52454L, 0L);
+ assertStatsEntry(stats, "ifb1", UID_ALL, TAG_NONE, 52454L, 0L);
+ assertStatsEntry(stats, "sit0", UID_ALL, TAG_NONE, 0L, 0L);
+ assertStatsEntry(stats, "ip6tnl0", UID_ALL, TAG_NONE, 0L, 0L);
+ }
+
+ public void testNetworkStatsSummaryDown() throws Exception {
+ stageFile(R.raw.net_dev_typical, new File(mTestProc, "net/dev"));
+ stageLong(1024L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_bytes"));
+ stageLong(128L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/rx_packets"));
+ stageLong(2048L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_bytes"));
+ stageLong(256L, new File(mTestProc, "net/xt_qtaguid/iface_stat/wlan0/tx_packets"));
+
+ final NetworkStats stats = mService.getNetworkStatsSummary();
+ assertEquals(7, stats.size());
+ assertStatsEntry(stats, "rmnet0", UID_ALL, TAG_NONE, 1507570L, 489339L);
+ assertStatsEntry(stats, "wlan0", UID_ALL, TAG_NONE, 1024L, 2048L);
+ }
+
public void testKernelTags() throws Exception {
assertEquals("0", tagToKernel(0x0));
assertEquals("214748364800", tagToKernel(0x32));
@@ -90,7 +129,6 @@
assertEquals(2147483647, kernelToTag("0x7fffffff00000000"));
assertEquals(0, kernelToTag("0x0000000000000000"));
assertEquals(2147483136, kernelToTag("0x7FFFFE0000000000"));
-
}
/**
@@ -111,11 +149,23 @@
}
}
+ private void stageLong(long value, File file) throws Exception {
+ new File(file.getParent()).mkdirs();
+ FileWriter out = null;
+ try {
+ out = new FileWriter(file);
+ out.write(Long.toString(value));
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
private static void assertStatsEntry(
- NetworkStats stats, String iface, int uid, int tag, long rx, long tx) {
+ NetworkStats stats, String iface, int uid, int tag, long rxBytes, long txBytes) {
final int i = stats.findIndex(iface, uid, tag);
- assertEquals(rx, stats.rx[i]);
- assertEquals(tx, stats.tx[i]);
+ final NetworkStats.Entry entry = stats.getValues(i, null);
+ assertEquals(rxBytes, entry.rxBytes);
+ assertEquals(txBytes, entry.txBytes);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index b4ac987..504ba42 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -27,7 +27,6 @@
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkTemplate.MATCH_WIFI;
import static org.easymock.EasyMock.anyInt;
import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.capture;
@@ -88,7 +87,7 @@
private static final long TEST_START = 1194220800000L;
private static final String TEST_IFACE = "test0";
- private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
+ private static NetworkTemplate sTemplateWifi = NetworkTemplate.buildTemplateWifi();
private BroadcastInterceptingContext mServiceContext;
private File mPolicyDir;
@@ -447,7 +446,7 @@
// pretend that 512 bytes total have happened
stats = new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 256L, 256L);
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 256L, 2L, 256L, 2L);
expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
.andReturn(stats).atLeastOnce();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index f2c28bb..bd80af9 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -25,8 +25,8 @@
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkTemplate.MATCH_MOBILE_ALL;
-import static android.net.NetworkTemplate.MATCH_WIFI;
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.UID_REMOVED;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
@@ -81,9 +81,9 @@
private static final String IMSI_1 = "310004";
private static final String IMSI_2 = "310260";
- private static NetworkTemplate sTemplateWifi = new NetworkTemplate(MATCH_WIFI, null);
- private static NetworkTemplate sTemplateImsi1 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_1);
- private static NetworkTemplate sTemplateImsi2 = new NetworkTemplate(MATCH_MOBILE_ALL, IMSI_2);
+ private static NetworkTemplate sTemplateWifi = buildTemplateWifi();
+ private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
+ private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
private static final int UID_RED = 1001;
private static final int UID_BLUE = 1002;
@@ -168,7 +168,7 @@
expectTime(TEST_START + elapsedRealtime);
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 2048L));
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 1L, 2048L, 2L));
expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
replay();
@@ -184,7 +184,7 @@
expectTime(TEST_START + elapsedRealtime);
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 4096L, 8192L));
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 4096L, 4L, 8192L, 8L));
expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
replay();
@@ -219,10 +219,10 @@
expectTime(TEST_START + elapsedRealtime);
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 2048L));
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 1024L, 8L, 2048L, 16L));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 2)
- .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 512L, 256L)
- .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 128L, 128L));
+ .addValues(TEST_IFACE, UID_RED, TAG_NONE, 512L, 4L, 256L, 2L)
+ .addValues(TEST_IFACE, UID_BLUE, TAG_NONE, 128L, 1L, 128L, 1L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -264,7 +264,6 @@
public void testStatsBucketResize() throws Exception {
long elapsedRealtime = 0;
NetworkStatsHistory history = null;
- long[] total = null;
assertStatsFilesExist(false);
@@ -284,19 +283,17 @@
expectTime(TEST_START + elapsedRealtime);
expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 512L, 512L));
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 512L, 4L, 512L, 4L));
expectNetworkStatsDetail(buildEmptyStats(elapsedRealtime));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// verify service recorded history
- history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
- total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(512L, total[0]);
- assertEquals(512L, total[1]);
- assertEquals(HOUR_IN_MILLIS, history.bucketDuration);
- assertEquals(2, history.bucketCount);
+ history = mService.getHistoryForNetwork(sTemplateWifi);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L);
+ assertEquals(HOUR_IN_MILLIS, history.getBucketDuration());
+ assertEquals(2, history.size());
verifyAndReset();
// now change bucket duration setting and trigger another poll with
@@ -310,12 +307,10 @@
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
// verify identical stats, but spread across 4 buckets now
- history = mService.getHistoryForNetwork(new NetworkTemplate(MATCH_WIFI, null));
- total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(512L, total[0]);
- assertEquals(512L, total[1]);
- assertEquals(30 * MINUTE_IN_MILLIS, history.bucketDuration);
- assertEquals(4, history.bucketCount);
+ history = mService.getHistoryForNetwork(sTemplateWifi);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 512L);
+ assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration());
+ assertEquals(4, history.size());
verifyAndReset();
}
@@ -338,11 +333,11 @@
expectTime(TEST_START + elapsedRealtime);
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 2048L, 512L));
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 2048L, 16L, 512L, 4L));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 3)
- .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 1536L, 512L)
- .addEntry(TEST_IFACE, UID_RED, 0xF00D, 512L, 512L)
- .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 512L, 0L));
+ .addValues(TEST_IFACE, UID_RED, TAG_NONE, 1536L, 12L, 512L, 4L)
+ .addValues(TEST_IFACE, UID_RED, 0xF00D, 512L, 4L, 512L, 4L)
+ .addValues(TEST_IFACE, UID_BLUE, TAG_NONE, 512L, 4L, 0L, 0L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -373,9 +368,9 @@
expectTime(TEST_START + elapsedRealtime);
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 128L, 1024L));
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 128L, 1L, 1024L, 8L));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 128L, 1024L));
+ .addValues(TEST_IFACE, UID_BLUE, TAG_NONE, 128L, 1L, 1024L, 8L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -412,11 +407,11 @@
expectTime(TEST_START + elapsedRealtime);
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_ALL, TAG_NONE, 4128L, 544L));
+ .addValues(TEST_IFACE, UID_ALL, TAG_NONE, 4128L, 258L, 544L, 34L));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 16L, 16L)
- .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 4096L, 512L)
- .addEntry(TEST_IFACE, UID_GREEN, TAG_NONE, 16L, 16L));
+ .addValues(TEST_IFACE, UID_RED, TAG_NONE, 16L, 1L, 16L, 1L)
+ .addValues(TEST_IFACE, UID_BLUE, TAG_NONE, 4096L, 258L, 512L, 32L)
+ .addValues(TEST_IFACE, UID_GREEN, TAG_NONE, 16L, 1L, 16L, 1L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -468,8 +463,8 @@
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 1024L, 1024L)
- .addEntry(TEST_IFACE, UID_RED, 0xF00D, 512L, 512L));
+ .addValues(TEST_IFACE, UID_RED, TAG_NONE, 1024L, 8L, 1024L, 8L)
+ .addValues(TEST_IFACE, UID_RED, 0xF00D, 512L, 4L, 512L, 4L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -497,7 +492,7 @@
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 512L, 256L));
+ .addValues(TEST_IFACE, UID_RED, TAG_NONE, 512L, 4L, 256L, 2L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -548,9 +543,9 @@
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_RED, TAG_NONE, 50L, 50L)
- .addEntry(TEST_IFACE, UID_RED, 0xF00D, 10L, 10L)
- .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 1024L, 512L));
+ .addValues(TEST_IFACE, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L)
+ .addValues(TEST_IFACE, UID_RED, 0xF00D, 10L, 1L, 10L, 1L)
+ .addValues(TEST_IFACE, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -566,7 +561,7 @@
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats(elapsedRealtime));
expectNetworkStatsDetail(new NetworkStats(elapsedRealtime, 1)
- .addEntry(TEST_IFACE, UID_BLUE, TAG_NONE, 2048L, 1024L));
+ .addValues(TEST_IFACE, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L));
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -574,33 +569,29 @@
// first verify entire history present
NetworkStats stats = mService.getSummaryForAllUid(
sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true);
- assertEquals(3, stats.size);
- assertStatsEntry(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 50L);
- assertStatsEntry(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 10L);
- assertStatsEntry(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 1024L);
+ assertEquals(3, stats.size());
+ assertValues(stats, 0, IFACE_ALL, UID_RED, TAG_NONE, 50L, 5L, 50L, 5L);
+ assertValues(stats, 1, IFACE_ALL, UID_RED, 0xF00D, 10L, 1L, 10L, 1L);
+ assertValues(stats, 2, IFACE_ALL, UID_BLUE, TAG_NONE, 2048L, 16L, 1024L, 8L);
// now verify that recent history only contains one uid
final long currentTime = TEST_START + elapsedRealtime;
stats = mService.getSummaryForAllUid(
sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true);
- assertEquals(1, stats.size);
- assertStatsEntry(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 512L);
+ assertEquals(1, stats.size());
+ assertValues(stats, 0, IFACE_ALL, UID_BLUE, TAG_NONE, 1024L, 8L, 512L, 4L);
verifyAndReset();
}
- private void assertNetworkTotal(NetworkTemplate template, long rx, long tx) {
+ private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long txBytes) {
final NetworkStatsHistory history = mService.getHistoryForNetwork(template);
- final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(rx, total[0]);
- assertEquals(tx, total[1]);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes);
}
- private void assertUidTotal(NetworkTemplate template, int uid, long rx, long tx) {
+ private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long txBytes) {
final NetworkStatsHistory history = mService.getHistoryForUid(template, uid, TAG_NONE);
- final long[] total = history.getTotalData(Long.MIN_VALUE, Long.MAX_VALUE, null);
- assertEquals(rx, total[0]);
- assertEquals(tx, total[1]);
+ assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, txBytes);
}
private void expectSystemReady() throws Exception {
@@ -660,13 +651,24 @@
}
}
- private static void assertStatsEntry(
- NetworkStats stats, int i, String iface, int uid, int tag, long rx, long tx) {
- assertEquals(iface, stats.iface[i]);
- assertEquals(uid, stats.uid[i]);
- assertEquals(tag, stats.tag[i]);
- assertEquals(rx, stats.rx[i]);
- assertEquals(tx, stats.tx[i]);
+ private static void assertValues(NetworkStats stats, int i, String iface, int uid, int tag,
+ long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ final NetworkStats.Entry entry = stats.getValues(i, null);
+ assertEquals(iface, entry.iface);
+ assertEquals(uid, entry.uid);
+ assertEquals(tag, entry.tag);
+ assertEquals(rxBytes, entry.rxBytes);
+ // TODO: enable testing packet counts once stored in history
+// assertEquals(rxPackets, entry.rxPackets);
+ assertEquals(txBytes, entry.txBytes);
+// assertEquals(txPackets, entry.txPackets);
+ }
+
+ private static void assertValues(
+ NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) {
+ final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null);
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
}
private static NetworkState buildWifiState() {
diff --git a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
index 2f275c3..50c18f0 100644
--- a/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ThrottleServiceTest.java
@@ -289,7 +289,7 @@
public void expectGetInterfaceCounter(long rx, long tx) throws Exception {
// TODO: provide elapsedRealtime mock to match TimeAuthority
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
- stats.addEntry(TEST_IFACE, NetworkStats.UID_ALL, NetworkStats.TAG_NONE, rx, tx);
+ stats.addValues(TEST_IFACE, NetworkStats.UID_ALL, NetworkStats.TAG_NONE, rx, 0L, tx, 0L);
expect(mMockNMService.getNetworkStatsSummary()).andReturn(stats).atLeastOnce();
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 66120a1..f7e0c66 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -61,7 +61,7 @@
/** @hide */
public TelephonyManager(Context context) {
if (sContext == null) {
- sContext = context;
+ sContext = context.getApplicationContext();
sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java
index fba3184..a69ce8b 100644
--- a/telephony/java/com/android/internal/telephony/DataCallState.java
+++ b/telephony/java/com/android/internal/telephony/DataCallState.java
@@ -52,7 +52,7 @@
/**
* Class returned by onSetupConnectionCompleted.
*/
- protected enum SetupResult {
+ public enum SetupResult {
SUCCESS,
ERR_BadCommand,
ERR_UnacceptableParameter,
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 5c84fdc..8978f1d 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,30 +17,24 @@
package com.android.internal.telephony;
+import com.android.internal.telephony.DataCallState.SetupResult;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import android.app.PendingIntent;
-import android.net.LinkAddress;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
-import android.net.NetworkUtils;
import android.net.ProxyProperties;
import android.os.AsyncResult;
-import android.os.Bundle;
import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
import android.os.SystemProperties;
import android.text.TextUtils;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
/**
* {@hide}
@@ -497,8 +491,7 @@
} else {
if (DBG) log("onSetupConnectionCompleted received DataCallState: " + response);
cid = response.cid;
- // set link properties based on data call response
- result = setLinkProperties(response, mLinkProperties);
+ result = updateLinkProperty(response).setupResult;
}
return result;
@@ -527,48 +520,41 @@
return response.setLinkProperties(lp, okToUseSystemPropertyDns);
}
- private DataConnectionAc.LinkPropertyChangeAction updateLinkProperty(
- DataCallState newState) {
- DataConnectionAc.LinkPropertyChangeAction changed =
- DataConnectionAc.LinkPropertyChangeAction.NONE;
+ public static class UpdateLinkPropertyResult {
+ public DataCallState.SetupResult setupResult = DataCallState.SetupResult.SUCCESS;
+ public LinkProperties oldLp;
+ public LinkProperties newLp;
+ public UpdateLinkPropertyResult(LinkProperties curLp) {
+ oldLp = curLp;
+ newLp = curLp;
+ }
+ }
- if (newState == null) return changed;
+ private UpdateLinkPropertyResult updateLinkProperty(DataCallState newState) {
+ UpdateLinkPropertyResult result = new UpdateLinkPropertyResult(mLinkProperties);
- DataCallState.SetupResult result;
- LinkProperties newLp = new LinkProperties();
+ if (newState == null) return result;
+
+ DataCallState.SetupResult setupResult;
+ result.newLp = new LinkProperties();
// set link properties based on data call response
- result = setLinkProperties(newState, newLp);
- if (result != DataCallState.SetupResult.SUCCESS) {
- if (DBG) log("UpdateLinkProperty failed : " + result);
- return changed;
+ result.setupResult = setLinkProperties(newState, result.newLp);
+ if (result.setupResult != DataCallState.SetupResult.SUCCESS) {
+ if (DBG) log("updateLinkProperty failed : " + result.setupResult);
+ return result;
}
// copy HTTP proxy as it is not part DataCallState.
- newLp.setHttpProxy(mLinkProperties.getHttpProxy());
+ result.newLp.setHttpProxy(mLinkProperties.getHttpProxy());
- if (DBG) log("old LP=" + mLinkProperties);
- if (DBG) log("new LP=" + newLp);
-
- // Check consistency of link address. Currently we expect
- // only one "global" address is assigned per each IP type.
- Collection<LinkAddress> oLinks = mLinkProperties.getLinkAddresses();
- Collection<LinkAddress> nLinks = newLp.getLinkAddresses();
- for (LinkAddress oldLink : oLinks) {
- for (LinkAddress newLink : nLinks) {
- if ((NetworkUtils.addressTypeMatches(oldLink.getAddress(),
- newLink.getAddress())) &&
- (oldLink.equals(newLink) == false)) {
- return DataConnectionAc.LinkPropertyChangeAction.RESET;
- }
- }
+ if (DBG && (! result.oldLp.equals(result.newLp))) {
+ if (DBG) log("updateLinkProperty old != new");
+ if (VDBG) log("updateLinkProperty old LP=" + result.oldLp);
+ if (VDBG) log("updateLinkProperty new LP=" + result.newLp);
}
+ mLinkProperties = result.newLp;
- if (mLinkProperties == null || !mLinkProperties.equals(newLp)) {
- mLinkProperties = newLp;
- changed = DataConnectionAc.LinkPropertyChangeAction.CHANGED;
- }
-
- return changed;
+ return result;
}
/**
@@ -643,14 +629,15 @@
}
case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
DataCallState newState = (DataCallState) msg.obj;
- DataConnectionAc.LinkPropertyChangeAction action = updateLinkProperty(newState);
+ UpdateLinkPropertyResult result =
+ updateLinkProperty(newState);
if (VDBG) {
- log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE action="
- + action + " newState=" + newState);
+ log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE result="
+ + result + " newState=" + newState);
}
mAc.replyToMessage(msg,
DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
- action.ordinal());
+ result);
break;
}
case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
@@ -688,7 +675,7 @@
case DataConnectionAc.REQ_GET_APNCONTEXT_LIST: {
if (VDBG) log("REQ_GET_APNCONTEXT_LIST num in list=" + mApnList.size());
mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_APNCONTEXT_LIST,
- new ArrayList(mApnList));
+ new ArrayList<ApnContext>(mApnList));
break;
}
case DataConnectionAc.REQ_SET_RECONNECT_INTENT: {
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index 309dbed..a9f2cd1 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
@@ -310,18 +311,18 @@
if (DBG) log("reqUpdateLinkPropertiesDataCallState");
}
- public LinkPropertyChangeAction rspUpdateLinkPropertiesDataCallState(Message response) {
- LinkPropertyChangeAction retVal = LinkPropertyChangeAction.fromInt(response.arg1);
- if (DBG) log("rspUpdateLinkPropertiesState=" + retVal);
+ public UpdateLinkPropertyResult rspUpdateLinkPropertiesDataCallState(Message response) {
+ UpdateLinkPropertyResult retVal = (UpdateLinkPropertyResult)response.obj;
+ if (DBG) log("rspUpdateLinkPropertiesState: retVal=" + retVal);
return retVal;
}
/**
* Update link properties in the data connection
*
- * @return true if link property has been updated. false otherwise.
+ * @return the removed and added addresses.
*/
- public LinkPropertyChangeAction updateLinkPropertiesDataCallStateSync(DataCallState newState) {
+ public UpdateLinkPropertyResult updateLinkPropertiesDataCallStateSync(DataCallState newState) {
Message response =
sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
if ((response != null) &&
@@ -329,7 +330,7 @@
return rspUpdateLinkPropertiesDataCallState(response);
} else {
log("getLinkProperties error response=" + response);
- return LinkPropertyChangeAction.NONE;
+ return new UpdateLinkPropertyResult(new LinkProperties());
}
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 977b412..4f8b525 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -18,10 +18,12 @@
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.database.ContentObserver;
import android.net.LinkCapabilities;
import android.net.LinkProperties;
import android.net.NetworkInfo;
@@ -334,6 +336,31 @@
}
};
+ private final DataRoamingSettingObserver mDataRoamingSettingObserver;
+
+ private class DataRoamingSettingObserver extends ContentObserver {
+ public DataRoamingSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ public void register(Context context) {
+ final ContentResolver resolver = context.getContentResolver();
+ resolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.DATA_ROAMING), false, this);
+ }
+
+ public void unregister(Context context) {
+ final ContentResolver resolver = context.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ // already running on mPhone handler thread
+ handleDataOnRoamingChange();
+ }
+ }
+
protected boolean isDataSetupCompleteOk(AsyncResult ar) {
if (ar.exception != null) {
if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
@@ -398,6 +425,10 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
+
+ // watch for changes to Settings.Secure.DATA_ROAMING
+ mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone);
+ mDataRoamingSettingObserver.register(mPhone.getContext());
}
public void dispose() {
@@ -407,6 +438,7 @@
mDataConnectionAsyncChannels.clear();
mIsDisposed = true;
mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
+ mDataRoamingSettingObserver.unregister(mPhone.getContext());
}
protected void broadcastMessenger() {
@@ -461,32 +493,38 @@
return result;
}
- //The data roaming setting is now located in the shared preferences.
- // See if the requested preference value is the same as that stored in
- // the shared values. If it is not, then update it.
+ /**
+ * Modify {@link Settings.Secure#DATA_ROAMING} value.
+ */
public void setDataOnRoamingEnabled(boolean enabled) {
if (getDataOnRoamingEnabled() != enabled) {
- Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
- Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
- if (mPhone.getServiceState().getRoaming()) {
- if (enabled) {
- resetAllRetryCounts();
- }
- sendMessage(obtainMessage(EVENT_ROAMING_ON));
- }
+ final ContentResolver resolver = mPhone.getContext().getContentResolver();
+ Settings.Secure.putInt(resolver, Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
+ // will trigger handleDataOnRoamingChange() through observer
}
}
- // Retrieve the data roaming setting from the shared preferences.
+ /**
+ * Return current {@link Settings.Secure#DATA_ROAMING} value.
+ */
public boolean getDataOnRoamingEnabled() {
try {
- return Settings.Secure.getInt(
- mPhone.getContext().getContentResolver(), Settings.Secure.DATA_ROAMING) > 0;
+ final ContentResolver resolver = mPhone.getContext().getContentResolver();
+ return Settings.Secure.getInt(resolver, Settings.Secure.DATA_ROAMING) != 0;
} catch (SettingNotFoundException snfe) {
return false;
}
}
+ private void handleDataOnRoamingChange() {
+ if (mPhone.getServiceState().getRoaming()) {
+ if (getDataOnRoamingEnabled()) {
+ resetAllRetryCounts();
+ }
+ sendMessage(obtainMessage(EVENT_ROAMING_ON));
+ }
+ }
+
// abstract methods
protected abstract String getActionIntentReconnectAlarm();
protected abstract void startNetStatPoll();
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 48c5318..4b02e8e 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1430,6 +1430,11 @@
String getMeid();
/**
+ * Retrieves IMEI for phones. Returns null if IMEI is not set.
+ */
+ String getImei();
+
+ /**
* Retrieves the PhoneSubInfo of the Phone
*/
public PhoneSubInfo getPhoneSubInfo();
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index c2212db..b5bfc76f 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -685,6 +685,10 @@
return mActivePhone.getMeid();
}
+ public String getImei() {
+ return mActivePhone.getImei();
+ }
+
public PhoneSubInfo getPhoneSubInfo(){
return mActivePhone.getPhoneSubInfo();
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 4309309..60cf9b7 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -166,4 +166,11 @@
* the value of config_sms_capable
*/
static final String PROPERTY_SMS_SEND = "telephony.sms.send";
+
+ /**
+ * Set to true to indicate a test CSIM card is used in the device.
+ * This property is for testing purpose only. This should not be defined
+ * in commercial configuration.
+ */
+ static final String PROPERTY_TEST_CSIM = "persist.radio.test-csim";
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index a31b704..0d9d27d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -136,6 +136,11 @@
}
@Override
+ public String getImei() {
+ return mImei;
+ }
+
+ @Override
protected void log(String s) {
if (DBG)
Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 8a60b5a..286515e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -122,6 +122,8 @@
//keep track of if phone is in emergency callback mode
private boolean mIsPhoneInEcmState;
private Registrant mEcmExitRespRegistrant;
+ protected String mImei;
+ protected String mImeiSv;
private String mEsn;
private String mMeid;
// string to define how the carrier specifies its own ota sp number
@@ -489,6 +491,11 @@
return mSST.getImsi();
}
+ public String getImei() {
+ Log.e(LOG_TAG, "IMEI is not available in CDMA");
+ return null;
+ }
+
public boolean canConference() {
Log.e(LOG_TAG, "canConference: not possible in CDMA");
return false;
@@ -987,6 +994,8 @@
break;
}
String[] respId = (String[])ar.result;
+ mImei = respId[0];
+ mImeiSv = respId[1];
mEsn = respId[2];
mMeid = respId[3];
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 459cf87..0d551aa 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -39,7 +39,6 @@
CDMALTEPhone mCdmaLtePhone;
private ServiceState mLteSS; // The last LTE state from Voice Registration
- private String mCurrentSpn = null;
public CdmaLteServiceStateTracker(CDMALTEPhone phone) {
super(phone);
@@ -345,6 +344,18 @@
ss.setOperatorAlphaLong(eriText);
}
+ if (cm.getSimState().isSIMReady()) {
+ // SIM is found on the device. If ERI roaming is OFF, use operator name
+ // from CSIM record.
+ boolean showSpn =
+ ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
+ int iconIndex = ss.getCdmaEriIconIndex();
+
+ if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF)) {
+ ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
+ }
+ }
+
String operatorNumeric;
phone.setSystemProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA,
@@ -468,43 +479,6 @@
}
@Override
- protected void updateSpnDisplay() {
- // mOperatorAlphaLong contains the ERI text
- String plmn = ss.getOperatorAlphaLong();
-
- boolean showSpn = false;
- String spn = null;
- if (cm.getSimState().isSIMReady()) {
- // SIM is found on the device. Read the operator name from the card.
- showSpn = ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
- spn = phone.mIccRecords.getServiceProviderName();
-
- // double check we are not printing identicall test
- if (TextUtils.equals(plmn, spn)) showSpn = false;
- }
-
- if (!TextUtils.equals(plmn, mCurPlmn) ||
- !TextUtils.equals(spn, mCurrentSpn)) {
- boolean showPlmn = plmn != null;
- if (DBG) {
- log(String.format("updateSpnDisplay: changed sending intent" +
- " showPlmn='%b' plmn='%s' showSpn='%b' spn='%s'",
- showPlmn, plmn, showSpn, spn));
- }
- Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn);
- intent.putExtra(Intents.EXTRA_SPN, spn);
- intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn);
- intent.putExtra(Intents.EXTRA_PLMN, plmn);
- phone.getContext().sendStickyBroadcast(intent);
- }
-
- mCurPlmn = plmn;
- mCurrentSpn = spn;
- }
-
- @Override
protected void log(String s) {
Log.d(LOG_TAG, "[CdmaLteSST] " + s);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
index 10515f7..fc6abad 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccRecords.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony.cdma;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.IccCardApplication.AppType;
import com.android.internal.telephony.IccFileHandler;
@@ -447,6 +448,12 @@
// to determine if the SIM is provisioned. Otherwise,
// consider the SIM is provisioned. (for case of ordinal
// USIM only UICC.)
+ // If PROPERTY_TEST_CSIM is defined, bypess provision check
+ // and consider the SIM is provisioned.
+ if (SystemProperties.getBoolean(PROPERTY_TEST_CSIM, false)) {
+ return true;
+ }
+
if (phone.mIccCard.isApplicationOnIcc(AppType.APPTYPE_CSIM) &&
((mMdn == null) || (mMin == null))) {
return false;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index d357eac..1db9860 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -855,6 +855,10 @@
return mImeiSv;
}
+ public String getImei() {
+ return mImei;
+ }
+
public String getEsn() {
Log.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method");
return "0";
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index df5898b..ccdb0bf 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -26,6 +26,9 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties.CompareResult;
+import android.net.NetworkUtils;
import android.net.ProxyProperties;
import android.net.TrafficStats;
import android.net.Uri;
@@ -53,6 +56,7 @@
import com.android.internal.telephony.ApnSetting;
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataConnection.UpdateLinkPropertyResult;
import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.Phone;
@@ -1037,7 +1041,7 @@
/**
* @param dcacs Collection of DataConnectionAc reported from RIL.
- * @return List of ApnContext whihc is connected, but does not present in
+ * @return List of ApnContext which is connected, but is not present in
* data connection list reported from RIL.
*/
private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
@@ -1091,32 +1095,30 @@
if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
// Create a hash map to store the dataCallState of each DataConnectionAc
- // TODO: Depends on how frequent the DATA_CALL_LIST got updated,
- // may cache response to reduce comparison.
- HashMap<DataCallState, DataConnectionAc> response;
- response = new HashMap<DataCallState, DataConnectionAc>();
+ HashMap<DataCallState, DataConnectionAc> dataCallStateToDcac;
+ dataCallStateToDcac = new HashMap<DataCallState, DataConnectionAc>();
for (DataCallState dataCallState : dataCallStates) {
DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid);
- if (dcac != null) response.put(dataCallState, dcac);
+ if (dcac != null) dataCallStateToDcac.put(dataCallState, dcac);
}
- // step1: Find a list of "connected" APN which does not have reference to
- // calls listed in the Data Call List.
- List<ApnContext> apnsToClear = findApnContextToClean(response.values());
+ // A list of apns to cleanup, those that aren't in the list we know we have to cleanup
+ List<ApnContext> apnsToCleanup = findApnContextToClean(dataCallStateToDcac.values());
- // step2: Check status of each calls in Data Call List.
- // Collect list of ApnContext associated with the data call if the link
- // has to be cleared.
+ // Find which connections have changed state and send a notification or cleanup
for (DataCallState newState : dataCallStates) {
- DataConnectionAc dcac = response.get(newState);
+ DataConnectionAc dcac = dataCallStateToDcac.get(newState);
- // no associated DataConnection found. Ignore.
- if (dcac == null) continue;
+ if (dcac == null) {
+ loge("onDataStateChanged(ar): No associated DataConnection ignore");
+ continue;
+ }
+ // The list of apn's associated with this DataConnection
Collection<ApnContext> apns = dcac.getApnListSync();
- // filter out ApnContext with "Connected/Connecting" state.
+ // Find which ApnContexts of this DC are in the "Connected/Connecting" state.
ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
for (ApnContext apnContext : apns) {
if (apnContext.getState() == State.CONNECTED ||
@@ -1125,67 +1127,86 @@
connectedApns.add(apnContext);
}
}
-
- // No "Connected" ApnContext associated with this CID. Ignore.
- if (connectedApns.isEmpty()) {
- continue;
- }
-
- if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
- + " newState=" + newState.toString());
- if (newState.active != 0) {
- boolean resetConnection;
- switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) {
- case NONE:
- if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
- resetConnection = false;
- break;
- case CHANGED:
- for (ApnContext apnContext : connectedApns) {
- if (DBG) log("onDataStateChanged(ar): Found and changed, notify (" +
- apnContext.toString() + ")");
- mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
- apnContext.getApnType());
+ if (connectedApns.size() == 0) {
+ if (DBG) log("onDataStateChanged(ar): no connected apns");
+ } else {
+ // Determine if the connection/apnContext should be cleaned up
+ // or just a notification should be sent out.
+ if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
+ + " newState=" + newState.toString());
+ if (newState.active == 0) {
+ if (DBG) {
+ log("onDataStateChanged(ar): inactive, cleanup apns=" + connectedApns);
}
- // Temporary hack, at this time a transition from CDMA -> Global
- // fails so we'll hope for the best and not reset the connection.
- // @see bug/4455071
- if (SystemProperties.getBoolean("telephony.ignore-state-changes",
- true)) {
- log("onDataStateChanged(ar): STOPSHIP don't reset, continue");
- resetConnection = false;
+ apnsToCleanup.addAll(connectedApns);
+ } else {
+ // Its active so update the DataConnections link properties
+ UpdateLinkPropertyResult result =
+ dcac.updateLinkPropertiesDataCallStateSync(newState);
+ if (result.oldLp.equals(result.newLp)) {
+ if (DBG) log("onDataStateChanged(ar): no change");
} else {
- // Things changed so reset connection, when hack is removed
- // this is the normal path.
- log("onDataStateChanged(ar): changed so resetting connection");
- resetConnection = true;
+ if (result.oldLp.isIdenticalInterfaceName(result.newLp)) {
+ if (! result.oldLp.isIdenticalDnses(result.newLp) ||
+ ! result.oldLp.isIdenticalRoutes(result.newLp) ||
+ ! result.oldLp.isIdenticalHttpProxy(result.newLp) ||
+ ! result.oldLp.isIdenticalAddresses(result.newLp)) {
+ // If the same address type was removed and added we need to cleanup
+ CompareResult<LinkAddress> car =
+ result.oldLp.compareAddresses(result.newLp);
+ boolean needToClean = false;
+ for (LinkAddress added : car.added) {
+ for (LinkAddress removed : car.removed) {
+ if (NetworkUtils.addressTypeMatches(removed.getAddress(),
+ added.getAddress())) {
+ needToClean = true;
+ break;
+ }
+ }
+ }
+ if (needToClean) {
+ if (DBG) {
+ log("onDataStateChanged(ar): addr change, cleanup apns=" +
+ connectedApns);
+ }
+ apnsToCleanup.addAll(connectedApns);
+ } else {
+ if (DBG) log("onDataStateChanged(ar): simple change");
+ for (ApnContext apnContext : connectedApns) {
+ mPhone.notifyDataConnection(
+ Phone.REASON_LINK_PROPERTIES_CHANGED,
+ apnContext.getApnType());
+ }
+ }
+ } else {
+ if (DBG) {
+ log("onDataStateChanged(ar): no changes");
+ }
+ }
+ } else {
+ if (DBG) {
+ log("onDataStateChanged(ar): interface change, cleanup apns="
+ + connectedApns);
+ }
+ apnsToCleanup.addAll(connectedApns);
+ }
}
- break;
- case RESET:
- default:
- if (DBG) log("onDataStateChanged(ar): an error, reset connection");
- resetConnection = true;
- break;
}
- if (resetConnection == false) continue;
}
-
- if (DBG) log("onDataStateChanged(ar): reset connection.");
-
- apnsToClear.addAll(connectedApns);
}
- // step3: Clear apn connection if applicable.
- if (!apnsToClear.isEmpty()) {
+ if (apnsToCleanup.size() != 0) {
// Add an event log when the network drops PDP
int cid = getCellLocationId();
EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
TelephonyManager.getDefault().getNetworkType());
}
- for (ApnContext apnContext : apnsToClear) {
+ // Cleanup those dropped connections
+ for (ApnContext apnContext : apnsToCleanup) {
cleanUpConnection(true, apnContext);
}
+
if (DBG) log("onDataStateChanged(ar): X");
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 9dfc015..5c4b446 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -264,6 +264,10 @@
return null;
}
+ public String getImei() {
+ return null;
+ }
+
public String getEsn() {
Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method");
return "0";
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index d438b2c..ed91c49 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -40,7 +40,7 @@
android:textSize="32dip"
android:text="@string/textview_text"
/>
-
+
<EditText android:id="@+id/edittext"
android:layout_height="wrap_content"
android:layout_width="match_parent"
@@ -49,6 +49,40 @@
</LinearLayout>
+ <Button android:id="@+id/button_alert_dialog"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/button_alert_dialog_text"
+ android:textSize="32dip"
+ />
</LinearLayout>
-</FrameLayout>
\ No newline at end of file
+ <LinearLayout
+ android:layout_width="600dip"
+ android:layout_height="128dip"
+ android:layout_gravity="center_vertical"
+ android:orientation="horizontal"
+ style="@android:style/Widget.Holo.Spinner"
+ >
+ <LinearLayout
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical"
+ >
+ <TextView
+ android:id="@+id/spinner_line_1"
+ android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:textSize="16dip"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:gravity="left|center_vertical"
+ android:text="@string/button_text"
+ />
+ </LinearLayout>
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/textview_direction_ltr.xml b/tests/BiDiTests/res/layout/textview_direction_ltr.xml
index f7b7b8e..2c790ec 100644
--- a/tests/BiDiTests/res/layout/textview_direction_ltr.xml
+++ b/tests/BiDiTests/res/layout/textview_direction_ltr.xml
@@ -18,95 +18,232 @@
android:id="@+id/textview_direction_ltr"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:layoutDirection="ltr">
+ android:layoutDirection="ltr"
+ android:textDirection="ltr">
- <LinearLayout android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textDirection="ltr">
-
- <LinearLayout android:orientation="vertical"
+ <TableLayout android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="inherit"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="firstStrong"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="anyRtl"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="ltr"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="rtl"
- />
- </LinearLayout>
+ <TableRow>
+ <TextView android:text="(unspecified)"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
- <LinearLayout android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ <TableRow>
+ <TextView android:text="inherit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="inherit"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="inherit"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="inherit"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="inherit"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="firstStrong"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="anyRtl"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="ltr"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="rtl"
- />
- </LinearLayout>
+ <TableRow>
+ <TextView android:text="firstStrong"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="firstStrong"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="firstStrong"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="firstStrong"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
- </LinearLayout>
+ <TableRow>
+ <TextView android:text="anyRtl"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="anyRtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="anyRtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="anyRtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
-</FrameLayout>
\ No newline at end of file
+ <TableRow>
+ <TextView android:text="ltr"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="ltr"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="ltr"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="ltr"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
+
+ <TableRow>
+ <TextView android:text="rtl"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginRight="7dip"
+ android:layout_marginLeft="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="rtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="rtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="rtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
+
+ </TableLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/textview_direction_rtl.xml b/tests/BiDiTests/res/layout/textview_direction_rtl.xml
index 81c5411..1df100d 100644
--- a/tests/BiDiTests/res/layout/textview_direction_rtl.xml
+++ b/tests/BiDiTests/res/layout/textview_direction_rtl.xml
@@ -18,95 +18,232 @@
android:id="@+id/textview_direction_rtl"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:layoutDirection="rtl">
+ android:layoutDirection="rtl"
+ android:textDirection="rtl">
- <LinearLayout android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textDirection="rtl">
-
- <LinearLayout android:orientation="vertical"
+ <TableLayout android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="inherit"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="firstStrong"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="anyRtl"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="ltr"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_text"
- android:textDirection="rtl"
- />
- </LinearLayout>
+ <TableRow>
+ <TextView android:text="(unspecified)"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
- <LinearLayout android:orientation="vertical"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ <TableRow>
+ <TextView android:text="inherit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="inherit"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="inherit"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="inherit"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="inherit"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="firstStrong"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="anyRtl"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="ltr"
- />
- <TextView android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textSize="24dip"
- android:text="@string/textview_hebrew_text"
- android:textDirection="rtl"
- />
- </LinearLayout>
+ <TableRow>
+ <TextView android:text="firstStrong"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="firstStrong"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="firstStrong"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="firstStrong"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
- </LinearLayout>
+ <TableRow>
+ <TextView android:text="anyRtl"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="anyRtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="anyRtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="anyRtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
-</FrameLayout>
\ No newline at end of file
+ <TableRow>
+ <TextView android:text="ltr"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="ltr"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="ltr"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="ltr"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
+
+ <TableRow>
+ <TextView android:text="rtl"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:typeface="serif"
+ android:layout_marginRight="7dip"
+ android:layout_marginLeft="7dip"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_hebrew_text"
+ android:textDirection="rtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_latin_text"
+ android:textDirection="rtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_multiline_text"
+ android:textDirection="rtl"
+ android:layout_marginLeft="7dip"
+ android:layout_marginRight="7dip"
+ android:background="#444444"
+ />
+ </TableRow>
+
+ </TableLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/textview_drawables_ltr.xml b/tests/BiDiTests/res/layout/textview_drawables_ltr.xml
new file mode 100644
index 0000000..88b13b7
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_drawables_ltr.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/textview_drawables_ltr"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layoutDirection="ltr">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableRight="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/start"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableRight="@drawable/start"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:id="@+id/textview_error"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawablePadding="3dip"
+ />
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/layout/textview_drawables_rtl.xml b/tests/BiDiTests/res/layout/textview_drawables_rtl.xml
new file mode 100644
index 0000000..7f47d5d
--- /dev/null
+++ b/tests/BiDiTests/res/layout/textview_drawables_rtl.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/textview_drawables_rtl"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layoutDirection="rtl">
+
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableRight="@drawable/start"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/start"
+ android:drawableRight="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableLeft="@drawable/end"
+ android:drawableStart="@drawable/start"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawableRight="@drawable/start"
+ android:drawableEnd="@drawable/end"
+ android:drawablePadding="3dip"
+ />
+
+ <TextView android:id="@+id/textview_error"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textSize="24dip"
+ android:text="@string/textview_text"
+ android:drawablePadding="3dip"
+ />
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index c0bbe94..bc99e79 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -23,6 +23,7 @@
<string name="button_left_text">Left</string>
<string name="button_before_text">Start</string>
<string name="button_requestlayout_text">Request Layout</string>
+ <string name="button_alert_dialog_text">AlertDialog</string>
<string name="textview_text">This is a text for a TextView</string>
<string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
<string name="normal_text">Normal String</string>
@@ -40,6 +41,6 @@
<string name="menu_delete">Delete</string>
<string name="textview_hebrew_text">םמab?!</string>
<string name="textview_latin_text">abםמ?!</string>
- <string name="textview_multiline_text">םמ?!\nab?!</string>
+ <string name="textview_multiline_text">םמ?!\nab?!\n?!</string>
</resources>
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index c033879..7002c41 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -134,6 +134,9 @@
addItem(result, "TextDirection LTR", BiDiTestTextViewDirectionLtr.class, R.id.textview_direction_ltr);
addItem(result, "TextDirection RTL", BiDiTestTextViewDirectionRtl.class, R.id.textview_direction_rtl);
+ addItem(result, "TextView Drawables LTR", BiDiTestTextViewDrawablesLtr.class, R.id.textview_drawables_ltr);
+ addItem(result, "TextView Drawables RTL", BiDiTestTextViewDrawablesRtl.class, R.id.textview_drawables_rtl);
+
return result;
}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java
index 9b3918d..f0b7438 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestBasic.java
@@ -16,17 +16,42 @@
package com.android.bidi;
+import android.app.AlertDialog;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Button;
public class BiDiTestBasic extends Fragment {
-
+
+ private View currentView;
+ private Button alertDialogButton;
+ private String[] items = {"This is a very very very very very very very very very very very long Item1", "Item2"};
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- return inflater.inflate(R.layout.basic, container, false);
+ currentView = inflater.inflate(R.layout.basic, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ alertDialogButton = (Button) currentView.findViewById(R.id.button_alert_dialog);
+ alertDialogButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ showDialog();
+ }
+ });
+ }
+
+ private void showDialog() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(currentView.getContext());
+ builder.setSingleChoiceItems(items, 0, null);
+ builder.show();
}
}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java
new file mode 100644
index 0000000..a65d92d
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesLtr.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class BiDiTestTextViewDrawablesLtr extends Fragment {
+
+ private View currentView;
+ private TextView textViewError;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = inflater.inflate(R.layout.textview_drawables_ltr, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ textViewError = (TextView) currentView.findViewById(R.id.textview_error);
+ textViewError.setError("Error!!");
+ }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java
new file mode 100644
index 0000000..7b7e812
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestTextViewDrawablesRtl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 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.bidi;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class BiDiTestTextViewDrawablesRtl extends Fragment {
+
+ private View currentView;
+ private TextView textViewError;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ currentView = inflater.inflate(R.layout.textview_drawables_rtl, container, false);
+ return currentView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ textViewError = (TextView) currentView.findViewById(R.id.textview_error);
+ textViewError.setError("Error!!");
+ }
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index 4f17e52..27e1887 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -168,15 +168,11 @@
drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
paint.setColor(Color.WHITE);
-// char[] glyphs = new char[2*length];
-// int count = getGlyphs(text, glyphs, dir);
-//
-// logGlypths(glyphs, count);
-// drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
- Log.v(TAG, "START -- drawTextWithGlyphs");
- drawTextWithGlyphs(canvas, text, x, y + currentTextSize, dir);
- Log.v(TAG, "END -- drawTextWithGlyphs");
+ Log.v(TAG, "START -- drawText");
+ setPaintDir(paint, dir);
+ canvas.drawText(text, x, y + currentTextSize, this.paint);
+ Log.v(TAG, "END -- drawText");
// Restore old paint properties
paint.setFakeBoldText(oldFakeBold);
@@ -190,26 +186,6 @@
paint.setBidiFlags(dir);
}
- private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
- canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
- }
-
- private void drawTextWithGlyphs(Canvas canvas, String text, int x, int y, int dir) {
- setPaintDir(paint, dir);
- canvas.drawTextWithGlyphs(text, x, y, paint);
- }
-
- private void logGlypths(char[] glyphs, int count) {
- Log.v(TAG, "GlyphIds - count=" + count);
- for (int n = 0; n < count; n++) {
- Log.v(TAG, "GlyphIds - Id[" + n + "]="+ (int)glyphs[n]);
- }
- }
-
- private int getGlyphs(String text, char[] glyphs, int dir) {
- return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs);
- }
-
private void drawInsideRect(Canvas canvas, int color) {
paint.setColor(color);
int width = getWidth();
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index b9bf526..38a85a3 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -38,20 +38,20 @@
vg.setUseDefaultMargins(true);
vg.setAlignmentMode(ALIGN_BOUNDS);
- Group row1 = new Group(1, CENTER);
- Group row2 = new Group(2, CENTER);
- Group row3 = new Group(3, BASELINE);
- Group row4 = new Group(4, BASELINE);
- Group row5 = new Group(5, FILL);
- Group row6 = new Group(6, CENTER);
- Group row7 = new Group(7, CENTER);
+ Spec row1 = spec(0, CENTER);
+ Spec row2 = spec(1, CENTER);
+ Spec row3 = spec(2, BASELINE);
+ Spec row4 = spec(3, BASELINE);
+ Spec row5 = spec(4, FILL, CAN_STRETCH);
+ Spec row6 = spec(5, CENTER);
+ Spec row7 = spec(6, CENTER);
- Group col1a = new Group(1, 4, CENTER);
- Group col1b = new Group(1, 4, LEFT);
- Group col1c = new Group(1, RIGHT);
- Group col2 = new Group(2, LEFT);
- Group col3 = new Group(3, FILL);
- Group col4 = new Group(4, FILL);
+ Spec col1a = spec(0, 4, CENTER);
+ Spec col1b = spec(0, 4, LEFT);
+ Spec col1c = spec(0, RIGHT);
+ Spec col2 = spec(1, LEFT);
+ Spec col3 = spec(2, FILL, CAN_STRETCH);
+ Spec col4 = spec(3, FILL);
{
TextView v = new TextView(context);
@@ -95,12 +95,7 @@
}
{
Space v = new Space(context);
- {
- LayoutParams lp = new LayoutParams(row5, col3);
- lp.columnGroup.flexibility = CAN_STRETCH;
- lp.rowGroup.flexibility = CAN_STRETCH;
- vg.addView(v, lp);
- }
+ vg.addView(v, new LayoutParams(row5, col3));
}
{
Button v = new Button(context);
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
index 505c83d..b1c4486 100755
--- a/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/AlignmentTest.java
@@ -21,7 +21,6 @@
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridLayout;
@@ -84,9 +83,7 @@
Alignment va = VERTICAL_ALIGNMENTS[i];
for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
Alignment ha = HORIZONTAL_ALIGNMENTS[j];
- Group rowGroup = new Group(i, va);
- Group colGroup = new Group(j, ha);
- LayoutParams layoutParams = new LayoutParams(rowGroup, colGroup);
+ LayoutParams layoutParams = new LayoutParams(spec(i, va), spec(j, ha));
String name = VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j];
ViewFactory factory = FACTORIES[(i + j) % FACTORIES.length];
container.addView(factory.create(name, 20), layoutParams);
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
index c5681e2..4ce449a 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/GridLayoutTest.java
@@ -33,9 +33,9 @@
int va = VERTICAL_ALIGNMENTS[i];
for (int j = 0; j < HORIZONTAL_ALIGNMENTS.length; j++) {
int ha = HORIZONTAL_ALIGNMENTS[j];
- GridLayout.Group rowGroup = new GridLayout.Group(UNDEFINED, null);
- GridLayout.Group colGroup = new GridLayout.Group(UNDEFINED, null);
- GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowGroup, colGroup);
+ Spec rowSpec = spec(UNDEFINED, null);
+ Spec colSpec = spec(UNDEFINED, null);
+ GridLayout.LayoutParams lp = new GridLayout.LayoutParams(rowSpec, colSpec);
//GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
lp.setGravity(va | ha);
View v = create(context, VERTICAL_NAMES[i] + "-" + HORIZONTAL_NAMES[j], 20);
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index cb8084d..9fcd05a 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -94,6 +94,15 @@
</activity>
<activity
+ android:name="CanvasTextureViewActivity"
+ android:label="_CanvasTextureView">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="GLTextureViewActivity"
android:label="_TextureViewGL">
<intent-filter>
@@ -382,6 +391,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity
+ android:name="MoreNinePatchesActivity"
+ android:label="_9patch2">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
<activity
android:name="QuickRejectActivity"
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_bg_holo_dark.9.png b/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_bg_holo_dark.9.png
new file mode 100644
index 0000000..089704e
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_bg_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_primary_holo_dark.9.png b/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_primary_holo_dark.9.png
new file mode 100644
index 0000000..385dbc4
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_primary_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_secondary_holo_dark.9.png b/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_secondary_holo_dark.9.png
new file mode 100644
index 0000000..f1510b24
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/progress_vertical_secondary_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_primary_holo.9.png b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_primary_holo.9.png
new file mode 100644
index 0000000..4208c6f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_primary_holo.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_secondary_holo.9.png b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_secondary_holo.9.png
new file mode 100644
index 0000000..b25fb2f
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_secondary_holo.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_dark.9.png b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_dark.9.png
new file mode 100644
index 0000000..25129c6
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_dark.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_light.9.png b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_light.9.png
new file mode 100644
index 0000000..1505e0e
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/scrubber_vertical_track_holo_light.9.png
Binary files differ
diff --git a/tests/HwAccelerationTest/res/drawable/progress_vertical_holo_dark.xml b/tests/HwAccelerationTest/res/drawable/progress_vertical_holo_dark.xml
new file mode 100644
index 0000000..9eb54b7
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/progress_vertical_holo_dark.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:id="@android:id/background"
+ android:drawable="@drawable/progress_vertical_bg_holo_dark" />
+
+ <item android:id="@android:id/secondaryProgress">
+ <scale android:scaleHeight="100%" android:scaleGravity="bottom"
+ android:drawable="@drawable/progress_vertical_secondary_holo_dark" />
+ </item>
+
+ <item android:id="@android:id/progress">
+ <scale android:scaleHeight="100%" android:scaleGravity="bottom"
+ android:drawable="@drawable/progress_vertical_primary_holo_dark" />
+ </item>
+
+</layer-list>
diff --git a/tests/HwAccelerationTest/res/drawable/scrubber_progress_vertical_holo_dark.xml b/tests/HwAccelerationTest/res/drawable/scrubber_progress_vertical_holo_dark.xml
new file mode 100644
index 0000000..0cc56bf
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable/scrubber_progress_vertical_holo_dark.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/background"
+ android:drawable="@drawable/scrubber_vertical_track_holo_dark" />
+ <item android:id="@android:id/secondaryProgress">
+ <scale android:scaleHeight="100%" android:scaleGravity="bottom"
+ android:drawable="@drawable/scrubber_vertical_secondary_holo" />
+ </item>
+ <item android:id="@android:id/progress">
+ <scale android:scaleHeight="100%" android:scaleGravity="bottom"
+ android:drawable="@drawable/scrubber_vertical_primary_holo" />
+ </item>
+</layer-list>
diff --git a/tests/HwAccelerationTest/res/layout/list_activity.xml b/tests/HwAccelerationTest/res/layout/list_activity.xml
index 6bba370..1a5d3d9 100644
--- a/tests/HwAccelerationTest/res/layout/list_activity.xml
+++ b/tests/HwAccelerationTest/res/layout/list_activity.xml
@@ -30,8 +30,10 @@
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="3dip"
+
+ android:onClick="startProfiling"
- android:text="Add" />
+ android:text="Start" />
<Button
android:layout_width="0dip"
@@ -39,8 +41,10 @@
android:layout_height="wrap_content"
android:layout_marginLeft="3dip"
android:layout_marginRight="10dip"
+
+ android:onClick="stopProfiling"
- android:text="Remove" />
+ android:text="Stop" />
</LinearLayout>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
new file mode 100644
index 0000000..4d7f042
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CanvasTextureViewActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 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.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class CanvasTextureViewActivity extends Activity
+ implements TextureView.SurfaceTextureListener {
+ private TextureView mTextureView;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout content = new FrameLayout(this);
+
+ mTextureView = new TextureView(this);
+ mTextureView.setSurfaceTextureListener(this);
+
+ content.addView(mTextureView, new FrameLayout.LayoutParams(500, 500, Gravity.CENTER));
+ setContentView(content);
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ Canvas c = mTextureView.lockCanvas();
+ try {
+ c.drawColor(0xff00ff00);
+ } finally {
+ mTextureView.unlockCanvasAndPost(c);
+ }
+
+ c = mTextureView.lockCanvas(new Rect(100, 100, 200, 200));
+ try {
+ c.drawColor(0xff0000ff);
+ } finally {
+ mTextureView.unlockCanvasAndPost(c);
+ }
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ // Ignored
+ }
+
+ @Override
+ public void onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ // Ignored
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ // Ignored
+ }
+}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
index 8fd4f6b..1493ab9 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ListActivity.java
@@ -20,15 +20,19 @@
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
+import android.os.Environment;
import android.util.DisplayMetrics;
import android.view.ContextMenu;
import android.view.View;
+import android.view.ViewDebug;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
+import java.io.File;
+
@SuppressWarnings({"UnusedDeclaration"})
public class ListActivity extends Activity {
private static final String[] DATA_LIST = {
@@ -87,6 +91,15 @@
registerForContextMenu(list);
}
+
+ public void startProfiling(View v) {
+ ViewDebug.startLooperProfiling(new File(Environment.getExternalStorageDirectory(),
+ "looper.trace"));
+ }
+
+ public void stopProfiling(View v) {
+ ViewDebug.stopLooperProfiling();
+ }
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MoreNinePatchesActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MoreNinePatchesActivity.java
new file mode 100644
index 0000000..0c42387
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MoreNinePatchesActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class MoreNinePatchesActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout layout = new FrameLayout(this);
+ PatchView b = new PatchView (this);
+ b.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT, Gravity.CENTER));
+ layout.addView(b);
+ layout.setBackgroundColor(0xffffffff);
+
+ setContentView(layout);
+ }
+
+ private class PatchView extends View {
+ private final Drawable mDrawable1;
+ private final Drawable mDrawable2;
+ private final Drawable mDrawable3;
+
+ private PatchView(Context context) {
+ super(context);
+ Resources res = context.getResources();
+ mDrawable1 = res.getDrawable(R.drawable.progress_vertical_holo_dark);
+ mDrawable2 = res.getDrawable(R.drawable.scrubber_progress_vertical_holo_dark);
+ mDrawable3 = res.getDrawable(R.drawable.scrubber_vertical_primary_holo);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.translate(100, 100);
+ mDrawable1.setBounds(0, 0, 33, 120);
+ mDrawable1.setLevel(5000);
+ mDrawable1.draw(canvas);
+
+ canvas.translate(20, 0);
+ mDrawable2.setBounds(0, 0, 33, 120);
+ mDrawable2.setLevel(5000);
+ mDrawable2.draw(canvas);
+
+ canvas.translate(20, 0);
+ mDrawable3.setBounds(0, 0, 33, 120);
+ mDrawable3.draw(canvas);
+ }
+ }
+}
diff --git a/tests/RenderScriptTests/FBOTest/Android.mk b/tests/RenderScriptTests/FBOTest/Android.mk
index 55525c4..1df7b26 100644
--- a/tests/RenderScriptTests/FBOTest/Android.mk
+++ b/tests/RenderScriptTests/FBOTest/Android.mk
@@ -14,8 +14,6 @@
# limitations under the License.
#
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -26,5 +24,3 @@
LOCAL_PACKAGE_NAME := FBOTest
include $(BUILD_PACKAGE)
-
-endif
diff --git a/tests/RenderScriptTests/ImageProcessing/Android.mk b/tests/RenderScriptTests/ImageProcessing/Android.mk
index 7fa30d0..507cc92 100644
--- a/tests/RenderScriptTests/ImageProcessing/Android.mk
+++ b/tests/RenderScriptTests/ImageProcessing/Android.mk
@@ -14,8 +14,6 @@
# limitations under the License.
#
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -28,5 +26,3 @@
LOCAL_PACKAGE_NAME := ImageProcessing
include $(BUILD_PACKAGE)
-
-endif
diff --git a/tests/RenderScriptTests/ModelViewer/Android.mk b/tests/RenderScriptTests/ModelViewer/Android.mk
index efe77d7..1d9bacf 100644
--- a/tests/RenderScriptTests/ModelViewer/Android.mk
+++ b/tests/RenderScriptTests/ModelViewer/Android.mk
@@ -14,8 +14,6 @@
# limitations under the License.
#
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -27,5 +25,3 @@
LOCAL_PACKAGE_NAME := ModelViewer
include $(BUILD_PACKAGE)
-
-endif
diff --git a/tests/RenderScriptTests/PerfTest/Android.mk b/tests/RenderScriptTests/PerfTest/Android.mk
index 757b3b1..0d1e7d2 100644
--- a/tests/RenderScriptTests/PerfTest/Android.mk
+++ b/tests/RenderScriptTests/PerfTest/Android.mk
@@ -14,8 +14,6 @@
# limitations under the License.
#
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -29,5 +27,3 @@
LOCAL_PACKAGE_NAME := PerfTest
include $(BUILD_PACKAGE)
-
-endif
diff --git a/tests/RenderScriptTests/tests/Android.mk b/tests/RenderScriptTests/tests/Android.mk
index 6c992d5..880b80f 100644
--- a/tests/RenderScriptTests/tests/Android.mk
+++ b/tests/RenderScriptTests/tests/Android.mk
@@ -14,8 +14,6 @@
# limitations under the License.
#
-ifneq ($(TARGET_SIMULATOR),true)
-
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@@ -26,5 +24,3 @@
LOCAL_PACKAGE_NAME := RSTest
include $(BUILD_PACKAGE)
-
-endif
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index a44072d..6b69864 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -198,7 +198,7 @@
}
void
-Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+Type::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -207,7 +207,7 @@
}
void
-Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+Type::ReadFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -226,7 +226,7 @@
void
Type::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -235,7 +235,7 @@
}
void
-Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+Type::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
__FILE__, __LINE__, m_qualifiedName.c_str());
@@ -284,7 +284,7 @@
}
void
-BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BasicType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, m_unmarshallMethod)));
}
@@ -303,13 +303,13 @@
void
BasicType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, m_createArrayMethod)));
}
void
-BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BasicType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, m_readArrayMethod, 1, v));
}
@@ -331,7 +331,7 @@
}
void
-BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BooleanType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new Comparison(new LiteralExpression("0"),
"!=", new MethodCall(parcel, "readInt"))));
@@ -351,13 +351,13 @@
void
BooleanType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createBooleanArray")));
}
void
-BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+BooleanType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
}
@@ -378,7 +378,7 @@
}
void
-CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+CharType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "readInt"), this));
}
@@ -397,13 +397,13 @@
void
CharType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createCharArray")));
}
void
-CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+CharType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
}
@@ -428,7 +428,7 @@
}
void
-StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+StringType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "readString")));
}
@@ -447,13 +447,13 @@
void
StringType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createStringArray")));
}
void
-StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+StringType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
}
@@ -496,7 +496,7 @@
void
CharSequenceType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
// if (0 != parcel.readInt()) {
// v = TextUtils.createFromParcel(parcel)
@@ -532,7 +532,7 @@
}
void
-RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+RemoteExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -551,7 +551,7 @@
}
void
-RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+RuntimeExceptionType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -571,7 +571,7 @@
}
void
-IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+IBinderType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "readStrongBinder")));
}
@@ -584,13 +584,13 @@
void
IBinderType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
addTo->Add(new Assignment(v, new MethodCall(parcel, "createBinderArray")));
}
void
-IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+IBinderType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
addTo->Add(new MethodCall(parcel, "readBinderArray", 1, v));
}
@@ -610,7 +610,7 @@
}
void
-IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+IInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -631,7 +631,7 @@
void
BinderType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -652,7 +652,7 @@
void
BinderProxyType::CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -672,7 +672,7 @@
}
void
-ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -691,7 +691,7 @@
}
void
-ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelableInterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, __LINE__);
}
@@ -709,25 +709,31 @@
addTo->Add(new MethodCall(parcel, "writeMap", 1, v));
}
-void
-MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+static void EnsureClassLoader(StatementBlock* addTo, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, cl)));
+ // We don't want to look up the class loader once for every
+ // collection argument, so ensure we do it at most once per method.
+ if (*cl == NULL) {
+ *cl = new Variable(CLASSLOADER_TYPE, "cl");
+ addTo->Add(new VariableDeclaration(*cl,
+ new LiteralExpression("this.getClass().getClassLoader()"),
+ CLASSLOADER_TYPE));
+ }
+}
+
+void
+MapType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
+{
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new Assignment(v, new MethodCall(parcel, "readHashMap", 1, *cl)));
}
void
MapType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new MethodCall(parcel, "readMap", 2, v, cl));
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new MethodCall(parcel, "readMap", 2, v, *cl));
}
@@ -751,24 +757,18 @@
}
void
-ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, cl)));
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new Assignment(v, new MethodCall(parcel, "readArrayList", 1, *cl)));
}
void
ListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
- Variable *cl = new Variable(CLASSLOADER_TYPE, "cl");
- addTo->Add(new VariableDeclaration(cl,
- new LiteralExpression("this.getClass().getClassLoader()"),
- CLASSLOADER_TYPE));
- addTo->Add(new MethodCall(parcel, "readList", 2, v, cl));
+ EnsureClassLoader(addTo, cl);
+ addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
}
@@ -811,7 +811,7 @@
}
void
-ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelableType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
// if (0 != parcel.readInt()) {
// v = CLASS.CREATOR.createFromParcel(parcel)
@@ -833,7 +833,7 @@
void
ParcelableType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
// TODO: really, we don't need to have this extra check, but we
// don't have two separate marshalling code paths
@@ -862,7 +862,7 @@
void
ParcelableType::CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
addTo->Add(new Assignment(v, new MethodCall(parcel,
@@ -870,7 +870,7 @@
}
void
-ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+ParcelableType::ReadArrayFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
string creator = v->type->QualifiedName() + ".CREATOR";
addTo->Add(new MethodCall(parcel, "readTypedArray", 2,
@@ -907,7 +907,7 @@
}
void
-InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+InterfaceType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
// v = Interface.asInterface(parcel.readStrongBinder());
string type = v->type->QualifiedName();
@@ -961,14 +961,14 @@
}
void
-GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+GenericType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
fprintf(stderr, "implement GenericType::CreateFromParcel\n");
}
void
GenericType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
fprintf(stderr, "implement GenericType::ReadFromParcel\n");
}
@@ -1009,7 +1009,7 @@
}
void
-GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel)
+GenericListType::CreateFromParcel(StatementBlock* addTo, Variable* v, Variable* parcel, Variable**)
{
if (m_creator == STRING_TYPE->CreatorName()) {
addTo->Add(new Assignment(v,
@@ -1027,7 +1027,7 @@
void
GenericListType::ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable**)
{
if (m_creator == STRING_TYPE->CreatorName()) {
addTo->Add(new MethodCall(parcel, "readStringList", 1, v));
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index 2ea3ac9..662e3a2 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -46,18 +46,18 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
protected:
void SetQualifiedName(const string& qualified);
@@ -89,16 +89,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
string m_marshallMethod;
@@ -116,16 +116,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class CharType : public Type
@@ -136,16 +136,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
@@ -159,16 +159,16 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class CharSequenceType : public Type
@@ -181,7 +181,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class RemoteExceptionType : public Type
@@ -192,7 +192,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class RuntimeExceptionType : public Type
@@ -203,7 +203,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class IBinderType : public Type
@@ -214,14 +214,14 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class IInterfaceType : public Type
@@ -232,7 +232,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class BinderType : public Type
@@ -243,7 +243,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class BinderProxyType : public Type
@@ -254,7 +254,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ParcelType : public Type
@@ -265,7 +265,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ParcelableInterfaceType : public Type
@@ -276,7 +276,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class MapType : public Type
@@ -287,9 +287,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ListType : public Type
@@ -302,9 +302,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class ParcelableType : public Type
@@ -318,18 +318,18 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual bool CanBeArray() const;
virtual void WriteArrayToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
};
class InterfaceType : public Type
@@ -344,7 +344,7 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
bool m_oneway;
@@ -364,9 +364,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
string m_genericArguments;
@@ -387,9 +387,9 @@
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
virtual void CreateFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
virtual void ReadFromParcel(StatementBlock* addTo, Variable* v,
- Variable* parcel);
+ Variable* parcel, Variable** cl);
private:
string m_creator;
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index f17f66b..92f5b64 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -948,8 +948,6 @@
int
main(int argc, const char **argv)
{
- int err = 0;
-
Options options;
int result = parse_options(argc, argv, &options);
if (result) {
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 0f18132..83e3bbc 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -286,25 +286,25 @@
static void
generate_create_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
if (v->dimension == 0) {
- t->CreateFromParcel(addTo, v, parcel);
+ t->CreateFromParcel(addTo, v, parcel, cl);
}
if (v->dimension == 1) {
- t->CreateArrayFromParcel(addTo, v, parcel);
+ t->CreateArrayFromParcel(addTo, v, parcel, cl);
}
}
static void
generate_read_from_parcel(Type* t, StatementBlock* addTo, Variable* v,
- Variable* parcel)
+ Variable* parcel, Variable** cl)
{
if (v->dimension == 0) {
- t->ReadFromParcel(addTo, v, parcel);
+ t->ReadFromParcel(addTo, v, parcel, cl);
}
if (v->dimension == 1) {
- t->ReadArrayFromParcel(addTo, v, parcel);
+ t->ReadArrayFromParcel(addTo, v, parcel, cl);
}
}
@@ -362,6 +362,7 @@
"enforceInterface", 1, new LiteralExpression("DESCRIPTOR")));
// args
+ Variable* cl = NULL;
VariableFactory stubArgs("_arg");
arg = method->args;
while (arg != NULL) {
@@ -373,7 +374,7 @@
if (convert_direction(arg->direction.data) & IN_PARAMETER) {
generate_create_from_parcel(t, c->statements, v,
- stubClass->transact_data);
+ stubClass->transact_data, &cl);
} else {
if (arg->type.dimension == 0) {
c->statements->Add(new Assignment(
@@ -531,7 +532,7 @@
if (_reply != NULL) {
if (_result != NULL) {
generate_create_from_parcel(proxy->returnType,
- tryStatement->statements, _result, _reply);
+ tryStatement->statements, _result, _reply, &cl);
}
// the out/inout parameters
@@ -541,7 +542,7 @@
Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
generate_read_from_parcel(t, tryStatement->statements,
- v, _reply);
+ v, _reply, &cl);
}
arg = arg->next;
}
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png
new file mode 100644
index 0000000..ac5a97b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png
new file mode 100644
index 0000000..a90dc9b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png
new file mode 100644
index 0000000..cb3c433
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
index 4bcd2be..5ab09f0 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
index cfeba3e..62ca427 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
index 1d97e05..ff698fb 100644
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png
new file mode 100644
index 0000000..4cb305d
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png
new file mode 100644
index 0000000..31d35c8
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png
new file mode 100644
index 0000000..f0cc341d
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png
Binary files differ
diff --git a/tools/layoutlib/bridge/src/android/view/Display_Delegate.java b/tools/layoutlib/bridge/src/android/view/Display_Delegate.java
new file mode 100644
index 0000000..83f9cc2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/Display_Delegate.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.layoutlib.bridge.android.BridgeWindowManager;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.os.RemoteException;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Display}
+ *
+ * Through the layoutlib_create tool, the original methods of Display have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class Display_Delegate {
+
+ // ---- Overridden methods ----
+
+ @LayoutlibDelegate
+ public static IWindowManager getWindowManager() {
+ return RenderAction.getCurrentContext().getIWindowManager();
+ }
+
+ // ---- Native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int getDisplayCount() {
+ return 1;
+ }
+
+ @LayoutlibDelegate
+ /** @hide Returns the actual screen size, not including any decor. */
+ /*package*/ static int getRealWidth(Display theDisplay) {
+ // always dynamically query for the current window manager
+ return RenderAction.getCurrentContext().getIWindowManager().getMetrics().widthPixels;
+ }
+
+ @LayoutlibDelegate
+ /** @hide Returns the actual screen size, not including any decor. */
+ /*package*/ static int getRealHeight(Display theDisplay) {
+ // always dynamically query for the current window manager
+ return RenderAction.getCurrentContext().getIWindowManager().getMetrics().heightPixels;
+ }
+
+ @LayoutlibDelegate
+ /** @hide special for when we are faking the screen size. */
+ /*package*/ static int getRawWidth(Display theDisplay) {
+ // same as real since we're not faking compatibility mode.
+ return getRealWidth(theDisplay);
+ }
+
+ @LayoutlibDelegate
+ /** @hide special for when we are faking the screen size. */
+ /*package*/ static int getRawHeight(Display theDisplay) {
+ // same as real since we're not faking compatibility mode.
+ return getRealHeight(theDisplay);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getOrientation(Display theDisplay) {
+ try {
+ // always dynamically query for the current window manager
+ return getWindowManager().getRotation();
+ } catch (RemoteException e) {
+ // this will never been thrown since this is not a true RPC.
+ }
+
+ return Surface.ROTATION_0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeClassInit() {
+ // not needed for now.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void init(Display theDisplay, int display) {
+ // always dynamically query for the current window manager
+ BridgeWindowManager wm = RenderAction.getCurrentContext().getIWindowManager();
+ theDisplay.mDensity = wm.getMetrics().density;
+ theDisplay.mDpiX = wm.getMetrics().xdpi;
+ theDisplay.mDpiY = wm.getMetrics().ydpi;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java b/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java
index 251c053..1fd7836 100644
--- a/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java
+++ b/tools/layoutlib/bridge/src/android/view/accessibility/AccessibilityManager.java
@@ -16,8 +16,11 @@
package android.view.accessibility;
+import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.Context;
import android.content.pm.ServiceInfo;
+import android.view.IWindow;
+import android.view.View;
import java.util.Collections;
import java.util.List;
@@ -38,6 +41,19 @@
private static AccessibilityManager sInstance = new AccessibilityManager();
/**
+ * Listener for the accessibility state.
+ */
+ public interface AccessibilityStateChangeListener {
+
+ /**
+ * Called back on change in the accessibility state.
+ *
+ * @param enabled Whether accessibility is enabled.
+ */
+ public void onAccessibilityStateChanged(boolean enabled);
+ }
+
+ /**
* Get an AccessibilityManager instance (create one if necessary).
*
* @hide
@@ -92,4 +108,30 @@
List<ServiceInfo> services = null;
return Collections.unmodifiableList(services);
}
+
+ public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() {
+ // normal implementation does this in some case, so let's do the same
+ // (unmodifiableList wrapped around null).
+ List<AccessibilityServiceInfo> services = null;
+ return Collections.unmodifiableList(services);
+ }
+
+ public boolean addAccessibilityStateChangeListener(
+ AccessibilityStateChangeListener listener) {
+ return true;
+ }
+
+ public boolean removeAccessibilityStateChangeListener(
+ AccessibilityStateChangeListener listener) {
+ return true;
+ }
+
+ public int addAccessibilityInteractionConnection(IWindow windowToken,
+ IAccessibilityInteractionConnection connection) {
+ return View.NO_ID;
+ }
+
+ public void removeAccessibilityInteractionConnection(IWindow windowToken) {
+ }
+
}
diff --git a/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
new file mode 100644
index 0000000..ec7a67e
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/inputmethod/InputMethodManager_Delegate.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import com.android.layoutlib.bridge.android.BridgeIInputMethodManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.os.Looper;
+
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link InputMethodManager}
+ *
+ * Through the layoutlib_create tool, the original methods of InputMethodManager have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class InputMethodManager_Delegate {
+
+ // ---- Overridden methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static InputMethodManager getInstance(Looper mainLooper) {
+ synchronized (InputMethodManager.mInstanceSync) {
+ if (InputMethodManager.mInstance != null) {
+ return InputMethodManager.mInstance;
+ }
+
+ InputMethodManager.mInstance = new InputMethodManager(new BridgeIInputMethodManager(),
+ mainLooper);
+ }
+ return InputMethodManager.mInstance;
+
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 47fa68e..69e0de9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -64,6 +64,7 @@
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.LayoutInflater;
+import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
@@ -91,7 +92,11 @@
private final Object mProjectKey;
private final DisplayMetrics mMetrics;
private final RenderResources mRenderResources;
+ private final Configuration mConfig;
private final ApplicationInfo mApplicationInfo;
+ private final IProjectCallback mProjectCallback;
+
+ private final BridgeWindowManager mIWindowManager;
private final Map<Object, Map<String, String>> mDefaultPropMaps =
new IdentityHashMap<Object, Map<String,String>>();
@@ -105,7 +110,6 @@
private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
private BridgeInflater mBridgeInflater;
- private final IProjectCallback mProjectCallback;
private BridgeContentResolver mContentResolver;
private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
@@ -113,28 +117,25 @@
/**
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
* @param metrics the {@link DisplayMetrics}.
- * @param themeName The name of the theme to use.
- * @param projectResources the resources of the project. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the
- * map contains (String, {@link }) pairs where the key is the resource name,
- * and the value is the resource value.
- * @param frameworkResources the framework resources. The map contains (String, map) pairs
- * where the string is the type of the resource reference used in the layout file, and the map
- * contains (String, {@link ResourceValue}) pairs where the key is the resource name, and the
- * value is the resource value.
- * @param styleInheritanceMap
+ * @param renderResources the configured resources (both framework and projects) for this
+ * render.
* @param projectCallback
+ * @param config the Configuration object for this render.
* @param targetSdkVersion the targetSdkVersion of the application.
*/
public BridgeContext(Object projectKey, DisplayMetrics metrics,
RenderResources renderResources,
IProjectCallback projectCallback,
+ Configuration config,
int targetSdkVersion) {
mProjectKey = projectKey;
mMetrics = metrics;
mProjectCallback = projectCallback;
mRenderResources = renderResources;
+ mConfig = config;
+
+ mIWindowManager = new BridgeWindowManager(mConfig, metrics, Surface.ROTATION_0);
mFragments.mCurState = Fragment.CREATED;
mFragments.mActivity = this;
@@ -151,13 +152,12 @@
*/
public void initResources() {
AssetManager assetManager = AssetManager.getSystem();
- Configuration config = new Configuration();
mSystemResources = BridgeResources.initSystem(
this,
assetManager,
mMetrics,
- config,
+ mConfig,
mProjectCallback);
mTheme = mSystemResources.newTheme();
}
@@ -197,6 +197,10 @@
return mRenderResources;
}
+ public BridgeWindowManager getIWindowManager() {
+ return mIWindowManager;
+ }
+
public Map<String, String> getDefaultPropMap(Object key) {
return mDefaultPropMaps.get(key);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
new file mode 100644
index 0000000..1394c32
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.android;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
+import com.android.internal.view.IInputMethodManager;
+import com.android.internal.view.InputBindResult;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.text.style.SuggestionSpan;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import java.util.List;
+
+/**
+ * Basic implementation of IInputMethodManager that does nothing.
+ *
+ */
+public class BridgeIInputMethodManager implements IInputMethodManager {
+
+ public void addClient(IInputMethodClient arg0, IInputContext arg1, int arg2, int arg3)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void finishInput(IInputMethodClient arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public InputMethodSubtype getCurrentInputMethodSubtype() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public List<InputMethodInfo> getEnabledInputMethodList() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo arg0,
+ boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public List<InputMethodInfo> getInputMethodList() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public InputMethodSubtype getLastInputMethodSubtype() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public List getShortcutInputMethodsAndSubtypes() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void hideMySoftInput(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean hideSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean notifySuggestionPicked(SuggestionSpan arg0, String arg1, int arg2)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void registerSuggestionSpansForNotification(SuggestionSpan[] arg0)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void removeClient(IInputMethodClient arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean setAdditionalInputMethodSubtypes(IBinder arg0, InputMethodSubtype[] arg1)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean setCurrentInputMethodSubtype(InputMethodSubtype arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void setImeWindowStatus(IBinder arg0, int arg1, int arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setInputMethod(IBinder arg0, String arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setInputMethodAndSubtype(IBinder arg0, String arg1, InputMethodSubtype arg2)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean setInputMethodEnabled(String arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void showInputMethodAndSubtypeEnablerFromClient(IInputMethodClient arg0, String arg1)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void showInputMethodPickerFromClient(IInputMethodClient arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void showMySoftInput(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean showSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public InputBindResult startInput(IInputMethodClient arg0, IInputContext arg1, EditorInfo arg2,
+ boolean arg3, boolean arg4) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean switchToLastInputMethod(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void updateStatusIcon(IBinder arg0, String arg1, int arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void windowGainedFocus(IInputMethodClient arg0, IBinder arg1, boolean arg2,
+ boolean arg3, int arg4, boolean arg5, int arg6) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public IBinder asBinder() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index 260cdc8..fc2f2f8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -131,6 +131,10 @@
*/
@Override
public CharSequence getText(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] != null) {
// FIXME: handle styled strings!
return mResourceData[index].getValue();
@@ -149,6 +153,10 @@
*/
@Override
public String getString(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] != null) {
return mResourceData[index].getValue();
}
@@ -166,6 +174,10 @@
*/
@Override
public boolean getBoolean(int index, boolean defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -188,6 +200,10 @@
*/
@Override
public int getInt(int index, int defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -252,6 +268,10 @@
*/
@Override
public float getFloat(int index, float defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -287,6 +307,10 @@
*/
@Override
public int getColor(int index, int defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -311,6 +335,10 @@
*/
@Override
public ColorStateList getColorStateList(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] == null) {
return null;
}
@@ -395,6 +423,10 @@
*/
@Override
public float getDimension(int index, float defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -568,6 +600,10 @@
*/
@Override
public float getFraction(int index, int base, int pbase, float defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
if (mResourceData[index] == null) {
return defValue;
}
@@ -607,6 +643,10 @@
*/
@Override
public int getResourceId(int index, int defValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return defValue;
+ }
+
// get the Resource for this index
ResourceValue resValue = mResourceData[index];
@@ -718,6 +758,10 @@
*/
@Override
public Drawable getDrawable(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] == null) {
return null;
}
@@ -744,6 +788,10 @@
*/
@Override
public CharSequence[] getTextArray(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (mResourceData[index] == null) {
return null;
}
@@ -776,6 +824,10 @@
*/
@Override
public boolean getValue(int index, TypedValue outValue) {
+ if (index < 0 || index >= mResourceData.length) {
+ return false;
+ }
+
if (mResourceData[index] == null) {
return false;
}
@@ -795,6 +847,10 @@
*/
@Override
public boolean hasValue(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return false;
+ }
+
return mResourceData[index] != null;
}
@@ -811,6 +867,10 @@
*/
@Override
public TypedValue peekValue(int index) {
+ if (index < 0 || index >= mResourceData.length) {
+ return null;
+ }
+
if (getValue(index, mValue)) {
return mValue;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
new file mode 100644
index 0000000..13cd9ec
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2011 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.layoutlib.bridge.android;
+
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
+
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.Display_Delegate;
+import android.view.IApplicationToken;
+import android.view.IOnKeyguardExitResult;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.util.List;
+
+/**
+ * Basic implementation of {@link IWindowManager} so that {@link Display} (and
+ * {@link Display_Delegate}) can return a valid instance.
+ */
+public class BridgeWindowManager implements IWindowManager {
+
+ private final Configuration mConfig;
+ private final DisplayMetrics mMetrics;
+ private final int mRotation;
+
+ public BridgeWindowManager(Configuration config, DisplayMetrics metrics, int rotation) {
+ mConfig = config;
+ mMetrics = metrics;
+ mRotation = rotation;
+ }
+
+ // custom API.
+
+ public DisplayMetrics getMetrics() {
+ return mMetrics;
+ }
+
+ // ---- implementation of IWindowManager that we care about ----
+
+ public int getRotation() throws RemoteException {
+ return mRotation;
+ }
+
+ public int getMaximumSizeDimension() throws RemoteException {
+ return 0;
+ }
+
+ public void getDisplaySize(Point arg0) throws RemoteException {
+ }
+
+ // ---- unused implementation of IWindowManager ----
+
+ public boolean canStatusBarHide() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void addWindowToken(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void clearForcedDisplaySize() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void closeSystemDialogs(String arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void disableKeyguard(IBinder arg0, String arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void executeAppTransition() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void exitKeyguardSecurely(IOnKeyguardExitResult arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void freezeRotation() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public float getAnimationScale(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public float[] getAnimationScales() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getDPadKeycodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getDPadScancodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public InputDevice getInputDevice(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int[] getInputDeviceIds() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int getKeycodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getKeycodeStateForDevice(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public int getPendingAppTransition() throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ public int getScancodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getScancodeStateForDevice(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getSwitchState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getSwitchStateForDevice(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getTrackballKeycodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public int getTrackballScancodeState(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public boolean hasKeys(int[] arg0, boolean[] arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean inKeyguardRestrictedInputMode() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectInputEventNoWait(InputEvent arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectKeyEvent(KeyEvent arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectPointerEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean injectTrackballEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean inputMethodClientHasFocus(IInputMethodClient arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isKeyguardLocked() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isKeyguardSecure() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isViewServerRunning() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public InputChannel monitorInput(String arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void moveAppTokensToBottom(List<IBinder> arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void moveAppTokensToTop(List<IBinder> arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void overridePendingAppTransition(String arg0, int arg1, int arg2)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void reenableKeyguard(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void removeAppToken(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void removeWindowToken(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Bitmap screenshotApplications(IBinder arg0, int arg1, int arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setAnimationScale(int arg0, float arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAnimationScales(float[] arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
+ CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setEventDispatching(boolean arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setFocusedApp(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setForcedDisplaySize(int arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setInTouchMode(boolean arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setNewConfiguration(Configuration arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setPointerSpeed(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setRotation(int arg0, boolean arg1, int arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setStrictModeVisualIndicatorPreference(String arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void showStrictModeViolation(boolean arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean startViewServer(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void statusBarVisibilityChanged(int arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean stopViewServer() throws RemoteException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void thawRotation() throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public Configuration updateOrientationFromAppTokens(Configuration arg0, IBinder arg1)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int watchRotation(IRotationWatcher arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public IBinder asBinder() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 6194f5d..d40222f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -27,10 +27,16 @@
import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
import com.android.resources.ResourceType;
+import com.android.resources.ScreenSize;
+import android.content.res.Configuration;
import android.os.HandlerThread_Delegate;
+import android.os.Looper;
import android.util.DisplayMetrics;
+import android.view.ViewConfiguration;
+import android.view.inputmethod.InputMethodManager;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@@ -94,24 +100,29 @@
// setup the display Metrics.
DisplayMetrics metrics = new DisplayMetrics();
metrics.densityDpi = mParams.getDensity().getDpiValue();
- metrics.density = metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
- metrics.scaledDensity = metrics.density;
- metrics.widthPixels = mParams.getScreenWidth();
- metrics.heightPixels = mParams.getScreenHeight();
- metrics.xdpi = mParams.getXdpi();
- metrics.ydpi = mParams.getYdpi();
+
+ metrics.density = metrics.noncompatDensity =
+ metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
+
+ metrics.scaledDensity = metrics.noncompatScaledDensity = metrics.density;
+
+ metrics.widthPixels = metrics.noncompatWidthPixels = mParams.getScreenWidth();
+ metrics.heightPixels = metrics.noncompatHeightPixels = mParams.getScreenHeight();
+ metrics.xdpi = metrics.noncompatXdpi = mParams.getXdpi();
+ metrics.ydpi = metrics.noncompatYdpi = mParams.getYdpi();
RenderResources resources = mParams.getResources();
// build the context
mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
- mParams.getProjectCallback(), mParams.getTargetSdkVersion());
+ mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion());
setUp();
return SUCCESS.createResult();
}
+
/**
* Prepares the scene for action.
* <p>
@@ -215,6 +226,9 @@
mContext.initResources();
sCurrentContext = mContext;
+ // create an InputMethodManager
+ InputMethodManager.getInstance(Looper.myLooper());
+
LayoutLog currentLog = mParams.getLog();
Bridge.setLog(currentLog);
mContext.getRenderResources().setFrameworkResourceIdProvider(this);
@@ -233,6 +247,12 @@
// quit HandlerThread created during this session.
HandlerThread_Delegate.cleanUp(sCurrentContext);
+ // clear the stored ViewConfiguration since the map is per density and not per context.
+ ViewConfiguration.sConfigurations.clear();
+
+ // remove the InputMethodManager
+ InputMethodManager.mInstance = null;
+
sCurrentContext = null;
Bridge.setLog(null);
@@ -281,6 +301,50 @@
}
}
+ private Configuration getConfiguration() {
+ Configuration config = new Configuration();
+
+ ScreenSize screenSize = mParams.getConfigScreenSize();
+ if (screenSize != null) {
+ switch (screenSize) {
+ case SMALL:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_SMALL;
+ break;
+ case NORMAL:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_NORMAL;
+ break;
+ case LARGE:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_LARGE;
+ break;
+ case XLARGE:
+ config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ break;
+ }
+ }
+
+ Density density = mParams.getDensity();
+ if (density == null) {
+ density = Density.MEDIUM;
+ }
+
+ config.screenWidthDp = mParams.getScreenWidth() / density.getDpiValue();
+ config.screenHeightDp = mParams.getScreenHeight() / density.getDpiValue();
+ if (config.screenHeightDp < config.screenWidthDp) {
+ config.smallestScreenWidthDp = config.screenHeightDp;
+ } else {
+ config.smallestScreenWidthDp = config.screenWidthDp;
+ }
+
+ // never run in compat mode:
+ config.compatScreenWidthDp = config.screenWidthDp;
+ config.compatScreenHeightDp = config.screenHeightDp;
+
+ // TODO: fill in more config info.
+
+ return config;
+ }
+
+
// --- FrameworkResourceIdProvider methods
@Override
diff --git a/tools/layoutlib/bridge/tests/.classpath b/tools/layoutlib/bridge/tests/.classpath
index 9cc2433..027bc67 100644
--- a/tools/layoutlib/bridge/tests/.classpath
+++ b/tools/layoutlib/bridge/tests/.classpath
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="res"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/layoutlib_bridge"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 233f72ec..df7e04f 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -103,9 +103,11 @@
"android.os.Handler#sendMessageAtTime",
"android.os.HandlerThread#run",
"android.os.Build#getString",
+ "android.view.Display#getWindowManager",
"android.view.LayoutInflater#rInflate",
"android.view.LayoutInflater#parseInclude",
"android.view.View#isInEditMode",
+ "android.view.inputmethod.InputMethodManager#getInstance",
"com.android.internal.util.XmlUtils#convertValueToInt",
// TODO: comment out once DelegateClass is working
};
@@ -154,6 +156,7 @@
"android.graphics.Xfermode",
"android.os.SystemClock",
"android.util.FloatMath",
+ "android.view.Display",
"libcore.icu.ICU",
};
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index c1affa6..fcdbd2c 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -57,6 +57,7 @@
private static final boolean RELEASE_SOCKET = true;
private static final boolean DONT_RELEASE_SOCKET = false;
private static final int SESSION_TIMEOUT = 5; // in seconds
+ private static final int TRANSFER_TIMEOUT = 15; // in seconds
/** Listener for events relating to a SIP call, such as when a call is being
* recieved ("on ringing") or a call is outgoing ("on calling").
@@ -537,10 +538,14 @@
Log.v(TAG, "onCallTransferring mSipSession:"
+ mSipSession + " newSession:" + newSession);
mTransferringSession = newSession;
- // session changing request
try {
- String answer = createAnswer(sessionDescription).encode();
- newSession.answerCall(answer, SESSION_TIMEOUT);
+ if (sessionDescription == null) {
+ newSession.makeCall(newSession.getPeerProfile(),
+ createOffer().encode(), TRANSFER_TIMEOUT);
+ } else {
+ String answer = createAnswer(sessionDescription).encode();
+ newSession.answerCall(answer, SESSION_TIMEOUT);
+ }
} catch (Throwable e) {
Log.e(TAG, "onCallTransferring()", e);
newSession.endCall();
diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java
index c031bc1..dc628e0 100644
--- a/voip/java/com/android/server/sip/SipHelper.java
+++ b/voip/java/com/android/server/sip/SipHelper.java
@@ -19,6 +19,9 @@
import gov.nist.javax.sip.SipStackExt;
import gov.nist.javax.sip.clientauthutils.AccountManager;
import gov.nist.javax.sip.clientauthutils.AuthenticationHelper;
+import gov.nist.javax.sip.header.extensions.ReferencesHeader;
+import gov.nist.javax.sip.header.extensions.ReferredByHeader;
+import gov.nist.javax.sip.header.extensions.ReplacesHeader;
import android.net.sip.SipProfile;
import android.util.Log;
@@ -284,14 +287,18 @@
}
public ClientTransaction sendInvite(SipProfile caller, SipProfile callee,
- String sessionDescription, String tag)
- throws SipException {
+ String sessionDescription, String tag, ReferredByHeader referredBy,
+ String replaces) throws SipException {
try {
Request request = createRequest(Request.INVITE, caller, callee, tag);
+ if (referredBy != null) request.addHeader(referredBy);
+ if (replaces != null) {
+ request.addHeader(mHeaderFactory.createHeader(
+ ReplacesHeader.NAME, replaces));
+ }
request.setContent(sessionDescription,
mHeaderFactory.createContentTypeHeader(
"application", "sdp"));
-
ClientTransaction clientTransaction =
mSipProvider.getNewClientTransaction(request);
if (DEBUG) Log.d(TAG, "send INVITE: " + request);
@@ -455,6 +462,25 @@
}
}
+ public void sendReferNotify(Dialog dialog, String content)
+ throws SipException {
+ try {
+ Request request = dialog.createRequest(Request.NOTIFY);
+ request.addHeader(mHeaderFactory.createSubscriptionStateHeader(
+ "active;expires=60"));
+ // set content here
+ request.setContent(content,
+ mHeaderFactory.createContentTypeHeader(
+ "message", "sipfrag"));
+ request.addHeader(mHeaderFactory.createEventHeader(
+ ReferencesHeader.REFER));
+ if (DEBUG) Log.d(TAG, "send NOTIFY: " + request);
+ dialog.sendRequest(mSipProvider.getNewClientTransaction(request));
+ } catch (ParseException e) {
+ throw new SipException("sendReferNotify()", e);
+ }
+ }
+
public void sendInviteRequestTerminated(Request inviteRequest,
ServerTransaction inviteTransaction) throws SipException {
try {
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 4e44402..48d9b17 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -18,12 +18,15 @@
import gov.nist.javax.sip.clientauthutils.AccountManager;
import gov.nist.javax.sip.clientauthutils.UserCredentials;
-import gov.nist.javax.sip.header.SIPHeaderNames;
import gov.nist.javax.sip.header.ProxyAuthenticate;
+import gov.nist.javax.sip.header.ReferTo;
+import gov.nist.javax.sip.header.SIPHeaderNames;
+import gov.nist.javax.sip.header.StatusLine;
import gov.nist.javax.sip.header.WWWAuthenticate;
import gov.nist.javax.sip.header.extensions.ReferredByHeader;
import gov.nist.javax.sip.header.extensions.ReplacesHeader;
import gov.nist.javax.sip.message.SIPMessage;
+import gov.nist.javax.sip.message.SIPResponse;
import android.net.sip.ISipSession;
import android.net.sip.ISipSessionListener;
@@ -71,12 +74,15 @@
import javax.sip.header.CSeqHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
+import javax.sip.header.HeaderAddress;
import javax.sip.header.MinExpiresHeader;
+import javax.sip.header.ReferToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Message;
import javax.sip.message.Request;
import javax.sip.message.Response;
+
/**
* Manages {@link ISipSession}'s for a SIP account.
*/
@@ -390,25 +396,26 @@
}
}
+ private SipSessionImpl createNewSession(RequestEvent event,
+ ISipSessionListener listener, ServerTransaction transaction,
+ int newState) throws SipException {
+ SipSessionImpl newSession = new SipSessionImpl(listener);
+ newSession.mServerTransaction = transaction;
+ newSession.mState = newState;
+ newSession.mDialog = newSession.mServerTransaction.getDialog();
+ newSession.mInviteReceived = event;
+ newSession.mPeerProfile = createPeerProfile((HeaderAddress)
+ event.getRequest().getHeader(FromHeader.NAME));
+ newSession.mPeerSessionDescription =
+ extractContent(event.getRequest());
+ return newSession;
+ }
+
private class SipSessionCallReceiverImpl extends SipSessionImpl {
public SipSessionCallReceiverImpl(ISipSessionListener listener) {
super(listener);
}
- private SipSessionImpl createNewSession(RequestEvent event,
- ISipSessionListener listener, ServerTransaction transaction)
- throws SipException {
- SipSessionImpl newSession = new SipSessionImpl(listener);
- newSession.mServerTransaction = transaction;
- newSession.mState = SipSession.State.INCOMING_CALL;
- newSession.mDialog = newSession.mServerTransaction.getDialog();
- newSession.mInviteReceived = event;
- newSession.mPeerProfile = createPeerProfile(event.getRequest());
- newSession.mPeerSessionDescription =
- extractContent(event.getRequest());
- return newSession;
- }
-
private int processInviteWithReplaces(RequestEvent event,
ReplacesHeader replaces) {
String callId = replaces.getCallId();
@@ -452,7 +459,8 @@
// got INVITE w/ replaces request.
newSession = createNewSession(event,
replacedSession.mProxy.getListener(),
- mSipHelper.getServerTransaction(event));
+ mSipHelper.getServerTransaction(event),
+ SipSession.State.INCOMING_CALL);
newSession.mProxy.onCallTransferring(newSession,
newSession.mPeerSessionDescription);
} else {
@@ -461,7 +469,8 @@
} else {
// New Incoming call.
newSession = createNewSession(event, mProxy,
- mSipHelper.sendRinging(event, generateTag()));
+ mSipHelper.sendRinging(event, generateTag()),
+ SipSession.State.INCOMING_CALL);
mProxy.onRinging(newSession, newSession.mPeerProfile,
newSession.mPeerSessionDescription);
}
@@ -507,6 +516,11 @@
private SipSessionImpl mKeepAliveSession;
+ // the following three members are used for handling refer request.
+ SipSessionImpl mReferSession;
+ ReferredByHeader mReferredBy;
+ String mReplaces;
+
// lightweight timer
class SessionTimer {
private boolean mRunning = true;
@@ -556,6 +570,9 @@
mInviteReceived = null;
mPeerSessionDescription = null;
mAuthenticationRetryCount = 0;
+ mReferSession = null;
+ mReferredBy = null;
+ mReplaces = null;
if (mDialog != null) mDialog.delete();
mDialog = null;
@@ -969,15 +986,26 @@
return (proxyAuth == null) ? null : proxyAuth.getNonce();
}
+ private String getResponseString(int statusCode) {
+ StatusLine statusLine = new StatusLine();
+ statusLine.setStatusCode(statusCode);
+ statusLine.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode));
+ return statusLine.encode();
+ }
+
private boolean readyForCall(EventObject evt) throws SipException {
// expect MakeCallCommand, RegisterCommand, DEREGISTER
if (evt instanceof MakeCallCommand) {
mState = SipSession.State.OUTGOING_CALL;
MakeCallCommand cmd = (MakeCallCommand) evt;
mPeerProfile = cmd.getPeerProfile();
- mClientTransaction = mSipHelper.sendInvite(mLocalProfile,
- mPeerProfile, cmd.getSessionDescription(),
- generateTag());
+ if (mReferSession != null) {
+ mSipHelper.sendReferNotify(mReferSession.mDialog,
+ getResponseString(Response.TRYING));
+ }
+ mClientTransaction = mSipHelper.sendInvite(
+ mLocalProfile, mPeerProfile, cmd.getSessionDescription(),
+ generateTag(), mReferredBy, mReplaces);
mDialog = mClientTransaction.getDialog();
addSipSession(this);
startSessionTimer(cmd.getTimeout());
@@ -1072,6 +1100,12 @@
}
return true;
case Response.OK:
+ if (mReferSession != null) {
+ mSipHelper.sendReferNotify(mReferSession.mDialog,
+ getResponseString(Response.OK));
+ // since we don't need to remember the session anymore.
+ mReferSession = null;
+ }
mSipHelper.sendInviteAck(event, mDialog);
mPeerSessionDescription = extractContent(response);
establishCall(true);
@@ -1087,6 +1121,10 @@
// rfc3261#section-14.1; re-schedule invite
return true;
default:
+ if (mReferSession != null) {
+ mSipHelper.sendReferNotify(mReferSession.mDialog,
+ getResponseString(Response.SERVICE_UNAVAILABLE));
+ }
if (statusCode >= 400) {
// error: an ack is sent automatically by the stack
onError(response);
@@ -1155,6 +1193,38 @@
return false;
}
+ private boolean processReferRequest(RequestEvent event)
+ throws SipException {
+ try {
+ ReferToHeader referto = (ReferToHeader) event.getRequest()
+ .getHeader(ReferTo.NAME);
+ Address address = referto.getAddress();
+ SipURI uri = (SipURI) address.getURI();
+ String replacesHeader = uri.getHeader(ReplacesHeader.NAME);
+ String username = uri.getUser();
+ if (username == null) {
+ mSipHelper.sendResponse(event, Response.BAD_REQUEST);
+ return false;
+ }
+ // send notify accepted
+ mSipHelper.sendResponse(event, Response.ACCEPTED);
+ SipSessionImpl newSession = createNewSession(event,
+ this.mProxy.getListener(),
+ mSipHelper.getServerTransaction(event),
+ SipSession.State.READY_TO_CALL);
+ newSession.mReferSession = this;
+ newSession.mReferredBy = (ReferredByHeader) event.getRequest()
+ .getHeader(ReferredByHeader.NAME);
+ newSession.mReplaces = replacesHeader;
+ newSession.mPeerProfile = createPeerProfile(referto);
+ newSession.mProxy.onCallTransferring(newSession,
+ null);
+ return true;
+ } catch (IllegalArgumentException e) {
+ throw new SipException("createPeerProfile()", e);
+ }
+ }
+
private boolean inCall(EventObject evt) throws SipException {
// expect END_CALL cmd, BYE request, hold call (MakeCallCommand)
// OK retransmission is handled in SipStack
@@ -1175,6 +1245,8 @@
mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
endCallNormally();
return true;
+ } else if (isRequestEvent(Request.REFER, evt)) {
+ return processReferRequest((RequestEvent) evt);
} else if (evt instanceof MakeCallCommand) {
// to change call
mState = SipSession.State.OUTGOING_CALL;
@@ -1182,6 +1254,8 @@
((MakeCallCommand) evt).getSessionDescription());
startSessionTimer(((MakeCallCommand) evt).getTimeout());
return true;
+ } else if (evt instanceof ResponseEvent) {
+ if (expectResponse(Request.NOTIFY, evt)) return true;
}
return false;
}
@@ -1558,12 +1632,10 @@
return false;
}
- private static SipProfile createPeerProfile(Request request)
+ private static SipProfile createPeerProfile(HeaderAddress header)
throws SipException {
try {
- FromHeader fromHeader =
- (FromHeader) request.getHeader(FromHeader.NAME);
- Address address = fromHeader.getAddress();
+ Address address = header.getAddress();
SipURI uri = (SipURI) address.getURI();
String username = uri.getUser();
if (username == null) username = ANONYMOUS;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogService.java b/wifi/java/android/net/wifi/WifiWatchdogService.java
deleted file mode 100644
index bce4b3a..0000000
--- a/wifi/java/android/net/wifi/WifiWatchdogService.java
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- * 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 android.net.wifi;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.DnsPinger;
-import android.net.NetworkInfo;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Scanner;
-
-/**
- * {@link WifiWatchdogService} monitors the initial connection to a Wi-Fi
- * network with multiple access points. After the framework successfully
- * connects to an access point, the watchdog verifies connectivity by 'pinging'
- * the configured DNS server using {@link DnsPinger}.
- * <p>
- * On DNS check failure, the BSSID is blacklisted if it is reasonably likely
- * that another AP might have internet access; otherwise the SSID is disabled.
- * <p>
- * On DNS success, the WatchdogService initiates a walled garden check via an
- * http get. A browser windows is activated if a walled garden is detected.
- *
- * @hide
- */
-public class WifiWatchdogService {
-
- private static final String WWS_TAG = "WifiWatchdogService";
-
- private static final boolean VDBG = true;
- private static final boolean DBG = true;
-
- // Used for verbose logging
- private String mDNSCheckLogStr;
-
- private Context mContext;
- private ContentResolver mContentResolver;
- private WifiManager mWifiManager;
-
- private WifiWatchdogHandler mHandler;
-
- private DnsPinger mDnsPinger;
-
- private IntentFilter mIntentFilter;
- private BroadcastReceiver mBroadcastReceiver;
- private boolean mBroadcastsEnabled;
-
- private static final int WIFI_SIGNAL_LEVELS = 4;
-
- /**
- * Low signal is defined as less than or equal to cut off
- */
- private static final int LOW_SIGNAL_CUTOFF = 0;
-
- private static final long MIN_LOW_SIGNAL_CHECK_INTERVAL = 2 * 60 * 1000;
- private static final long MIN_SINGLE_DNS_CHECK_INTERVAL = 10 * 60 * 1000;
- private static final long MIN_WALLED_GARDEN_INTERVAL = 15 * 60 * 1000;
-
- private static final int MAX_CHECKS_PER_SSID = 9;
- private static final int NUM_DNS_PINGS = 7;
- private static double MIN_RESPONSE_RATE = 0.50;
-
- // TODO : Adjust multiple DNS downward to 250 on repeated failure
- // private static final int MULTI_DNS_PING_TIMEOUT_MS = 250;
-
- private static final int DNS_PING_TIMEOUT_MS = 800;
- private static final long DNS_PING_INTERVAL = 250;
-
- private static final long BLACKLIST_FOLLOWUP_INTERVAL = 15 * 1000;
-
- private Status mStatus = new Status();
-
- private static class Status {
- String bssid = "";
- String ssid = "";
-
- HashSet<String> allBssids = new HashSet<String>();
- int numFullDNSchecks = 0;
-
- long lastSingleCheckTime = -24 * 60 * 60 * 1000;
- long lastWalledGardenCheckTime = -24 * 60 * 60 * 1000;
-
- WatchdogState state = WatchdogState.INACTIVE;
-
- // Info for dns check
- int dnsCheckTries = 0;
- int dnsCheckSuccesses = 0;
-
- public int signal = -200;
-
- }
-
- private enum WatchdogState {
- /**
- * Full DNS check in progress
- */
- DNS_FULL_CHECK,
-
- /**
- * Walled Garden detected, will pop up browser next round.
- */
- WALLED_GARDEN_DETECTED,
-
- /**
- * DNS failed, will blacklist/disable AP next round
- */
- DNS_CHECK_FAILURE,
-
- /**
- * Online or displaying walled garden auth page
- */
- CHECKS_COMPLETE,
-
- /**
- * Watchdog idle, network has been blacklisted or received disconnect
- * msg
- */
- INACTIVE,
-
- BLACKLISTED_AP
- }
-
- public WifiWatchdogService(Context context) {
- mContext = context;
- mContentResolver = context.getContentResolver();
- mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- mDnsPinger = new DnsPinger("WifiWatchdogServer.DnsPinger", context,
- ConnectivityManager.TYPE_WIFI);
-
- HandlerThread handlerThread = new HandlerThread("WifiWatchdogServiceThread");
- handlerThread.start();
- mHandler = new WifiWatchdogHandler(handlerThread.getLooper());
-
- setupNetworkReceiver();
-
- // The content observer to listen needs a handler, which createThread
- // creates
- registerForSettingsChanges();
-
- // Start things off
- if (isWatchdogEnabled()) {
- mHandler.sendEmptyMessage(WifiWatchdogHandler.MESSAGE_CONTEXT_EVENT);
- }
- }
-
- /**
- *
- */
- private void setupNetworkReceiver() {
- mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- mHandler.sendMessage(mHandler.obtainMessage(
- WifiWatchdogHandler.MESSAGE_NETWORK_EVENT,
- intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO)
- ));
- } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
- mHandler.sendEmptyMessage(WifiWatchdogHandler.RSSI_CHANGE_EVENT);
- } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- mHandler.sendEmptyMessage(WifiWatchdogHandler.SCAN_RESULTS_AVAILABLE);
- } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- mHandler.sendMessage(mHandler.obtainMessage(
- WifiWatchdogHandler.WIFI_STATE_CHANGE,
- intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 4)));
- }
- }
- };
-
- mIntentFilter = new IntentFilter();
- mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
- mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
- }
-
- /**
- * Observes the watchdog on/off setting, and takes action when changed.
- */
- private void registerForSettingsChanges() {
- ContentObserver contentObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- mHandler.sendEmptyMessage((WifiWatchdogHandler.MESSAGE_CONTEXT_EVENT));
- }
- };
-
- mContext.getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON),
- false, contentObserver);
- }
-
- private void handleNewConnection() {
- WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
- String newSsid = wifiInfo.getSSID();
- String newBssid = wifiInfo.getBSSID();
-
- if (VDBG) {
- Slog.v(WWS_TAG, String.format("handleConnected:: old (%s, %s) ==> new (%s, %s)",
- mStatus.ssid, mStatus.bssid, newSsid, newBssid));
- }
-
- if (TextUtils.isEmpty(newSsid) || TextUtils.isEmpty(newBssid)) {
- return;
- }
-
- if (!TextUtils.equals(mStatus.ssid, newSsid)) {
- mStatus = new Status();
- mStatus.ssid = newSsid;
- }
-
- mStatus.bssid = newBssid;
- mStatus.allBssids.add(newBssid);
- mStatus.signal = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), WIFI_SIGNAL_LEVELS);
-
- initDnsFullCheck();
- }
-
- public void updateRssi() {
- WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
- if (!TextUtils.equals(mStatus.ssid, wifiInfo.getSSID()) ||
- !TextUtils.equals(mStatus.bssid, wifiInfo.getBSSID())) {
- return;
- }
-
- mStatus.signal = WifiManager.calculateSignalLevel(wifiInfo.getRssi(), WIFI_SIGNAL_LEVELS);
- }
-
- /**
- * Single step in state machine
- */
- private void handleStateStep() {
- // Slog.v(WWS_TAG, "handleStateStep:: " + mStatus.state);
-
- switch (mStatus.state) {
- case DNS_FULL_CHECK:
- if (VDBG) {
- Slog.v(WWS_TAG, "DNS_FULL_CHECK: " + mDNSCheckLogStr);
- }
-
- long pingResponseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
- DNS_PING_TIMEOUT_MS);
-
- mStatus.dnsCheckTries++;
- if (pingResponseTime >= 0)
- mStatus.dnsCheckSuccesses++;
-
- if (DBG) {
- if (pingResponseTime >= 0) {
- mDNSCheckLogStr += " | " + pingResponseTime;
- } else {
- mDNSCheckLogStr += " | " + "x";
- }
- }
-
- switch (currentDnsCheckStatus()) {
- case SUCCESS:
- if (DBG) {
- Slog.d(WWS_TAG, mDNSCheckLogStr + " -- Success");
- }
- doWalledGardenCheck();
- break;
- case FAILURE:
- if (DBG) {
- Slog.d(WWS_TAG, mDNSCheckLogStr + " -- Failure");
- }
- mStatus.state = WatchdogState.DNS_CHECK_FAILURE;
- break;
- case INCOMPLETE:
- // Taking no action
- break;
- }
- break;
- case DNS_CHECK_FAILURE:
- WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
- if (!mStatus.ssid.equals(wifiInfo.getSSID()) ||
- !mStatus.bssid.equals(wifiInfo.getBSSID())) {
- Slog.i(WWS_TAG, "handleState DNS_CHECK_FAILURE:: network has changed!");
- mStatus.state = WatchdogState.INACTIVE;
- break;
- }
-
- if (mStatus.numFullDNSchecks >= mStatus.allBssids.size() ||
- mStatus.numFullDNSchecks >= MAX_CHECKS_PER_SSID) {
- disableAP(wifiInfo);
- } else {
- blacklistAP();
- }
- break;
- case WALLED_GARDEN_DETECTED:
- popUpBrowser();
- mStatus.state = WatchdogState.CHECKS_COMPLETE;
- break;
- case BLACKLISTED_AP:
- WifiInfo wifiInfo2 = mWifiManager.getConnectionInfo();
- if (wifiInfo2.getSupplicantState() != SupplicantState.COMPLETED) {
- Slog.d(WWS_TAG,
- "handleState::BlacklistedAP - offline, but didn't get disconnect!");
- mStatus.state = WatchdogState.INACTIVE;
- break;
- }
- if (mStatus.bssid.equals(wifiInfo2.getBSSID())) {
- Slog.d(WWS_TAG, "handleState::BlacklistedAP - connected to same bssid");
- if (!handleSingleDnsCheck()) {
- disableAP(wifiInfo2);
- break;
- }
- }
-
- Slog.d(WWS_TAG, "handleState::BlacklistedAP - Simiulating a new connection");
- handleNewConnection();
- break;
- }
- }
-
- private void doWalledGardenCheck() {
- if (!isWalledGardenTestEnabled()) {
- if (VDBG)
- Slog.v(WWS_TAG, "Skipping walled garden check - disabled");
- mStatus.state = WatchdogState.CHECKS_COMPLETE;
- return;
- }
- long waitTime = waitTime(MIN_WALLED_GARDEN_INTERVAL,
- mStatus.lastWalledGardenCheckTime);
- if (waitTime > 0) {
- if (VDBG) {
- Slog.v(WWS_TAG, "Skipping walled garden check - wait " +
- waitTime + " ms.");
- }
- mStatus.state = WatchdogState.CHECKS_COMPLETE;
- return;
- }
-
- mStatus.lastWalledGardenCheckTime = SystemClock.elapsedRealtime();
- if (isWalledGardenConnection()) {
- if (DBG)
- Slog.d(WWS_TAG,
- "Walled garden test complete - walled garden detected");
- mStatus.state = WatchdogState.WALLED_GARDEN_DETECTED;
- } else {
- if (DBG)
- Slog.d(WWS_TAG, "Walled garden test complete - online");
- mStatus.state = WatchdogState.CHECKS_COMPLETE;
- }
- }
-
- private boolean handleSingleDnsCheck() {
- mStatus.lastSingleCheckTime = SystemClock.elapsedRealtime();
- long responseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
- DNS_PING_TIMEOUT_MS);
- if (DBG) {
- Slog.d(WWS_TAG, "Ran a single DNS ping. Response time: " + responseTime);
- }
- if (responseTime < 0) {
- return false;
- }
- return true;
-
- }
-
- /**
- * @return Delay in MS before next single DNS check can proceed.
- */
- private long timeToNextScheduledDNSCheck() {
- if (mStatus.signal > LOW_SIGNAL_CUTOFF) {
- return waitTime(MIN_SINGLE_DNS_CHECK_INTERVAL, mStatus.lastSingleCheckTime);
- } else {
- return waitTime(MIN_LOW_SIGNAL_CHECK_INTERVAL, mStatus.lastSingleCheckTime);
- }
- }
-
- /**
- * Helper to return wait time left given a min interval and last run
- *
- * @param interval minimum wait interval
- * @param lastTime last time action was performed in
- * SystemClock.elapsedRealtime()
- * @return non negative time to wait
- */
- private static long waitTime(long interval, long lastTime) {
- long wait = interval + lastTime - SystemClock.elapsedRealtime();
- return wait > 0 ? wait : 0;
- }
-
- private void popUpBrowser() {
- Uri uri = Uri.parse("http://www.google.com");
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
- Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- }
-
- private void disableAP(WifiInfo info) {
- // TODO : Unban networks if they had low signal ?
- Slog.i(WWS_TAG, String.format("Disabling current SSID, %s [bssid %s]. " +
- "numChecks %d, numAPs %d", mStatus.ssid, mStatus.bssid,
- mStatus.numFullDNSchecks, mStatus.allBssids.size()));
- mWifiManager.disableNetwork(info.getNetworkId());
- mStatus.state = WatchdogState.INACTIVE;
- }
-
- private void blacklistAP() {
- Slog.i(WWS_TAG, String.format("Blacklisting current BSSID %s [ssid %s]. " +
- "numChecks %d, numAPs %d", mStatus.bssid, mStatus.ssid,
- mStatus.numFullDNSchecks, mStatus.allBssids.size()));
-
- mWifiManager.addToBlacklist(mStatus.bssid);
- mWifiManager.reassociate();
- mStatus.state = WatchdogState.BLACKLISTED_AP;
- }
-
- /**
- * Checks the scan for new BBIDs using current mSsid
- */
- private void updateBssids() {
- String curSsid = mStatus.ssid;
- HashSet<String> bssids = mStatus.allBssids;
- List<ScanResult> results = mWifiManager.getScanResults();
- int oldNumBssids = bssids.size();
-
- if (results == null) {
- if (VDBG) {
- Slog.v(WWS_TAG, "updateBssids: Got null scan results!");
- }
- return;
- }
-
- for (ScanResult result : results) {
- if (result != null && curSsid.equals(result.SSID))
- bssids.add(result.BSSID);
- }
-
- // if (VDBG && bssids.size() - oldNumBssids > 0) {
- // Slog.v(WWS_TAG,
- // String.format("updateBssids:: Found %d new APs (total %d) on SSID %s",
- // bssids.size() - oldNumBssids, bssids.size(), curSsid));
- // }
- }
-
- enum DnsCheckStatus {
- SUCCESS,
- FAILURE,
- INCOMPLETE
- }
-
- /**
- * Computes the current results of the dns check, ends early if outcome is
- * assured.
- */
- private DnsCheckStatus currentDnsCheckStatus() {
- /**
- * After a full ping count, if we have more responses than this cutoff,
- * the outcome is success; else it is 'failure'.
- */
- double pingResponseCutoff = MIN_RESPONSE_RATE * NUM_DNS_PINGS;
- int remainingChecks = NUM_DNS_PINGS - mStatus.dnsCheckTries;
-
- /**
- * Our final success count will be at least this big, so we're
- * guaranteed to succeed.
- */
- if (mStatus.dnsCheckSuccesses >= pingResponseCutoff) {
- return DnsCheckStatus.SUCCESS;
- }
-
- /**
- * Our final count will be at most the current count plus the remaining
- * pings - we're guaranteed to fail.
- */
- if (remainingChecks + mStatus.dnsCheckSuccesses < pingResponseCutoff) {
- return DnsCheckStatus.FAILURE;
- }
-
- return DnsCheckStatus.INCOMPLETE;
- }
-
- private void initDnsFullCheck() {
- if (DBG) {
- Slog.d(WWS_TAG, "Starting DNS pings at " + SystemClock.elapsedRealtime());
- }
- mStatus.numFullDNSchecks++;
- mStatus.dnsCheckSuccesses = 0;
- mStatus.dnsCheckTries = 0;
- mStatus.state = WatchdogState.DNS_FULL_CHECK;
-
- if (DBG) {
- mDNSCheckLogStr = String.format("Dns Check %d. Pinging %s on ssid [%s]: ",
- mStatus.numFullDNSchecks, mDnsPinger.getDns(),
- mStatus.ssid);
- }
- }
-
- /**
- * DNS based detection techniques do not work at all hotspots. The one sure
- * way to check a walled garden is to see if a URL fetch on a known address
- * fetches the data we expect
- */
- private boolean isWalledGardenConnection() {
- InputStream in = null;
- HttpURLConnection urlConnection = null;
- try {
- URL url = new URL(getWalledGardenUrl());
- urlConnection = (HttpURLConnection) url.openConnection();
- in = new BufferedInputStream(urlConnection.getInputStream());
- Scanner scanner = new Scanner(in);
- if (scanner.findInLine(getWalledGardenPattern()) != null) {
- return false;
- } else {
- return true;
- }
- } catch (IOException e) {
- return false;
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- }
- }
- if (urlConnection != null)
- urlConnection.disconnect();
- }
- }
-
- /**
- * There is little logic inside this class, instead methods of the form
- * "handle___" are called in the main {@link WifiWatchdogService}.
- */
- private class WifiWatchdogHandler extends Handler {
- /**
- * Major network event, object is NetworkInfo
- */
- static final int MESSAGE_NETWORK_EVENT = 1;
- /**
- * Change in settings, no object
- */
- static final int MESSAGE_CONTEXT_EVENT = 2;
-
- /**
- * Change in signal strength
- */
- static final int RSSI_CHANGE_EVENT = 3;
- static final int SCAN_RESULTS_AVAILABLE = 4;
-
- static final int WIFI_STATE_CHANGE = 5;
-
- /**
- * Single step of state machine. One DNS check, or one WalledGarden
- * check, or one external action. We separate out external actions to
- * increase chance of detecting that a check failure is caused by change
- * in network status. Messages should have an arg1 which to sync status
- * messages.
- */
- static final int CHECK_SEQUENCE_STEP = 10;
- static final int SINGLE_DNS_CHECK = 11;
-
- /**
- * @param looper
- */
- public WifiWatchdogHandler(Looper looper) {
- super(looper);
- }
-
- boolean singleCheckQueued = false;
- long queuedSingleDnsCheckArrival;
-
- /**
- * Sends a singleDnsCheck message with shortest time - guards against
- * multiple.
- */
- private boolean queueSingleDnsCheck() {
- long delay = timeToNextScheduledDNSCheck();
- long newArrival = delay + SystemClock.elapsedRealtime();
- if (singleCheckQueued && queuedSingleDnsCheckArrival <= newArrival)
- return true;
- queuedSingleDnsCheckArrival = newArrival;
- singleCheckQueued = true;
- removeMessages(SINGLE_DNS_CHECK);
- return sendMessageDelayed(obtainMessage(SINGLE_DNS_CHECK), delay);
- }
-
- boolean checkSequenceQueued = false;
- long queuedCheckSequenceArrival;
-
- /**
- * Sends a state_machine_step message if the delay requested is lower
- * than the current delay.
- */
- private boolean sendCheckSequenceStep(long delay) {
- long newArrival = delay + SystemClock.elapsedRealtime();
- if (checkSequenceQueued && queuedCheckSequenceArrival <= newArrival)
- return true;
- queuedCheckSequenceArrival = newArrival;
- checkSequenceQueued = true;
- removeMessages(CHECK_SEQUENCE_STEP);
- return sendMessageDelayed(obtainMessage(CHECK_SEQUENCE_STEP), delay);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case CHECK_SEQUENCE_STEP:
- checkSequenceQueued = false;
- handleStateStep();
- if (mStatus.state == WatchdogState.CHECKS_COMPLETE) {
- queueSingleDnsCheck();
- } else if (mStatus.state == WatchdogState.DNS_FULL_CHECK) {
- sendCheckSequenceStep(DNS_PING_INTERVAL);
- } else if (mStatus.state == WatchdogState.BLACKLISTED_AP) {
- sendCheckSequenceStep(BLACKLIST_FOLLOWUP_INTERVAL);
- } else if (mStatus.state != WatchdogState.INACTIVE) {
- sendCheckSequenceStep(0);
- }
- return;
- case MESSAGE_NETWORK_EVENT:
- if (!mBroadcastsEnabled) {
- Slog.e(WWS_TAG,
- "MessageNetworkEvent - WatchdogService not enabled... returning");
- return;
- }
- NetworkInfo info = (NetworkInfo) msg.obj;
- switch (info.getState()) {
- case DISCONNECTED:
- mStatus.state = WatchdogState.INACTIVE;
- return;
- case CONNECTED:
- handleNewConnection();
- sendCheckSequenceStep(0);
- }
- return;
- case SINGLE_DNS_CHECK:
- singleCheckQueued = false;
- if (mStatus.state != WatchdogState.CHECKS_COMPLETE) {
- Slog.d(WWS_TAG, "Single check returning, curState: " + mStatus.state);
- break;
- }
-
- if (!handleSingleDnsCheck()) {
- initDnsFullCheck();
- sendCheckSequenceStep(0);
- } else {
- queueSingleDnsCheck();
- }
-
- break;
- case RSSI_CHANGE_EVENT:
- updateRssi();
- if (mStatus.state == WatchdogState.CHECKS_COMPLETE)
- queueSingleDnsCheck();
- break;
- case SCAN_RESULTS_AVAILABLE:
- updateBssids();
- break;
- case WIFI_STATE_CHANGE:
- if ((Integer) msg.obj == WifiManager.WIFI_STATE_DISABLING) {
- Slog.i(WWS_TAG, "WifiStateDisabling -- Resetting WatchdogState");
- mStatus = new Status();
- }
- break;
- case MESSAGE_CONTEXT_EVENT:
- if (isWatchdogEnabled() && !mBroadcastsEnabled) {
- mContext.registerReceiver(mBroadcastReceiver, mIntentFilter);
- mBroadcastsEnabled = true;
- Slog.i(WWS_TAG, "WifiWatchdogService enabled");
- } else if (!isWatchdogEnabled() && mBroadcastsEnabled) {
- mContext.unregisterReceiver(mBroadcastReceiver);
- removeMessages(SINGLE_DNS_CHECK);
- removeMessages(CHECK_SEQUENCE_STEP);
- mBroadcastsEnabled = false;
- Slog.i(WWS_TAG, "WifiWatchdogService disabled");
- }
- break;
- }
- }
- }
-
- public void dump(PrintWriter pw) {
- pw.print("WatchdogStatus: ");
- pw.print("State " + mStatus.state);
- pw.println(", network [" + mStatus.ssid + ", " + mStatus.bssid + "]");
- pw.print("checkCount " + mStatus.numFullDNSchecks);
- pw.println(", bssids: " + mStatus.allBssids);
- pw.print(", hasCheckMessages? " +
- mHandler.hasMessages(WifiWatchdogHandler.CHECK_SEQUENCE_STEP));
- pw.println(" hasSingleCheckMessages? " +
- mHandler.hasMessages(WifiWatchdogHandler.SINGLE_DNS_CHECK));
- pw.println("DNS check log str: " + mDNSCheckLogStr);
- pw.println("lastSingleCheck: " + mStatus.lastSingleCheckTime);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED
- */
- private Boolean isWalledGardenTestEnabled() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, 1) == 1;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_URL
- */
- private String getWalledGardenUrl() {
- String url = Settings.Secure.getString(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL);
- if (TextUtils.isEmpty(url))
- return "http://www.google.com/";
- return url;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_PATTERN
- */
- private String getWalledGardenPattern() {
- String pattern = Settings.Secure.getString(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_PATTERN);
- if (TextUtils.isEmpty(pattern))
- return "<title>.*Google.*</title>";
- return pattern;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ON
- */
- private boolean isWatchdogEnabled() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_ON, 1) == 1;
- }
-}
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
new file mode 100644
index 0000000..0eb73b7
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.ConnectivityManager;
+import android.net.DnsPinger;
+import android.net.NetworkInfo;
+import android.net.Uri;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * {@link WifiWatchdogStateMachine} monitors the initial connection to a Wi-Fi
+ * network with multiple access points. After the framework successfully
+ * connects to an access point, the watchdog verifies connectivity by 'pinging'
+ * the configured DNS server using {@link DnsPinger}.
+ * <p>
+ * On DNS check failure, the BSSID is blacklisted if it is reasonably likely
+ * that another AP might have internet access; otherwise the SSID is disabled.
+ * <p>
+ * On DNS success, the WatchdogService initiates a walled garden check via an
+ * http get. A browser window is activated if a walled garden is detected.
+ *
+ * @hide
+ */
+public class WifiWatchdogStateMachine extends StateMachine {
+
+ private static final boolean VDBG = false;
+ private static final boolean DBG = true;
+ private static final String WWSM_TAG = "WifiWatchdogStateMachine";
+
+ private static final int WIFI_SIGNAL_LEVELS = 4;
+ /**
+ * Low signal is defined as less than or equal to cut off
+ */
+ private static final int LOW_SIGNAL_CUTOFF = 1;
+
+ private static final long MIN_LOW_SIGNAL_CHECK_INTERVAL_MS = 2 * 60 * 1000;
+ private static final long MIN_SINGLE_DNS_CHECK_INTERVAL_MS = 10 * 60 * 1000;
+ private static final long MIN_WALLED_GARDEN_INTERVAL_MS = 30 * 60 * 1000;
+
+ private static final int MAX_CHECKS_PER_SSID = 7;
+ private static final int NUM_DNS_PINGS = 5;
+ private static final double MIN_DNS_RESPONSE_RATE = 0.50;
+
+ private static final int DNS_PING_TIMEOUT_MS = 800;
+ private static final long DNS_PING_INTERVAL_MS = 100;
+
+ private static final long BLACKLIST_FOLLOWUP_INTERVAL_MS = 15 * 1000;
+
+ private static final int BASE = Protocol.BASE_WIFI_WATCHDOG;
+
+ /**
+ * Indicates the enable setting of WWS may have changed
+ */
+ private static final int EVENT_WATCHDOG_TOGGLED = BASE + 1;
+
+ /**
+ * Indicates the wifi network state has changed. Passed w/ original intent
+ * which has a non-null networkInfo object
+ */
+ private static final int EVENT_NETWORK_STATE_CHANGE = BASE + 2;
+ /**
+ * Indicates the signal has changed. Passed with arg1
+ * {@link #mNetEventCounter} and arg2 [raw signal strength]
+ */
+ private static final int EVENT_RSSI_CHANGE = BASE + 3;
+ private static final int EVENT_SCAN_RESULTS_AVAILABLE = BASE + 4;
+ private static final int EVENT_WIFI_RADIO_STATE_CHANGE = BASE + 5;
+
+ private static final int MESSAGE_CHECK_STEP = BASE + 100;
+ private static final int MESSAGE_HANDLE_WALLED_GARDEN = BASE + 101;
+ private static final int MESSAGE_HANDLE_BAD_AP = BASE + 102;
+ /**
+ * arg1 == mOnlineWatchState.checkCount
+ */
+ private static final int MESSAGE_SINGLE_DNS_CHECK = BASE + 103;
+ private static final int MESSAGE_NETWORK_FOLLOWUP = BASE + 104;
+
+ private Context mContext;
+ private ContentResolver mContentResolver;
+ private WifiManager mWifiManager;
+ private DnsPinger mDnsPinger;
+ private IntentFilter mIntentFilter;
+ private BroadcastReceiver mBroadcastReceiver;
+
+ private DefaultState mDefaultState = new DefaultState();
+ private WatchdogDisabledState mWatchdogDisabledState = new WatchdogDisabledState();
+ private WatchdogEnabledState mWatchdogEnabledState = new WatchdogEnabledState();
+ private NotConnectedState mNotConnectedState = new NotConnectedState();
+ private ConnectedState mConnectedState = new ConnectedState();
+ private DnsCheckingState mDnsCheckingState = new DnsCheckingState();
+ private OnlineWatchState mOnlineWatchState = new OnlineWatchState();
+ private DnsCheckFailureState mDnsCheckFailureState = new DnsCheckFailureState();
+ private WalledGardenState mWalledGardenState = new WalledGardenState();
+ private BlacklistedApState mBlacklistedApState = new BlacklistedApState();
+
+ /**
+ * The {@link WifiInfo} object passed to WWSM on network broadcasts
+ */
+ private WifiInfo mInitialConnInfo;
+ private int mNetEventCounter = 0;
+
+ /**
+ * Currently maintained but not used, TODO
+ */
+ private HashSet<String> mBssids = new HashSet<String>();
+ private int mNumFullDNSchecks = 0;
+
+ private Long mLastWalledGardenCheckTime = null;
+
+ /**
+ * This is set by the blacklisted state and reset when connected to a new AP.
+ * It triggers a disableNetwork call if a DNS check fails.
+ */
+ public boolean mDisableAPNextFailure = false;
+
+ /**
+ * STATE MAP
+ * Default
+ * / \
+ * Disabled Enabled
+ * / \
+ * Disconnected Connected
+ * /---------\
+ * (all other states)
+ */
+ private WifiWatchdogStateMachine(Context context) {
+ super(WWSM_TAG);
+ mContext = context;
+ mContentResolver = context.getContentResolver();
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ mDnsPinger = new DnsPinger("WifiWatchdogServer.DnsPinger", context,
+ ConnectivityManager.TYPE_WIFI);
+
+ setupNetworkReceiver();
+
+ // The content observer to listen needs a handler
+ registerForSettingsChanges();
+ addState(mDefaultState);
+ addState(mWatchdogDisabledState, mDefaultState);
+ addState(mWatchdogEnabledState, mDefaultState);
+ addState(mNotConnectedState, mWatchdogEnabledState);
+ addState(mConnectedState, mWatchdogEnabledState);
+ addState(mDnsCheckingState, mConnectedState);
+ addState(mDnsCheckFailureState, mConnectedState);
+ addState(mWalledGardenState, mConnectedState);
+ addState(mBlacklistedApState, mConnectedState);
+ addState(mOnlineWatchState, mConnectedState);
+
+ setInitialState(mWatchdogDisabledState);
+ }
+
+ public static WifiWatchdogStateMachine makeWifiWatchdogStateMachine(Context context) {
+ WifiWatchdogStateMachine wwsm = new WifiWatchdogStateMachine(context);
+ wwsm.start();
+ wwsm.sendMessage(EVENT_WATCHDOG_TOGGLED);
+ return wwsm;
+ }
+
+ /**
+ *
+ */
+ private void setupNetworkReceiver() {
+ mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+ sendMessage(EVENT_NETWORK_STATE_CHANGE, intent);
+ } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
+ obtainMessage(EVENT_RSSI_CHANGE, mNetEventCounter,
+ intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)).sendToTarget();
+ } else if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ sendMessage(EVENT_SCAN_RESULTS_AVAILABLE);
+ } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ sendMessage(EVENT_WIFI_RADIO_STATE_CHANGE,
+ intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN));
+ }
+ }
+ };
+
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ }
+
+ /**
+ * Observes the watchdog on/off setting, and takes action when changed.
+ */
+ private void registerForSettingsChanges() {
+ ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ sendMessage(EVENT_WATCHDOG_TOGGLED);
+ }
+ };
+
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON),
+ false, contentObserver);
+ }
+
+ /**
+ * DNS based detection techniques do not work at all hotspots. The one sure
+ * way to check a walled garden is to see if a URL fetch on a known address
+ * fetches the data we expect
+ */
+ private boolean isWalledGardenConnection() {
+ InputStream in = null;
+ HttpURLConnection urlConnection = null;
+ try {
+ URL url = new URL(getWalledGardenUrl());
+ urlConnection = (HttpURLConnection) url.openConnection();
+ in = new BufferedInputStream(urlConnection.getInputStream());
+ Scanner scanner = new Scanner(in);
+ if (scanner.findInLine(getWalledGardenPattern()) != null) {
+ return false;
+ } else {
+ return true;
+ }
+ } catch (IOException e) {
+ return false;
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ if (urlConnection != null)
+ urlConnection.disconnect();
+ }
+ }
+
+ private boolean rssiStrengthAboveCutoff(int rssi) {
+ return WifiManager.calculateSignalLevel(rssi, WIFI_SIGNAL_LEVELS) > LOW_SIGNAL_CUTOFF;
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.print("WatchdogStatus: ");
+ pw.print("State " + getCurrentState());
+ pw.println(", network [" + mInitialConnInfo + "]");
+ pw.print("checkCount " + mNumFullDNSchecks);
+ pw.println(", bssids: " + mBssids);
+ pw.println("lastSingleCheck: " + mOnlineWatchState.lastCheckTime);
+ }
+
+ /**
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED
+ */
+ private Boolean isWalledGardenTestEnabled() {
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, 1) == 1;
+ }
+
+ /**
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_URL
+ */
+ private String getWalledGardenUrl() {
+ String url = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL);
+ if (TextUtils.isEmpty(url))
+ return "http://www.google.com/";
+ return url;
+ }
+
+ /**
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_PATTERN
+ */
+ private String getWalledGardenPattern() {
+ String pattern = Settings.Secure.getString(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_PATTERN);
+ if (TextUtils.isEmpty(pattern))
+ return "<title>.*Google.*</title>";
+ return pattern;
+ }
+
+ /**
+ * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ON
+ */
+ private boolean isWatchdogEnabled() {
+ return Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.WIFI_WATCHDOG_ON, 1) == 1;
+ }
+
+
+ /**
+ * Helper to return wait time left given a min interval and last run
+ *
+ * @param interval minimum wait interval
+ * @param lastTime last time action was performed in
+ * SystemClock.elapsedRealtime(). Null if never.
+ * @return non negative time to wait
+ */
+ private static long waitTime(long interval, Long lastTime) {
+ if (lastTime == null)
+ return 0;
+ long wait = interval + lastTime - SystemClock.elapsedRealtime();
+ return wait > 0 ? wait : 0;
+ }
+
+ private static String wifiInfoToStr(WifiInfo wifiInfo) {
+ if (wifiInfo == null)
+ return "null";
+ return "(" + wifiInfo.getSSID() + ", " + wifiInfo.getBSSID() + ")";
+ }
+
+ /**
+ *
+ */
+ private void resetWatchdogState() {
+ mInitialConnInfo = null;
+ mDisableAPNextFailure = false;
+ mLastWalledGardenCheckTime = null;
+ mNumFullDNSchecks = 0;
+ mBssids.clear();
+ }
+
+ private void popUpBrowser() {
+ Uri uri = Uri.parse("http://www.google.com");
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
+ Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+
+ private void sendCheckStepMessage(long delay) {
+ sendMessageDelayed(obtainMessage(MESSAGE_CHECK_STEP, mNetEventCounter, 0), delay);
+ }
+
+ class DefaultState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Caught message " + msg.what + " in state " +
+ getCurrentState().getName());
+ }
+ return HANDLED;
+ }
+ }
+
+ class WatchdogDisabledState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_WATCHDOG_TOGGLED:
+ if (isWatchdogEnabled())
+ transitionTo(mNotConnectedState);
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+ }
+
+ class WatchdogEnabledState extends State {
+ @Override
+ public void enter() {
+ resetWatchdogState();
+ mContext.registerReceiver(mBroadcastReceiver, mIntentFilter);
+ Slog.i(WWSM_TAG, "WifiWatchdogService enabled");
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_WATCHDOG_TOGGLED:
+ if (!isWatchdogEnabled())
+ transitionTo(mWatchdogDisabledState);
+ return HANDLED;
+ case EVENT_NETWORK_STATE_CHANGE:
+ Intent stateChangeIntent = (Intent) msg.obj;
+ NetworkInfo networkInfo = (NetworkInfo)
+ stateChangeIntent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+
+ switch (networkInfo.getState()) {
+ case CONNECTED:
+ // WifiInfo wifiInfo = (WifiInfo)
+ // stateChangeIntent
+ // .getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
+ // TODO : Replace with above code when API is changed
+ WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+ if (wifiInfo == null) {
+ Slog.e(WWSM_TAG, "Connected --> WifiInfo object null!");
+ return HANDLED;
+ }
+
+ if (wifiInfo.getSSID() == null || wifiInfo.getBSSID() == null) {
+ Slog.e(WWSM_TAG, "Received wifiInfo object with null elts: "
+ + wifiInfoToStr(wifiInfo));
+ return HANDLED;
+ }
+
+ initConnection(wifiInfo);
+ transitionTo(mDnsCheckingState);
+ mNetEventCounter++;
+ return HANDLED;
+ case DISCONNECTED:
+ case DISCONNECTING:
+ mNetEventCounter++;
+ transitionTo(mNotConnectedState);
+ return HANDLED;
+ }
+ return HANDLED;
+ case EVENT_WIFI_RADIO_STATE_CHANGE:
+ if ((Integer) msg.obj == WifiManager.WIFI_STATE_DISABLING) {
+ Slog.i(WWSM_TAG, "WifiStateDisabling -- Resetting WatchdogState");
+ resetWatchdogState();
+ mNetEventCounter++;
+ transitionTo(mNotConnectedState);
+ }
+ return HANDLED;
+ }
+
+ return NOT_HANDLED;
+ }
+
+ /**
+ * @param wifiInfo Info object with non-null ssid and bssid
+ */
+ private void initConnection(WifiInfo wifiInfo) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Connected:: old " + wifiInfoToStr(mInitialConnInfo) +
+ " ==> new " + wifiInfoToStr(wifiInfo));
+ }
+
+ if (mInitialConnInfo == null || !wifiInfo.getSSID().equals(mInitialConnInfo.getSSID())) {
+ resetWatchdogState();
+ } else if (!wifiInfo.getBSSID().equals(mInitialConnInfo.getBSSID())) {
+ mDisableAPNextFailure = false;
+ }
+ mInitialConnInfo = wifiInfo;
+ }
+
+ @Override
+ public void exit() {
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ Slog.i(WWSM_TAG, "WifiWatchdogService disabled");
+ }
+ }
+
+ class NotConnectedState extends State {
+ }
+
+ class ConnectedState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_SCAN_RESULTS_AVAILABLE:
+ String curSsid = mInitialConnInfo.getSSID();
+ List<ScanResult> results = mWifiManager.getScanResults();
+ int oldNumBssids = mBssids.size();
+
+ if (results == null) {
+ if (DBG) {
+ Slog.d(WWSM_TAG, "updateBssids: Got null scan results!");
+ }
+ return HANDLED;
+ }
+
+ for (ScanResult result : results) {
+ if (result == null || result.SSID == null) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Received invalid scan result: " + result);
+ }
+ continue;
+ }
+ if (curSsid.equals(result.SSID))
+ mBssids.add(result.BSSID);
+ }
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+
+ }
+
+ class DnsCheckingState extends State {
+ int dnsCheckTries = 0;
+ int dnsCheckSuccesses = 0;
+ String dnsCheckLogStr = "";
+
+ @Override
+ public void enter() {
+ mNumFullDNSchecks++;
+ dnsCheckSuccesses = 0;
+ dnsCheckTries = 0;
+ if (DBG) {
+ Slog.d(WWSM_TAG, "Starting DNS pings at " + SystemClock.elapsedRealtime());
+ dnsCheckLogStr = String.format("Dns Check %d. Pinging %s on ssid [%s]: ",
+ mNumFullDNSchecks, mDnsPinger.getDns(), mInitialConnInfo.getSSID());
+ }
+
+ sendCheckStepMessage(0);
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ if (msg.what != MESSAGE_CHECK_STEP) {
+ return NOT_HANDLED;
+ }
+ if (msg.arg1 != mNetEventCounter) {
+ Slog.d(WWSM_TAG, "Check step out of sync, ignoring...");
+ return HANDLED;
+ }
+
+ long pingResponseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
+ DNS_PING_TIMEOUT_MS);
+
+ dnsCheckTries++;
+ if (pingResponseTime >= 0)
+ dnsCheckSuccesses++;
+
+ if (DBG) {
+ if (pingResponseTime >= 0) {
+ dnsCheckLogStr += "|" + pingResponseTime;
+ } else {
+ dnsCheckLogStr += "|x";
+ }
+ }
+
+ if (VDBG) {
+ Slog.v(WWSM_TAG, dnsCheckLogStr);
+ }
+
+ /**
+ * After a full ping count, if we have more responses than this
+ * cutoff, the outcome is success; else it is 'failure'.
+ */
+ double pingResponseCutoff = MIN_DNS_RESPONSE_RATE * NUM_DNS_PINGS;
+ int remainingChecks = NUM_DNS_PINGS - dnsCheckTries;
+
+ /**
+ * Our final success count will be at least this big, so we're
+ * guaranteed to succeed.
+ */
+ if (dnsCheckSuccesses >= pingResponseCutoff) {
+ // DNS CHECKS OK, NOW WALLED GARDEN
+ if (DBG) {
+ Slog.d(WWSM_TAG, dnsCheckLogStr + "| SUCCESS");
+ }
+
+ if (!shouldCheckWalledGarden()) {
+ transitionTo(mOnlineWatchState);
+ return HANDLED;
+ }
+
+ mLastWalledGardenCheckTime = SystemClock.elapsedRealtime();
+ if (isWalledGardenConnection()) {
+ if (DBG)
+ Slog.d(WWSM_TAG,
+ "Walled garden test complete - walled garden detected");
+ transitionTo(mWalledGardenState);
+ } else {
+ if (DBG)
+ Slog.d(WWSM_TAG, "Walled garden test complete - online");
+ transitionTo(mOnlineWatchState);
+ }
+ return HANDLED;
+ }
+
+ /**
+ * Our final count will be at most the current count plus the
+ * remaining pings - we're guaranteed to fail.
+ */
+ if (remainingChecks + dnsCheckSuccesses < pingResponseCutoff) {
+ if (DBG) {
+ Slog.d(WWSM_TAG, dnsCheckLogStr + "| FAILURE");
+ }
+ transitionTo(mDnsCheckFailureState);
+ return HANDLED;
+ }
+
+ // Still in dns check step
+ sendCheckStepMessage(DNS_PING_INTERVAL_MS);
+ return HANDLED;
+ }
+
+ private boolean shouldCheckWalledGarden() {
+ if (!isWalledGardenTestEnabled()) {
+ if (VDBG)
+ Slog.v(WWSM_TAG, "Skipping walled garden check - disabled");
+ return false;
+ }
+ long waitTime = waitTime(MIN_WALLED_GARDEN_INTERVAL_MS,
+ mLastWalledGardenCheckTime);
+ if (waitTime > 0) {
+ if (DBG) {
+ Slog.d(WWSM_TAG, "Skipping walled garden check - wait " +
+ waitTime + " ms.");
+ }
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ class OnlineWatchState extends State {
+ /**
+ * Signals a short-wait message is enqueued for the current 'guard' counter
+ */
+ boolean unstableSignalChecks = false;
+
+ /**
+ * The signal is unstable. We should enqueue a short-wait check, if one is enqueued
+ * already
+ */
+ boolean signalUnstable = false;
+
+ /**
+ * A monotonic counter to ensure that at most one check message will be processed from any
+ * set of check messages currently enqueued. Avoids duplicate checks when a low-signal
+ * event is observed.
+ */
+ int checkGuard = 0;
+ Long lastCheckTime = null;
+
+ @Override
+ public void enter() {
+ lastCheckTime = SystemClock.elapsedRealtime();
+ signalUnstable = false;
+ checkGuard++;
+ unstableSignalChecks = false;
+ triggerSingleDnsCheck();
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_RSSI_CHANGE:
+ if (msg.arg1 != mNetEventCounter) {
+ if (DBG) {
+ Slog.d(WWSM_TAG, "Rssi change message out of sync, ignoring");
+ }
+ return HANDLED;
+ }
+ int newRssi = msg.arg2;
+ signalUnstable = !rssiStrengthAboveCutoff(newRssi);
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "OnlineWatchState:: new rssi " + newRssi + " --> level " +
+ WifiManager.calculateSignalLevel(newRssi, WIFI_SIGNAL_LEVELS));
+ }
+
+ if (signalUnstable && !unstableSignalChecks) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Sending triggered check msg");
+ }
+ triggerSingleDnsCheck();
+ }
+ return HANDLED;
+ case MESSAGE_SINGLE_DNS_CHECK:
+ if (msg.arg1 != checkGuard) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Single check msg out of sync, ignoring.");
+ }
+ return HANDLED;
+ }
+ lastCheckTime = SystemClock.elapsedRealtime();
+ long responseTime = mDnsPinger.pingDns(mDnsPinger.getDns(),
+ DNS_PING_TIMEOUT_MS);
+ if (responseTime >= 0) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Ran a single DNS ping. Response time: "
+ + responseTime);
+ }
+
+ checkGuard++;
+ unstableSignalChecks = false;
+ triggerSingleDnsCheck();
+ } else {
+ if (DBG) {
+ Slog.d(WWSM_TAG, "Single dns ping failure. Starting full checks.");
+ }
+ transitionTo(mDnsCheckingState);
+ }
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+
+ /**
+ * Times a dns check with an interval based on {@link #curSignalStable}
+ */
+ private void triggerSingleDnsCheck() {
+ long waitInterval;
+ if (signalUnstable) {
+ waitInterval = MIN_LOW_SIGNAL_CHECK_INTERVAL_MS;
+ unstableSignalChecks = true;
+ } else {
+ waitInterval = MIN_SINGLE_DNS_CHECK_INTERVAL_MS;
+ }
+ sendMessageDelayed(obtainMessage(MESSAGE_SINGLE_DNS_CHECK, checkGuard, 0),
+ waitTime(waitInterval, lastCheckTime));
+ }
+ }
+
+ class DnsCheckFailureState extends State {
+ @Override
+ public void enter() {
+ obtainMessage(MESSAGE_HANDLE_BAD_AP, mNetEventCounter, 0).sendToTarget();
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ if (msg.what != MESSAGE_HANDLE_BAD_AP) {
+ return NOT_HANDLED;
+ }
+
+ if (msg.arg1 != mNetEventCounter) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "Msg out of sync, ignoring...");
+ }
+ return HANDLED;
+ }
+
+ if (mDisableAPNextFailure || mNumFullDNSchecks >= MAX_CHECKS_PER_SSID) {
+ // TODO : Unban networks if they had low signal ?
+ Slog.i(WWSM_TAG, "Disabling current SSID " + wifiInfoToStr(mInitialConnInfo)
+ + ". " +
+ "numChecks " + mNumFullDNSchecks + ", numAPs " + mBssids.size());
+ mWifiManager.disableNetwork(mInitialConnInfo.getNetworkId());
+ transitionTo(mNotConnectedState);
+ } else {
+ Slog.i(WWSM_TAG, "Blacklisting current BSSID. " + wifiInfoToStr(mInitialConnInfo) +
+ "numChecks " + mNumFullDNSchecks + ", numAPs " + mBssids.size());
+
+ mWifiManager.addToBlacklist(mInitialConnInfo.getBSSID());
+ mWifiManager.reassociate();
+ transitionTo(mBlacklistedApState);
+ }
+ return HANDLED;
+ }
+ }
+
+ class WalledGardenState extends State {
+ @Override
+ public void enter() {
+ obtainMessage(MESSAGE_HANDLE_WALLED_GARDEN, mNetEventCounter, 0).sendToTarget();
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ if (msg.what != MESSAGE_HANDLE_WALLED_GARDEN) {
+ return NOT_HANDLED;
+ }
+
+ if (msg.arg1 != mNetEventCounter) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "WalledGardenState::Msg out of sync, ignoring...");
+ }
+ return HANDLED;
+ }
+ popUpBrowser();
+ transitionTo(mOnlineWatchState);
+ return HANDLED;
+ }
+ }
+
+ class BlacklistedApState extends State {
+ @Override
+ public void enter() {
+ mDisableAPNextFailure = true;
+ sendMessageDelayed(obtainMessage(MESSAGE_NETWORK_FOLLOWUP, mNetEventCounter, 0),
+ BLACKLIST_FOLLOWUP_INTERVAL_MS);
+ }
+
+ @Override
+ public boolean processMessage(Message msg) {
+ if (msg.what != MESSAGE_NETWORK_FOLLOWUP) {
+ return NOT_HANDLED;
+ }
+
+ if (msg.arg1 != mNetEventCounter) {
+ if (VDBG) {
+ Slog.v(WWSM_TAG, "BlacklistedApState::Msg out of sync, ignoring...");
+ }
+ return HANDLED;
+ }
+
+ transitionTo(mDnsCheckingState);
+ return HANDLED;
+ }
+ }
+}