summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/Activity.java231
-rw-r--r--core/java/android/app/ActivityManager.java1
-rw-r--r--core/java/android/app/ActivityManagerNative.java94
-rw-r--r--core/java/android/app/ContextImpl.java17
-rw-r--r--core/java/android/app/DownloadManager.java12
-rw-r--r--core/java/android/app/IActivityManager.java10
-rw-r--r--core/java/android/app/Instrumentation.java43
-rw-r--r--core/java/android/app/Notification.java26
-rw-r--r--core/java/android/app/TaskStackBuilder.java220
-rw-r--r--core/java/android/content/Context.java21
-rw-r--r--core/java/android/content/Intent.java40
-rw-r--r--core/java/android/content/pm/ActivityInfo.java8
-rw-r--r--core/java/android/content/pm/PackageParser.java46
-rw-r--r--core/java/android/hardware/input/IInputManager.aidl37
-rwxr-xr-xcore/java/android/hardware/input/InputManager.java651
-rw-r--r--core/java/android/hardware/usb/UsbManager.java10
-rw-r--r--core/java/android/net/ConnectivityManager.java6
-rw-r--r--core/java/android/net/INetworkStatsService.aidl13
-rw-r--r--core/java/android/net/INetworkStatsSession.aidl38
-rw-r--r--core/java/android/net/NetworkIdentity.java74
-rw-r--r--core/java/android/net/NetworkPolicy.java23
-rw-r--r--core/java/android/net/NetworkPolicyManager.java58
-rw-r--r--core/java/android/net/NetworkQuotaInfo.java6
-rw-r--r--core/java/android/net/NetworkState.java6
-rw-r--r--core/java/android/net/NetworkStats.java9
-rw-r--r--core/java/android/net/NetworkStatsHistory.java6
-rw-r--r--core/java/android/net/NetworkTemplate.java95
-rw-r--r--core/java/android/net/TrafficStats.java13
-rw-r--r--core/java/android/net/nsd/DnsSdServiceInfo.java136
-rw-r--r--core/java/android/net/nsd/DnsSdTxtRecord.java305
-rw-r--r--core/java/android/net/nsd/INsdManager.aidl29
-rw-r--r--core/java/android/net/nsd/NetworkServiceInfo.java32
-rw-r--r--core/java/android/net/nsd/NsdManager.java394
-rw-r--r--core/java/android/nfc/INdefPushCallback.aidl3
-rw-r--r--core/java/android/nfc/INfcTag.aidl1
-rw-r--r--core/java/android/nfc/NfcActivityManager.java44
-rw-r--r--core/java/android/nfc/NfcAdapter.java39
-rw-r--r--core/java/android/nfc/tech/IsoDep.java23
-rw-r--r--core/java/android/nfc/tech/MifareClassic.java1
-rw-r--r--core/java/android/preference/Preference.java33
-rw-r--r--core/java/android/provider/ContactsContract.java8
-rw-r--r--core/java/android/provider/Settings.java53
-rw-r--r--core/java/android/text/SpannableStringBuilder.java61
-rw-r--r--core/java/android/view/GLES20TextureLayer.java14
-rw-r--r--core/java/android/view/HardwareRenderer.java51
-rw-r--r--core/java/android/view/IWindowManager.aidl44
-rwxr-xr-xcore/java/android/view/InputDevice.java70
-rw-r--r--core/java/android/view/KeyCharacterMap.java27
-rw-r--r--core/java/android/view/TextureView.java48
-rw-r--r--core/java/android/view/View.java849
-rw-r--r--core/java/android/view/ViewConfiguration.java2
-rw-r--r--core/java/android/view/ViewGroup.java21
-rw-r--r--core/java/android/view/ViewRootImpl.java308
-rw-r--r--core/java/android/view/ViewTreeObserver.java119
-rw-r--r--core/java/android/view/WindowManagerPolicy.java31
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java8
-rw-r--r--core/java/android/view/textservice/SpellCheckerInfo.java12
-rw-r--r--core/java/android/view/textservice/SpellCheckerSession.java10
-rw-r--r--core/java/android/webkit/FindActionModeCallback.java4
-rw-r--r--core/java/android/webkit/WebSettingsClassic.java2
-rw-r--r--core/java/android/webkit/WebView.java28
-rw-r--r--core/java/android/webkit/WebViewClassic.java53
-rw-r--r--core/java/android/webkit/WebViewCore.java46
-rw-r--r--core/java/android/widget/Chronometer.java1
-rw-r--r--core/java/android/widget/Editor.java1
-rw-r--r--core/java/android/widget/TextView.java57
66 files changed, 4078 insertions, 704 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index b277efb..7207e29 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -29,6 +29,8 @@ import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -65,13 +67,13 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.view.WindowManagerImpl;
import android.view.View.OnCreateContextMenuListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewManager;
import android.view.Window;
import android.view.WindowManager;
+import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView;
@@ -704,6 +706,7 @@ public class Activity extends ContextThemeWrapper
/*package*/ boolean mVisibleFromServer = false;
/*package*/ boolean mVisibleFromClient = true;
/*package*/ ActionBarImpl mActionBar = null;
+ private boolean mEnableDefaultActionBarUp;
private CharSequence mTitle;
private int mTitleColor = 0;
@@ -865,6 +868,13 @@ public class Activity extends ContextThemeWrapper
if (mLastNonConfigurationInstances != null) {
mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
}
+ if (mActivityInfo.parentActivityName != null) {
+ if (mActionBar == null) {
+ mEnableDefaultActionBarUp = true;
+ } else {
+ mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
+ }
+ }
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
@@ -1829,6 +1839,7 @@ public class Activity extends ContextThemeWrapper
}
mActionBar = new ActionBarImpl(this);
+ mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
}
/**
@@ -2511,7 +2522,19 @@ public class Activity extends ContextThemeWrapper
if (onOptionsItemSelected(item)) {
return true;
}
- return mFragments.dispatchOptionsItemSelected(item);
+ if (mFragments.dispatchOptionsItemSelected(item)) {
+ return true;
+ }
+ if (item.getItemId() == android.R.id.home && mActionBar != null &&
+ (mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+ if (mParent == null) {
+ onNavigateUp();
+ } else {
+ mParent.onNavigateUpFromChild(this);
+ }
+ return true;
+ }
+ return false;
case Window.FEATURE_CONTEXT_MENU:
EventLog.writeEvent(50000, 1, item.getTitleCondensed());
@@ -2630,7 +2653,7 @@ public class Activity extends ContextThemeWrapper
* facilities.
*
* <p>Derived classes should call through to the base class for it to
- * perform the default menu handling.
+ * perform the default menu handling.</p>
*
* @param item The menu item that was selected.
*
@@ -2647,6 +2670,92 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * This method is called whenever the user chooses to navigate Up within your application's
+ * activity hierarchy from the action bar.
+ *
+ * <p>If the attribute {@link android.R.attr#parentActivityName parentActivityName}
+ * was specified in the manifest for this activity or an activity-alias to it,
+ * default Up navigation will be handled automatically. If any activity
+ * along the parent chain requires extra Intent arguments, the Activity subclass
+ * should override the method {@link #onPrepareNavigateUpTaskStack(TaskStackBuilder)}
+ * to supply those arguments.</p>
+ *
+ * <p>See <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
+ * from the developer guide and <a href="{@docRoot}design/patterns/navigation.html">Navigation</a>
+ * from the design guide for more information about navigating within your app.</p>
+ *
+ * <p>See the {@link TaskStackBuilder} class and the Activity methods
+ * {@link #getParentActivityIntent()}, {@link #shouldUpRecreateTask(Intent)}, and
+ * {@link #navigateUpTo(Intent)} for help implementing custom Up navigation.
+ * The AppNavigation sample application in the Android SDK is also available for reference.</p>
+ *
+ * @return true if Up navigation completed successfully and this Activity was finished,
+ * false otherwise.
+ */
+ public boolean onNavigateUp() {
+ // Automatically handle hierarchical Up navigation if the proper
+ // metadata is available.
+ Intent upIntent = getParentActivityIntent();
+ if (upIntent != null) {
+ if (shouldUpRecreateTask(upIntent)) {
+ TaskStackBuilder b = TaskStackBuilder.from(this);
+ onCreateNavigateUpTaskStack(b);
+ onPrepareNavigateUpTaskStack(b);
+ b.startActivities();
+ finish();
+ } else {
+ navigateUpTo(upIntent);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This is called when a child activity of this one attempts to navigate up.
+ * The default implementation simply calls onNavigateUp() on this activity (the parent).
+ *
+ * @param child The activity making the call.
+ */
+ public boolean onNavigateUpFromChild(Activity child) {
+ return onNavigateUp();
+ }
+
+ /**
+ * Define the synthetic task stack that will be generated during Up navigation from
+ * a different task.
+ *
+ * <p>The default implementation of this method adds the parent chain of this activity
+ * as specified in the manifest to the supplied {@link TaskStackBuilder}. Applications
+ * may choose to override this method to construct the desired task stack in a different
+ * way.</p>
+ *
+ * <p>Applications that wish to supply extra Intent parameters to the parent stack defined
+ * by the manifest should override {@link #onPrepareNavigateUpTaskStack(TaskStackBuilder)}.</p>
+ *
+ * @param builder An empty TaskStackBuilder - the application should add intents representing
+ * the desired task stack
+ */
+ public void onCreateNavigateUpTaskStack(TaskStackBuilder builder) {
+ builder.addParentStack(this);
+ }
+
+ /**
+ * Prepare the synthetic task stack that will be generated during Up navigation
+ * from a different task.
+ *
+ * <p>This method receives the {@link TaskStackBuilder} with the constructed series of
+ * Intents as generated by {@link #onCreateNavigateUpTaskStack(TaskStackBuilder)}.
+ * If any extra data should be added to these intents before launching the new task,
+ * the application should override this method and add that data here.</p>
+ *
+ * @param builder A TaskStackBuilder that has been populated with Intents by
+ * onCreateNavigateUpTaskStack.
+ */
+ public void onPrepareNavigateUpTaskStack(TaskStackBuilder builder) {
+ }
+
+ /**
* This hook is called whenever the options menu is being closed (either by the user canceling
* the menu with the back/menu button, or when an item is selected).
*
@@ -4658,6 +4767,122 @@ public class Activity extends ContextThemeWrapper
public void onActionModeFinished(ActionMode mode) {
}
+ /**
+ * Returns true if the app should recreate the task when navigating 'up' from this activity
+ * by using targetIntent.
+ *
+ * <p>If this method returns false the app can trivially call
+ * {@link #navigateUpTo(Intent)} using the same parameters to correctly perform
+ * up navigation. If this method returns false, the app should synthesize a new task stack
+ * by using {@link TaskStackBuilder} or another similar mechanism to perform up navigation.</p>
+ *
+ * @param targetIntent An intent representing the target destination for up navigation
+ * @return true if navigating up should recreate a new task stack, false if the same task
+ * should be used for the destination
+ */
+ public boolean shouldUpRecreateTask(Intent targetIntent) {
+ try {
+ PackageManager pm = getPackageManager();
+ ComponentName cn = targetIntent.getComponent();
+ if (cn == null) {
+ cn = targetIntent.resolveActivity(pm);
+ }
+ ActivityInfo info = pm.getActivityInfo(cn, 0);
+ if (info.taskAffinity == null) {
+ return false;
+ }
+ return !ActivityManagerNative.getDefault()
+ .targetTaskAffinityMatchesActivity(mToken, info.taskAffinity);
+ } catch (RemoteException e) {
+ return false;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Navigate from this activity to the activity specified by upIntent, finishing this activity
+ * in the process. If the activity indicated by upIntent already exists in the task's history,
+ * this activity and all others before the indicated activity in the history stack will be
+ * finished. If the indicated activity does not appear in the history stack, this is equivalent
+ * to simply calling finish() on this activity.
+ *
+ * <p>This method should be used when performing up navigation from within the same task
+ * as the destination. If up navigation should cross tasks in some cases, see
+ * {@link #shouldUpRecreateTask(Intent)}.</p>
+ *
+ * @param upIntent An intent representing the target destination for up navigation
+ *
+ * @return true if up navigation successfully reached the activity indicated by upIntent and
+ * upIntent was delivered to it. false if an instance of the indicated activity could
+ * not be found and this activity was simply finished normally.
+ */
+ public boolean navigateUpTo(Intent upIntent) {
+ if (mParent == null) {
+ ComponentName destInfo = upIntent.getComponent();
+ if (destInfo == null) {
+ destInfo = upIntent.resolveActivity(getPackageManager());
+ if (destInfo == null) {
+ return false;
+ }
+ upIntent = new Intent(upIntent);
+ upIntent.setComponent(destInfo);
+ }
+ int resultCode;
+ Intent resultData;
+ synchronized (this) {
+ resultCode = mResultCode;
+ resultData = mResultData;
+ }
+ if (resultData != null) {
+ resultData.setAllowFds(false);
+ }
+ try {
+ return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
+ resultCode, resultData);
+ } catch (RemoteException e) {
+ return false;
+ }
+ } else {
+ return mParent.navigateUpToFromChild(this, upIntent);
+ }
+ }
+
+ /**
+ * This is called when a child activity of this one calls its
+ * {@link #navigateUpTo} method. The default implementation simply calls
+ * navigateUpTo(upIntent) on this activity (the parent).
+ *
+ * @param child The activity making the call.
+ * @param upIntent An intent representing the target destination for up navigation
+ *
+ * @return true if up navigation successfully reached the activity indicated by upIntent and
+ * upIntent was delivered to it. false if an instance of the indicated activity could
+ * not be found and this activity was simply finished normally.
+ */
+ public boolean navigateUpToFromChild(Activity child, Intent upIntent) {
+ return navigateUpTo(upIntent);
+ }
+
+ /**
+ * Obtain an {@link Intent} that will launch an explicit target activity specified by
+ * this activity's logical parent. The logical parent is named in the application's manifest
+ * by the {@link android.R.attr#parentActivityName parentActivityName} attribute.
+ * Activity subclasses may override this method to modify the Intent returned by
+ * super.getParentActivityIntent() or to implement a different mechanism of retrieving
+ * the parent intent entirely.
+ *
+ * @return a new Intent targeting the defined parent of this activity or null if
+ * there is no valid parent.
+ */
+ public Intent getParentActivityIntent() {
+ final String parentName = mActivityInfo.parentActivityName;
+ if (TextUtils.isEmpty(parentName)) {
+ return null;
+ }
+ return new Intent().setClassName(this, parentName);
+ }
+
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 531a695..11b4c3a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1774,5 +1774,4 @@ public class ActivityManager {
return false;
}
}
-
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 5917cbf..a3fdf3e 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -17,10 +17,10 @@
package android.app;
import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.IIntentSender;
-import android.content.IIntentReceiver;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
@@ -32,11 +32,11 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
-import android.os.Parcelable;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.text.TextUtils;
@@ -867,6 +867,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_UID_FOR_INTENT_SENDER_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IIntentSender r = IIntentSender.Stub.asInterface(
+ data.readStrongBinder());
+ int res = getUidForIntentSender(r);
+ reply.writeNoException();
+ reply.writeInt(res);
+ return true;
+ }
+
case SET_PROCESS_LIMIT_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int max = data.readInt();
@@ -1605,6 +1615,31 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case TARGET_TASK_AFFINITY_MATCHES_ACTIVITY_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ String destAffinity = data.readString();
+ boolean res = targetTaskAffinityMatchesActivity(token, destAffinity);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
+ case NAVIGATE_UP_TO_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ Intent target = Intent.CREATOR.createFromParcel(data);
+ int resultCode = data.readInt();
+ Intent resultData = null;
+ if (data.readInt() != 0) {
+ resultData = Intent.CREATOR.createFromParcel(data);
+ }
+ boolean res = navigateUpTo(token, target, resultCode, resultData);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -2689,6 +2724,18 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
+ public int getUidForIntentSender(IIntentSender sender) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(sender.asBinder());
+ mRemote.transact(GET_UID_FOR_INTENT_SENDER_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int res = reply.readInt();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
public void setProcessLimit(int max) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -3662,5 +3709,42 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ public boolean targetTaskAffinityMatchesActivity(IBinder token, String destAffinity)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ data.writeString(destAffinity);
+ mRemote.transact(TARGET_TASK_AFFINITY_MATCHES_ACTIVITY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean result = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return result;
+ }
+
+ public boolean navigateUpTo(IBinder token, Intent target, int resultCode, Intent resultData)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ target.writeToParcel(data, 0);
+ data.writeInt(resultCode);
+ if (resultData != null) {
+ data.writeInt(1);
+ resultData.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ mRemote.transact(NAVIGATE_UP_TO_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean result = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return result;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d758eca..c5d7b91 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -45,6 +45,8 @@ import android.graphics.drawable.Drawable;
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
import android.hardware.SerialManager;
+import android.hardware.input.IInputManager;
+import android.hardware.input.InputManager;
import android.hardware.usb.IUsbManager;
import android.hardware.usb.UsbManager;
import android.location.CountryDetector;
@@ -59,6 +61,8 @@ import android.net.NetworkPolicyManager;
import android.net.ThrottleManager;
import android.net.IThrottleManager;
import android.net.Uri;
+import android.net.nsd.INsdManager;
+import android.net.nsd.NsdManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.IWifiP2pManager;
@@ -321,6 +325,11 @@ class ContextImpl extends Context {
return createDropBoxManager();
}});
+ registerService(INPUT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new InputManager(ctx);
+ }});
+
registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return InputMethodManager.getInstance(ctx);
@@ -372,6 +381,14 @@ class ContextImpl extends Context {
ctx.mMainThread.getHandler());
}});
+ registerService(NSD_SERVICE, new ServiceFetcher() {
+ @Override
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(NSD_SERVICE);
+ INsdManager service = INsdManager.Stub.asInterface(b);
+ return new NsdManager(service);
+ }});
+
// Note: this was previously cached in a static variable, but
// constructed using mMainThread.getHandler(), so converting
// it to be a regular Context-cached service...
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index ad8d41f..dd58397 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1097,6 +1097,18 @@ public class DownloadManager {
}
}
+ /** {@hide} */
+ public static boolean isActiveNetworkExpensive(Context context) {
+ // TODO: connect to NetworkPolicyManager
+ return false;
+ }
+
+ /** {@hide} */
+ public static long getActiveNetworkWarningBytes(Context context) {
+ // TODO: connect to NetworkPolicyManager
+ return -1;
+ }
+
/**
* Adds a file to the downloads database system, so it could appear in Downloads App
* (and thus become eligible for management by the Downloads App).
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2b1eb43..c71b186 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -175,6 +175,7 @@ public interface IActivityManager extends IInterface {
public boolean clearApplicationUserData(final String packageName,
final IPackageDataObserver observer, int userId) throws RemoteException;
public String getPackageForIntentSender(IIntentSender sender) throws RemoteException;
+ public int getUidForIntentSender(IIntentSender sender) throws RemoteException;
public void setProcessLimit(int max) throws RemoteException;
public int getProcessLimit() throws RemoteException;
@@ -341,6 +342,12 @@ public interface IActivityManager extends IInterface {
public void dismissKeyguardOnNextActivity() throws RemoteException;
+ public boolean targetTaskAffinityMatchesActivity(IBinder token, String destAffinity)
+ throws RemoteException;
+
+ public boolean navigateUpTo(IBinder token, Intent target, int resultCode, Intent resultData)
+ throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -525,6 +532,7 @@ public interface IActivityManager extends IInterface {
int START_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+89;
int BACKUP_AGENT_CREATED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+90;
int UNBIND_BACKUP_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+91;
+ int GET_UID_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
@@ -578,4 +586,6 @@ public interface IActivityManager extends IInterface {
int GET_MY_MEMORY_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+142;
int KILL_PROCESSES_BELOW_FOREGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+143;
int GET_CURRENT_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+144;
+ int TARGET_TASK_AFFINITY_MATCHES_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+145;
+ int NAVIGATE_UP_TO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+146;
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e4f7950..f955713 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Debug;
import android.os.IBinder;
@@ -35,6 +36,7 @@ import android.os.SystemClock;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.IWindowManager;
+import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -859,11 +861,30 @@ public class Instrumentation {
*/
public void sendKeySync(KeyEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectKeyEvent(event, true);
- } catch (RemoteException e) {
+
+ long downTime = event.getDownTime();
+ long eventTime = event.getEventTime();
+ int action = event.getAction();
+ int code = event.getKeyCode();
+ int repeatCount = event.getRepeatCount();
+ int metaState = event.getMetaState();
+ int deviceId = event.getDeviceId();
+ int scancode = event.getScanCode();
+ int source = event.getSource();
+ int flags = event.getFlags();
+ if (source == InputDevice.SOURCE_UNKNOWN) {
+ source = InputDevice.SOURCE_KEYBOARD;
+ }
+ if (eventTime == 0) {
+ eventTime = SystemClock.uptimeMillis();
+ }
+ if (downTime == 0) {
+ downTime = eventTime;
}
+ KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
+ deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
+ InputManager.injectInputEvent(newEvent,
+ InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
@@ -902,11 +923,10 @@ public class Instrumentation {
*/
public void sendPointerSync(MotionEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectPointerEvent(event, true);
- } catch (RemoteException e) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
}
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
@@ -922,11 +942,10 @@ public class Instrumentation {
*/
public void sendTrackballEventSync(MotionEvent event) {
validateNotAppThread();
- try {
- (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
- .injectTrackballEvent(event, true);
- } catch (RemoteException e) {
+ if ((event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
+ event.setSource(InputDevice.SOURCE_TRACKBALL);
}
+ InputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
/**
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 096af93..04c64a0 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -26,6 +26,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.IntProperty;
import android.util.Log;
@@ -808,6 +809,7 @@ public class Notification implements Parcelable
@Deprecated
public void setLatestEventInfo(Context context,
CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
+ // TODO: rewrite this to use Builder
RemoteViews contentView = new RemoteViews(context.getPackageName(),
R.layout.notification_template_base);
if (this.icon != 0) {
@@ -820,6 +822,7 @@ public class Notification implements Parcelable
contentView.setTextViewText(R.id.text, contentText);
}
if (this.when != 0) {
+ contentView.setViewVisibility(R.id.time, View.VISIBLE);
contentView.setLong(R.id.time, "setTime", when);
}
@@ -942,6 +945,7 @@ public class Notification implements Parcelable
private ArrayList<Action> mActions = new ArrayList<Action>(3);
private boolean mCanHasIntruder;
private boolean mIntruderActionsShowText;
+ private boolean mUseChronometer;
/**
* Constructs a new Builder with the defaults:
@@ -983,6 +987,18 @@ public class Notification implements Parcelable
}
/**
+ * @hide
+ *
+ * Show the {@link Notification#when} field as a countdown (or count-up) timer instead of a timestamp.
+ *
+ * @see Notification#when
+ */
+ public Builder setUsesChronometer(boolean b) {
+ mUseChronometer = b;
+ return this;
+ }
+
+ /**
* Set the small icon resource, which will be used to represent the notification in the
* status bar.
*
@@ -1434,7 +1450,15 @@ public class Notification implements Parcelable
}
}
if (mWhen != 0) {
- contentView.setLong(R.id.time, "setTime", mWhen);
+ if (mUseChronometer) {
+ contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
+ contentView.setLong(R.id.chronometer, "setBase",
+ mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
+ contentView.setBoolean(R.id.chronometer, "setStarted", true);
+ } else {
+ contentView.setViewVisibility(R.id.time, View.VISIBLE);
+ contentView.setLong(R.id.time, "setTime", mWhen);
+ }
}
contentView.setViewVisibility(R.id.line3, hasLine3 ? View.VISIBLE : View.GONE);
return contentView;
diff --git a/core/java/android/app/TaskStackBuilder.java b/core/java/android/app/TaskStackBuilder.java
new file mode 100644
index 0000000..7fd4747
--- /dev/null
+++ b/core/java/android/app/TaskStackBuilder.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012 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.app;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Utility class for constructing synthetic back stacks for cross-task navigation
+ * on Android 3.0 and newer.
+ *
+ * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for
+ * app navigation using the back key changed. The back key's behavior is local
+ * to the current task and does not capture navigation across different tasks.
+ * Navigating across tasks and easily reaching the previous task is accomplished
+ * through the "recents" UI, accessible through the software-provided Recents key
+ * on the navigation or system bar. On devices with the older hardware button configuration
+ * the recents UI can be accessed with a long press on the Home key.</p>
+ *
+ * <p>When crossing from one task stack to another post-Android 3.0,
+ * the application should synthesize a back stack/history for the new task so that
+ * the user may navigate out of the new task and back to the Launcher by repeated
+ * presses of the back key. Back key presses should not navigate across task stacks.</p>
+ *
+ * <p>TaskStackBuilder provides a way to obey the correct conventions
+ * around cross-task navigation.</p>
+ *
+ * <div class="special reference">
+ * <h3>About Navigation</h3>
+ * For more detailed information about tasks, the back stack, and navigation design guidelines,
+ * please read
+ * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
+ * from the developer guide and <a href="{@docRoot}design/patterns/navigation.html">Navigation</a>
+ * from the design guide.
+ * </div>
+ */
+public class TaskStackBuilder implements Iterable<Intent> {
+ private static final String TAG = "TaskStackBuilder";
+
+ private final ArrayList<Intent> mIntents = new ArrayList<Intent>();
+ private final Context mSourceContext;
+
+ private TaskStackBuilder(Context a) {
+ mSourceContext = a;
+ }
+
+ /**
+ * Return a new TaskStackBuilder for launching a fresh task stack consisting
+ * of a series of activities.
+ *
+ * @param context The context that will launch the new task stack or generate a PendingIntent
+ * @return A new TaskStackBuilder
+ */
+ public static TaskStackBuilder from(Context context) {
+ return new TaskStackBuilder(context);
+ }
+
+ /**
+ * Add a new Intent to the task stack. The most recently added Intent will invoke
+ * the Activity at the top of the final task stack.
+ *
+ * @param nextIntent Intent for the next Activity in the synthesized task stack
+ * @return This TaskStackBuilder for method chaining
+ */
+ public TaskStackBuilder addNextIntent(Intent nextIntent) {
+ mIntents.add(nextIntent);
+ return this;
+ }
+
+ /**
+ * Add the activity parent chain as specified by the
+ * {@link android.R.attr#parentActivityName parentActivityName} attribute of the activity
+ * (or activity-alias) element in the application's manifest to the task stack builder.
+ *
+ * @param sourceActivity All parents of this activity will be added
+ * @return This TaskStackBuilder for method chaining
+ */
+ public TaskStackBuilder addParentStack(Activity sourceActivity) {
+ final int insertAt = mIntents.size();
+ Intent parent = sourceActivity.getParentActivityIntent();
+ PackageManager pm = sourceActivity.getPackageManager();
+ while (parent != null) {
+ mIntents.add(insertAt, parent);
+ try {
+ ActivityInfo info = pm.getActivityInfo(parent.getComponent(), 0);
+ String parentActivity = info.parentActivityName;
+ if (parentActivity != null) {
+ parent = new Intent().setComponent(
+ new ComponentName(mSourceContext, parentActivity));
+ } else {
+ parent = null;
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
+ throw new IllegalArgumentException(e);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Add the activity parent chain as specified by the
+ * {@link android.R.attr#parentActivityName parentActivityName} attribute of the activity
+ * (or activity-alias) element in the application's manifest to the task stack builder.
+ *
+ * @param sourceActivityClass All parents of this activity will be added
+ * @return This TaskStackBuilder for method chaining
+ */
+ public TaskStackBuilder addParentStack(Class<?> sourceActivityClass) {
+ final int insertAt = mIntents.size();
+ PackageManager pm = mSourceContext.getPackageManager();
+ try {
+ ActivityInfo info = pm.getActivityInfo(
+ new ComponentName(mSourceContext, sourceActivityClass), 0);
+ String parentActivity = info.parentActivityName;
+ Intent parent = new Intent().setComponent(
+ new ComponentName(mSourceContext, parentActivity));
+ while (parent != null) {
+ mIntents.add(insertAt, parent);
+ info = pm.getActivityInfo(parent.getComponent(), 0);
+ parentActivity = info.parentActivityName;
+ if (parentActivity != null) {
+ parent = new Intent().setComponent(
+ new ComponentName(mSourceContext, parentActivity));
+ } else {
+ parent = null;
+ }
+ }
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
+ throw new IllegalArgumentException(e);
+ }
+ return this;
+ }
+
+ /**
+ * @return the number of intents added so far.
+ */
+ public int getIntentCount() {
+ return mIntents.size();
+ }
+
+ /**
+ * Get the intent at the specified index.
+ * Useful if you need to modify the flags or extras of an intent that was previously added,
+ * for example with {@link #addParentStack(Activity)}.
+ *
+ * @param index Index from 0-getIntentCount()
+ * @return the intent at position index
+ */
+ public Intent getIntent(int index) {
+ return mIntents.get(index);
+ }
+
+ public Iterator<Intent> iterator() {
+ return mIntents.iterator();
+ }
+
+ /**
+ * Start the task stack constructed by this builder.
+ */
+ public void startActivities() {
+ if (mIntents.isEmpty()) {
+ throw new IllegalStateException(
+ "No intents added to TaskStackBuilder; cannot startActivities");
+ }
+
+ Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
+ intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_CLEAR_TASK |
+ Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+ mSourceContext.startActivities(intents);
+ }
+
+ /**
+ * Obtain a {@link PendingIntent} for launching the task constructed by this builder so far.
+ *
+ * @param requestCode Private request code for the sender
+ * @param flags May be {@link PendingIntent#FLAG_ONE_SHOT},
+ * {@link PendingIntent#FLAG_NO_CREATE}, {@link PendingIntent#FLAG_CANCEL_CURRENT},
+ * {@link PendingIntent#FLAG_UPDATE_CURRENT}, or any of the flags supported by
+ * {@link Intent#fillIn(Intent, int)} to control which unspecified parts of the
+ * intent that can be supplied when the actual send happens.
+ * @return The obtained PendingIntent
+ */
+ public PendingIntent getPendingIntent(int requestCode, int flags) {
+ if (mIntents.isEmpty()) {
+ throw new IllegalStateException(
+ "No intents added to TaskStackBuilder; cannot getPendingIntent");
+ }
+
+ Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
+ intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_CLEAR_TASK |
+ Intent.FLAG_ACTIVITY_TASK_ON_HOME);
+ return PendingIntent.getActivities(mSourceContext, requestCode, intents, flags);
+ }
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2902504..36638f9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1769,6 +1769,18 @@ public abstract class Context {
public static final String WIFI_P2P_SERVICE = "wifip2p";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.net.NsdManager} for handling management of network service
+ * discovery
+ *
+ * @hide
+ * @see #getSystemService
+ * @see android.net.NsdManager
+ */
+ public static final String NSD_SERVICE = "servicediscovery";
+
+
+ /**
* Use with {@link #getSystemService} to retrieve a
* {@link android.media.AudioManager} for handling management of volume,
* ringer modes and audio routing.
@@ -1907,6 +1919,15 @@ public abstract class Context {
public static final String SERIAL_SERVICE = "serial";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.hardware.input.InputManager} for interacting with input devices.
+ *
+ * @see #getSystemService
+ * @see android.hardware.input.InputManager
+ */
+ public static final String INPUT_SERVICE = "input";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 2a9f1af..18d682d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2000,8 +2000,8 @@ public class Intent implements Parcelable, Cloneable {
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_ANLG_HEADSET_PLUG =
- "android.intent.action.USB_ANLG_HEADSET_PLUG";
+ public static final String ACTION_ANALOG_AUDIO_DOCK_PLUG =
+ "android.intent.action.ANALOG_AUDIO_DOCK_PLUG";
/**
* Broadcast Action: A digital audio speaker/headset plugged in or unplugged.
@@ -2015,8 +2015,8 @@ public class Intent implements Parcelable, Cloneable {
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_USB_DGTL_HEADSET_PLUG =
- "android.intent.action.USB_DGTL_HEADSET_PLUG";
+ public static final String ACTION_DIGITAL_AUDIO_DOCK_PLUG =
+ "android.intent.action.DIGITAL_AUDIO_DOCK_PLUG";
/**
* Broadcast Action: A HMDI cable was plugged or unplugged
@@ -2034,6 +2034,38 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.HDMI_AUDIO_PLUG";
/**
+ * Broadcast Action: A USB audio accessory was plugged in or unplugged.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+ * <li><em>card</em> - ALSA card number (integer) </li>
+ * <li><em>device</em> - ALSA device number (integer) </li>
+ * </ul>
+ * </ul>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_AUDIO_ACCESSORY_PLUG =
+ "android.intent.action.USB_AUDIO_ACCESSORY_PLUG";
+
+ /**
+ * Broadcast Action: A USB audio device was plugged in or unplugged.
+ *
+ * <p>The intent will have the following extra values:
+ * <ul>
+ * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+ * <li><em>card</em> - ALSA card number (integer) </li>
+ * <li><em>device</em> - ALSA device number (integer) </li>
+ * </ul>
+ * </ul>
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_USB_AUDIO_DEVICE_PLUG =
+ "android.intent.action.USB_AUDIO_DEVICE_PLUG";
+
+ /**
* <p>Broadcast Action: The user has switched on advanced settings in the settings app:</p>
* <ul>
* <li><em>state</em> - A boolean value indicating whether the settings is on or off.</li>
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0e6694d..6b16e74 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -450,6 +450,11 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW = 1;
+ /**
+ * If defined, the activity named here is the logical parent of this activity.
+ */
+ public String parentActivityName;
+
public ActivityInfo() {
}
@@ -465,6 +470,7 @@ public class ActivityInfo extends ComponentInfo
configChanges = orig.configChanges;
softInputMode = orig.softInputMode;
uiOptions = orig.uiOptions;
+ parentActivityName = orig.parentActivityName;
}
/**
@@ -524,6 +530,7 @@ public class ActivityInfo extends ComponentInfo
dest.writeInt(configChanges);
dest.writeInt(softInputMode);
dest.writeInt(uiOptions);
+ dest.writeString(parentActivityName);
}
public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -548,5 +555,6 @@ public class ActivityInfo extends ComponentInfo
configChanges = source.readInt();
softInputMode = source.readInt();
uiOptions = source.readInt();
+ parentActivityName = source.readString();
}
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index a79b86a..7571993 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -94,10 +94,12 @@ public class PackageParser {
public static class SplitPermissionInfo {
public final String rootPerm;
public final String[] newPerms;
+ public final int targetSdk;
- public SplitPermissionInfo(String rootPerm, String[] newPerms) {
+ public SplitPermissionInfo(String rootPerm, String[] newPerms, int targetSdk) {
this.rootPerm = rootPerm;
this.newPerms = newPerms;
+ this.targetSdk = targetSdk;
}
}
@@ -126,7 +128,14 @@ public class PackageParser {
public static final PackageParser.SplitPermissionInfo SPLIT_PERMISSIONS[] =
new PackageParser.SplitPermissionInfo[] {
new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
- new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE })
+ new String[] { android.Manifest.permission.READ_EXTERNAL_STORAGE },
+ android.os.Build.VERSION_CODES.CUR_DEVELOPMENT+1),
+ new PackageParser.SplitPermissionInfo(android.Manifest.permission.READ_CONTACTS,
+ new String[] { android.Manifest.permission.READ_CALL_LOG },
+ android.os.Build.VERSION_CODES.JELLY_BEAN),
+ new PackageParser.SplitPermissionInfo(android.Manifest.permission.WRITE_CONTACTS,
+ new String[] { android.Manifest.permission.WRITE_CALL_LOG },
+ android.os.Build.VERSION_CODES.JELLY_BEAN)
};
private String mArchiveSourcePath;
@@ -1293,8 +1302,9 @@ public class PackageParser {
for (int is=0; is<NS; is++) {
final PackageParser.SplitPermissionInfo spi
= PackageParser.SPLIT_PERMISSIONS[is];
- if (!pkg.requestedPermissions.contains(spi.rootPerm)) {
- break;
+ if (pkg.applicationInfo.targetSdkVersion >= spi.targetSdk
+ || !pkg.requestedPermissions.contains(spi.rootPerm)) {
+ continue;
}
for (int in=0; in<spi.newPerms.length; in++) {
final String perm = spi.newPerms[in];
@@ -2030,6 +2040,19 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestActivity_uiOptions,
a.info.applicationInfo.uiOptions);
+ String parentName = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName, 0);
+ if (parentName != null) {
+ String parentClassName = buildClassName(a.info.packageName, parentName, outError);
+ if (outError[0] == null) {
+ a.info.parentActivityName = parentClassName;
+ } else {
+ Log.e(TAG, "Activity " + a.info.name + " specified invalid parentActivityName " +
+ parentName);
+ outError[0] = null;
+ }
+ }
+
String str;
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestActivity_permission, 0);
@@ -2274,6 +2297,7 @@ public class PackageParser {
info.theme = target.info.theme;
info.softInputMode = target.info.softInputMode;
info.uiOptions = target.info.uiOptions;
+ info.parentActivityName = target.info.parentActivityName;
Activity a = new Activity(mParseActivityAliasArgs, info);
if (outError[0] != null) {
@@ -2295,6 +2319,20 @@ public class PackageParser {
a.info.permission = str.length() > 0 ? str.toString().intern() : null;
}
+ String parentName = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
+ 0);
+ if (parentName != null) {
+ String parentClassName = buildClassName(a.info.packageName, parentName, outError);
+ if (outError[0] == null) {
+ a.info.parentActivityName = parentClassName;
+ } else {
+ Log.e(TAG, "Activity alias " + a.info.name +
+ " specified invalid parentActivityName " + parentName);
+ outError[0] = null;
+ }
+ }
+
sa.recycle();
if (outError[0] != null) {
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
new file mode 100644
index 0000000..c2abce5
--- /dev/null
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 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.hardware.input;
+
+import android.view.InputDevice;
+import android.view.InputEvent;
+
+/** @hide */
+interface IInputManager {
+ // Gets input device information.
+ InputDevice getInputDevice(int deviceId);
+ int[] getInputDeviceIds();
+
+ // Reports whether the hardware supports the given keys; returns true if successful
+ boolean hasKeys(int deviceId, int sourceMask, in int[] keyCodes, out boolean[] keyExists);
+
+ // Temporarily changes the pointer speed.
+ void tryPointerSpeed(int speed);
+
+ // Injects an input event into the system. To inject into windows owned by other
+ // applications, the caller must have the INJECT_EVENTS permission.
+ boolean injectInputEvent(in InputEvent ev, int mode);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
new file mode 100755
index 0000000..5ead1f4
--- /dev/null
+++ b/core/java/android/hardware/input/InputManager.java
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 2012 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.hardware.input;
+
+import com.android.internal.util.XmlUtils;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.KeyCharacterMap;
+import android.view.KeyCharacterMap.UnavailableException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Provides information about input devices and available key layouts.
+ * <p>
+ * Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(java.lang.String)
+ * Context.getSystemService()} with the argument
+ * {@link android.content.Context#INPUT_SERVICE}.
+ * </p>
+ */
+public final class InputManager {
+ private static final String TAG = "InputManager";
+
+ private static final IInputManager sIm;
+
+ private final Context mContext;
+
+ // Used to simulate a persistent data store.
+ // TODO: Replace with the real thing.
+ private static final HashMap<String, String> mFakeRegistry = new HashMap<String, String>();
+
+ /**
+ * Broadcast Action: Query available keyboard layouts.
+ * <p>
+ * The input manager service locates available keyboard layouts
+ * by querying broadcast receivers that are registered for this action.
+ * An application can offer additional keyboard layouts to the user
+ * by declaring a suitable broadcast receiver in its manifest.
+ * </p><p>
+ * Here is an example broadcast receiver declaration that an application
+ * might include in its AndroidManifest.xml to advertise keyboard layouts.
+ * The meta-data specifies a resource that contains a description of each keyboard
+ * layout that is provided by the application.
+ * <pre><code>
+ * &lt;receiver android:name=".InputDeviceReceiver">
+ * &lt;intent-filter>
+ * &lt;action android:name="android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS" />
+ * &lt;/intent-filter>
+ * &lt;meta-data android:name="android.hardware.input.metadata.KEYBOARD_LAYOUTS"
+ * android:resource="@xml/keyboard_layouts" />
+ * &lt;/receiver>
+ * </code></pre>
+ * </p><p>
+ * In the above example, the <code>@xml/keyboard_layouts</code> resource refers to
+ * an XML resource whose root element is <code>&lt;keyboard-layouts></code> that
+ * contains zero or more <code>&lt;keyboard-layout></code> elements.
+ * Each <code>&lt;keyboard-layout></code> element specifies the name, label, and location
+ * of a key character map for a particular keyboard layout.
+ * <pre></code>
+ * &lt;?xml version="1.0" encoding="utf-8"?>
+ * &lt;keyboard-layouts xmlns:android="http://schemas.android.com/apk/res/android">
+ * &lt;keyboard-layout android:name="keyboard_layout_english_us"
+ * android:label="@string/keyboard_layout_english_us_label"
+ * android:kcm="@raw/keyboard_layout_english_us" />
+ * &lt;/keyboard-layouts>
+ * </p><p>
+ * The <code>android:name</code> attribute specifies an identifier by which
+ * the keyboard layout will be known in the package.
+ * The <code>android:label</code> attributes specifies a human-readable descriptive
+ * label to describe the keyboard layout in the user interface, such as "English (US)".
+ * The <code>android:kcm</code> attribute refers to a
+ * <a href="http://source.android.com/tech/input/key-character-map-files.html">
+ * key character map</a> resource that defines the keyboard layout.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_QUERY_KEYBOARD_LAYOUTS =
+ "android.hardware.input.action.QUERY_KEYBOARD_LAYOUTS";
+
+ /**
+ * Metadata Key: Keyboard layout metadata associated with
+ * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS}.
+ * <p>
+ * Specifies the resource id of a XML resource that describes the keyboard
+ * layouts that are provided by the application.
+ * </p>
+ */
+ public static final String META_DATA_KEYBOARD_LAYOUTS =
+ "android.hardware.input.metadata.KEYBOARD_LAYOUTS";
+
+ /**
+ * Pointer Speed: The minimum (slowest) pointer speed (-7).
+ * @hide
+ */
+ public static final int MIN_POINTER_SPEED = -7;
+
+ /**
+ * Pointer Speed: The maximum (fastest) pointer speed (7).
+ * @hide
+ */
+ public static final int MAX_POINTER_SPEED = 7;
+
+ /**
+ * Pointer Speed: The default pointer speed (0).
+ * @hide
+ */
+ public static final int DEFAULT_POINTER_SPEED = 0;
+
+ /**
+ * Input Event Injection Synchronization Mode: None.
+ * Never blocks. Injection is asynchronous and is assumed always to be successful.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0; // see InputDispatcher.h
+
+ /**
+ * Input Event Injection Synchronization Mode: Wait for result.
+ * Waits for previous events to be dispatched so that the input dispatcher can
+ * determine whether input event injection will be permitted based on the current
+ * input focus. Does not wait for the input event to finish being handled
+ * by the application.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1; // see InputDispatcher.h
+
+ /**
+ * Input Event Injection Synchronization Mode: Wait for finish.
+ * Waits for the event to be delivered to the application and handled.
+ * @hide
+ */
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; // see InputDispatcher.h
+
+ static {
+ IBinder b = ServiceManager.getService(Context.INPUT_SERVICE);
+ sIm = IInputManager.Stub.asInterface(b);
+ }
+
+ /** @hide */
+ public InputManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Gets information about all supported keyboard layouts.
+ * <p>
+ * The input manager consults the built-in keyboard layouts as well
+ * as all keyboard layouts advertised by applications using a
+ * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS} broadcast receiver.
+ * </p>
+ *
+ * @return A list of all supported keyboard layouts.
+ * @hide
+ */
+ public List<KeyboardLayout> getKeyboardLayouts() {
+ ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
+
+ final PackageManager pm = mContext.getPackageManager();
+ Intent intent = new Intent(ACTION_QUERY_KEYBOARD_LAYOUTS);
+ for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
+ PackageManager.GET_META_DATA)) {
+ loadKeyboardLayouts(pm, resolveInfo.activityInfo, list, null);
+ }
+ return list;
+ }
+
+ /**
+ * Gets the keyboard layout with the specified descriptor.
+ *
+ * @param keyboardLayoutDescriptor The keyboard layout descriptor, as returned by
+ * {@link KeyboardLayout#getDescriptor()}.
+ * @return The keyboard layout, or null if it could not be loaded.
+ *
+ * @hide
+ */
+ public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
+ if (keyboardLayoutDescriptor == null) {
+ throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+ }
+
+ KeyboardLayoutDescriptor d = parseKeyboardLayoutDescriptor(keyboardLayoutDescriptor);
+ if (d == null) {
+ return null;
+ }
+
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ ActivityInfo receiver = pm.getReceiverInfo(
+ new ComponentName(d.packageName, d.receiverName),
+ PackageManager.GET_META_DATA);
+ return loadKeyboardLayouts(pm, receiver, null, d.keyboardLayoutName);
+ } catch (NameNotFoundException ex) {
+ Log.w(TAG, "Could not load keyboard layout '" + d.keyboardLayoutName
+ + "' from receiver " + d.packageName + "/" + d.receiverName, ex);
+ return null;
+ }
+ }
+
+ /**
+ * Gets the keyboard layout descriptor for the specified input device.
+ *
+ * @param inputDeviceDescriptor The input device descriptor.
+ * @return The keyboard layout descriptor, or null if unknown or if the default
+ * keyboard layout will be used.
+ *
+ * @hide
+ */
+ public String getInputDeviceKeyboardLayoutDescriptor(String inputDeviceDescriptor) {
+ if (inputDeviceDescriptor == null) {
+ throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+ }
+
+ return mFakeRegistry.get(inputDeviceDescriptor);
+ }
+
+ /**
+ * Sets the keyboard layout descriptor for the specified input device.
+ * <p>
+ * This method may have the side-effect of causing the input device in question
+ * to be reconfigured.
+ * </p>
+ *
+ * @param inputDeviceDescriptor The input device descriptor.
+ * @param keyboardLayoutDescriptor The keyboard layout descriptor, or null to remove
+ * the mapping so that the default keyboard layout will be used for the input device.
+ *
+ * @hide
+ */
+ public void setInputDeviceKeyboardLayoutDescriptor(String inputDeviceDescriptor,
+ String keyboardLayoutDescriptor) {
+ if (inputDeviceDescriptor == null) {
+ throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+ }
+
+ mFakeRegistry.put(inputDeviceDescriptor, keyboardLayoutDescriptor);
+ }
+
+ private KeyboardLayout loadKeyboardLayouts(
+ PackageManager pm, ActivityInfo receiver,
+ List<KeyboardLayout> list, String keyboardName) {
+ Bundle metaData = receiver.metaData;
+ if (metaData == null) {
+ return null;
+ }
+
+ int configResId = metaData.getInt(META_DATA_KEYBOARD_LAYOUTS);
+ if (configResId == 0) {
+ Log.w(TAG, "Missing meta-data '" + META_DATA_KEYBOARD_LAYOUTS + "' on receiver "
+ + receiver.packageName + "/" + receiver.name);
+ return null;
+ }
+
+ try {
+ Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
+ XmlResourceParser parser = resources.getXml(configResId);
+ try {
+ XmlUtils.beginDocument(parser, "keyboard-layouts");
+
+ for (;;) {
+ XmlUtils.nextElement(parser);
+ String element = parser.getName();
+ if (element == null) {
+ break;
+ }
+ if (element.equals("keyboard-layout")) {
+ TypedArray a = resources.obtainAttributes(
+ parser, com.android.internal.R.styleable.KeyboardLayout);
+ try {
+ String name = a.getString(
+ com.android.internal.R.styleable.KeyboardLayout_name);
+ String label = a.getString(
+ com.android.internal.R.styleable.KeyboardLayout_label);
+ int kcmResId = a.getResourceId(
+ com.android.internal.R.styleable.KeyboardLayout_kcm, 0);
+ if (name == null || label == null || kcmResId == 0) {
+ Log.w(TAG, "Missing required 'name', 'label' or 'kcm' "
+ + "attributes in keyboard layout "
+ + "resource from receiver "
+ + receiver.packageName + "/" + receiver.name);
+ } else {
+ String descriptor = makeKeyboardLayoutDescriptor(
+ receiver.packageName, receiver.name, name);
+ KeyboardLayout c = new KeyboardLayout(
+ descriptor, label, kcmResId);
+ if (keyboardName != null && name.equals(keyboardName)) {
+ return c;
+ }
+ if (list != null) {
+ list.add(c);
+ }
+ }
+ } finally {
+ a.recycle();
+ }
+ } else {
+ Log.w(TAG, "Skipping unrecognized element '" + element
+ + "' in keyboard layout resource from receiver "
+ + receiver.packageName + "/" + receiver.name);
+ }
+ }
+ } finally {
+ parser.close();
+ }
+ } catch (Exception ex) {
+ Log.w(TAG, "Could not load keyboard layout resource from receiver "
+ + receiver.packageName + "/" + receiver.name, ex);
+ return null;
+ }
+ if (keyboardName != null) {
+ Log.w(TAG, "Could not load keyboard layout '" + keyboardName
+ + "' from receiver " + receiver.packageName + "/" + receiver.name
+ + " because it was not declared in the keyboard layout resource.");
+ }
+ return null;
+ }
+
+ /**
+ * Gets the mouse pointer speed.
+ * <p>
+ * Only returns the permanent mouse pointer speed. Ignores any temporary pointer
+ * speed set by {@link #tryPointerSpeed}.
+ * </p>
+ *
+ * @return The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public int getPointerSpeed() {
+ int speed = DEFAULT_POINTER_SPEED;
+ try {
+ speed = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.POINTER_SPEED);
+ } catch (SettingNotFoundException snfe) {
+ }
+ return speed;
+ }
+
+ /**
+ * Sets the mouse pointer speed.
+ * <p>
+ * Requires {@link android.Manifest.permissions.WRITE_SETTINGS}.
+ * </p>
+ *
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public void setPointerSpeed(int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ Settings.System.putInt(mContext.getContentResolver(),
+ Settings.System.POINTER_SPEED, speed);
+ }
+
+ /**
+ * Changes the mouse pointer speed temporarily, but does not save the setting.
+ * <p>
+ * Requires {@link android.Manifest.permission.SET_POINTER_SPEED}.
+ * </p>
+ *
+ * @param speed The pointer speed as a value between {@link #MIN_POINTER_SPEED} and
+ * {@link #MAX_POINTER_SPEED}, or the default value {@link #DEFAULT_POINTER_SPEED}.
+ *
+ * @hide
+ */
+ public void tryPointerSpeed(int speed) {
+ if (speed < MIN_POINTER_SPEED || speed > MAX_POINTER_SPEED) {
+ throw new IllegalArgumentException("speed out of range");
+ }
+
+ try {
+ sIm.tryPointerSpeed(speed);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Could not set temporary pointer speed.", ex);
+ }
+ }
+
+ /**
+ * Gets information about the input device with the specified id.
+ * @param id The device id.
+ * @return The input device or null if not found.
+ *
+ * @hide
+ */
+ public static InputDevice getInputDevice(int id) {
+ try {
+ return sIm.getInputDevice(id);
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Could not get input device information.", ex);
+ }
+ }
+
+ /**
+ * Gets the ids of all input devices in the system.
+ * @return The input device ids.
+ *
+ * @hide
+ */
+ public static int[] getInputDeviceIds() {
+ try {
+ return sIm.getInputDeviceIds();
+ } catch (RemoteException ex) {
+ throw new RuntimeException("Could not get input device ids.", ex);
+ }
+ }
+
+ /**
+ * Queries the framework about whether any physical keys exist on the
+ * any keyboard attached to the device that are capable of producing the given
+ * array of key codes.
+ *
+ * @param keyCodes The array of key codes to query.
+ * @return A new array of the same size as the key codes array whose elements
+ * are set to true if at least one attached keyboard supports the corresponding key code
+ * at the same index in the key codes array.
+ *
+ * @hide
+ */
+ public static boolean[] deviceHasKeys(int[] keyCodes) {
+ boolean[] ret = new boolean[keyCodes.length];
+ try {
+ sIm.hasKeys(-1, InputDevice.SOURCE_ANY, keyCodes, ret);
+ } catch (RemoteException e) {
+ // no fallback; just return the empty array
+ }
+ return ret;
+ }
+
+ /**
+ * Injects an input event into the event system on behalf of an application.
+ * The synchronization mode determines whether the method blocks while waiting for
+ * input injection to proceed.
+ * <p>
+ * Requires {@link android.Manifest.permission.INJECT_EVENTS} to inject into
+ * windows that are owned by other applications.
+ * </p><p>
+ * Make sure you correctly set the event time and input source of the event
+ * before calling this method.
+ * </p>
+ *
+ * @param event The event to inject.
+ * @param mode The synchronization mode. One of:
+ * {@link #INJECT_INPUT_EVENT_MODE_ASYNC},
+ * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT}, or
+ * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH}.
+ * @return True if input event injection succeeded.
+ *
+ * @hide
+ */
+ public static boolean injectInputEvent(InputEvent event, int mode) {
+ if (event == null) {
+ throw new IllegalArgumentException("event must not be null");
+ }
+ if (mode != INJECT_INPUT_EVENT_MODE_ASYNC
+ && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
+ && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
+ throw new IllegalArgumentException("mode is invalid");
+ }
+
+ try {
+ return sIm.injectInputEvent(event, mode);
+ } catch (RemoteException ex) {
+ return false;
+ }
+ }
+
+ private static String makeKeyboardLayoutDescriptor(String packageName,
+ String receiverName, String keyboardName) {
+ return packageName + "/" + receiverName + "/" + keyboardName;
+ }
+
+ private static KeyboardLayoutDescriptor parseKeyboardLayoutDescriptor(String descriptor) {
+ int pos = descriptor.indexOf('/');
+ if (pos < 0 || pos + 1 == descriptor.length()) {
+ return null;
+ }
+ int pos2 = descriptor.indexOf('/', pos + 1);
+ if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
+ return null;
+ }
+
+ KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
+ result.packageName = descriptor.substring(0, pos);
+ result.receiverName = descriptor.substring(pos + 1, pos2);
+ result.keyboardLayoutName = descriptor.substring(pos2 + 1);
+ return result;
+ }
+
+ /**
+ * Describes a keyboard layout.
+ *
+ * @hide
+ */
+ public static final class KeyboardLayout implements Parcelable,
+ Comparable<KeyboardLayout> {
+ private final String mDescriptor;
+ private final String mLabel;
+ private final int mKeyCharacterMapResId;
+
+ private KeyCharacterMap mKeyCharacterMap;
+
+ public static final Parcelable.Creator<KeyboardLayout> CREATOR =
+ new Parcelable.Creator<KeyboardLayout>() {
+ public KeyboardLayout createFromParcel(Parcel source) {
+ return new KeyboardLayout(source);
+ }
+ public KeyboardLayout[] newArray(int size) {
+ return new KeyboardLayout[size];
+ }
+ };
+
+ private KeyboardLayout(String descriptor,
+ String label, int keyCharacterMapResId) {
+ mDescriptor = descriptor;
+ mLabel = label;
+ mKeyCharacterMapResId = keyCharacterMapResId;
+ }
+
+ private KeyboardLayout(Parcel source) {
+ mDescriptor = source.readString();
+ mLabel = source.readString();
+ mKeyCharacterMapResId = source.readInt();
+ }
+
+ /**
+ * Gets the keyboard layout descriptor, which can be used to retrieve
+ * the keyboard layout again later using
+ * {@link InputManager#getKeyboardLayout(String)}.
+ *
+ * @return The keyboard layout descriptor.
+ */
+ public String getDescriptor() {
+ return mDescriptor;
+ }
+
+ /**
+ * Gets the keyboard layout descriptive label to show in the user interface.
+ * @return The keyboard layout descriptive label.
+ */
+ public String getLabel() {
+ return mLabel;
+ }
+
+ /**
+ * Loads the key character map associated with the keyboard layout.
+ *
+ * @param pm The package manager.
+ * @return The key character map, or null if it could not be loaded for any reason.
+ */
+ public KeyCharacterMap loadKeyCharacterMap(PackageManager pm) {
+ if (pm == null) {
+ throw new IllegalArgumentException("pm must not be null");
+ }
+
+ if (mKeyCharacterMap == null) {
+ KeyboardLayoutDescriptor d = parseKeyboardLayoutDescriptor(mDescriptor);
+ if (d == null) {
+ Log.e(TAG, "Could not load key character map '" + mDescriptor
+ + "' because the descriptor could not be parsed.");
+ return null;
+ }
+
+ CharSequence cs = pm.getText(d.packageName, mKeyCharacterMapResId, null);
+ if (cs == null) {
+ Log.e(TAG, "Could not load key character map '" + mDescriptor
+ + "' because its associated resource could not be loaded.");
+ return null;
+ }
+
+ try {
+ mKeyCharacterMap = KeyCharacterMap.load(cs);
+ } catch (UnavailableException ex) {
+ Log.e(TAG, "Could not load key character map '" + mDescriptor
+ + "' due to an error while parsing.", ex);
+ return null;
+ }
+ }
+ return mKeyCharacterMap;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mDescriptor);
+ dest.writeString(mLabel);
+ dest.writeInt(mKeyCharacterMapResId);
+ }
+
+ @Override
+ public int compareTo(KeyboardLayout another) {
+ return mLabel.compareToIgnoreCase(another.mLabel);
+ }
+
+ @Override
+ public String toString() {
+ return mLabel;
+ }
+ }
+
+ private static final class KeyboardLayoutDescriptor {
+ public String packageName;
+ public String receiverName;
+ public String keyboardLayoutName;
+ }
+}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 93f93c7..c40504a 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -66,6 +66,8 @@ public class UsbManager {
* PTP function is enabled
* <li> {@link #USB_FUNCTION_PTP} boolean extra indicating whether the
* accessory function is enabled
+ * <li> {@link #USB_FUNCTION_AUDIO_SOURCE} boolean extra indicating whether the
+ * audio source function is enabled
* </ul>
*
* {@hide}
@@ -178,6 +180,14 @@ public class UsbManager {
public static final String USB_FUNCTION_PTP = "ptp";
/**
+ * Name of the audio source USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ *
+ * {@hide}
+ */
+ public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
+
+ /**
* Name of the Accessory USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2eef8f4..de16985 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.RemoteException;
@@ -610,6 +611,11 @@ public class ConnectivityManager {
mService = checkNotNull(service, "missing IConnectivityManager");
}
+ /** {@hide} */
+ public static ConnectivityManager from(Context context) {
+ return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
/**
* {@hide}
*/
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index 0e883cf..b4f6367 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -16,6 +16,7 @@
package android.net;
+import android.net.INetworkStatsSession;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
@@ -23,15 +24,11 @@ import android.net.NetworkTemplate;
/** {@hide} */
interface INetworkStatsService {
- /** Return historical network layer stats for traffic that matches template. */
- NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
- /** Return historical network layer stats for specific UID traffic that matches template. */
- NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+ /** Start a statistics query session. */
+ INetworkStatsSession openSession();
- /** Return network layer usage summary for traffic that matches template. */
- NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
- /** Return network layer usage summary per UID for traffic that matches template. */
- NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+ /** Return network layer usage total for traffic that matches template. */
+ long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
/** Return data layer snapshot of UID network usage. */
NetworkStats getDataLayerSnapshotForUid(int uid);
diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl
new file mode 100644
index 0000000..1596fa2
--- /dev/null
+++ b/core/java/android/net/INetworkStatsSession.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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;
+
+import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+
+/** {@hide} */
+interface INetworkStatsSession {
+
+ /** Return network layer usage summary for traffic that matches template. */
+ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end);
+ /** Return historical network layer stats for traffic that matches template. */
+ NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields);
+
+ /** Return network layer usage summary per UID for traffic that matches template. */
+ NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+ /** Return historical network layer stats for specific UID traffic that matches template. */
+ NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
+
+ void close();
+
+}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index ee12989..4ac5e76 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -16,9 +16,13 @@
package android.net;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import android.content.Context;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
import android.os.Build;
import android.telephony.TelephonyManager;
@@ -42,18 +46,21 @@ public class NetworkIdentity {
final int mType;
final int mSubType;
final String mSubscriberId;
+ final String mNetworkId;
final boolean mRoaming;
- public NetworkIdentity(int type, int subType, String subscriberId, boolean roaming) {
- this.mType = type;
- this.mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType;
- this.mSubscriberId = subscriberId;
- this.mRoaming = roaming;
+ public NetworkIdentity(
+ int type, int subType, String subscriberId, String networkId, boolean roaming) {
+ mType = type;
+ mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType;
+ mSubscriberId = subscriberId;
+ mNetworkId = networkId;
+ mRoaming = roaming;
}
@Override
public int hashCode() {
- return Objects.hashCode(mType, mSubType, mSubscriberId, mRoaming);
+ return Objects.hashCode(mType, mSubType, mSubscriberId, mNetworkId, mRoaming);
}
@Override
@@ -61,27 +68,34 @@ public class NetworkIdentity {
if (obj instanceof NetworkIdentity) {
final NetworkIdentity ident = (NetworkIdentity) obj;
return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming
- && Objects.equal(mSubscriberId, ident.mSubscriberId);
+ && Objects.equal(mSubscriberId, ident.mSubscriberId)
+ && Objects.equal(mNetworkId, ident.mNetworkId);
}
return false;
}
@Override
public String toString() {
- final String typeName = ConnectivityManager.getNetworkTypeName(mType);
- final String subTypeName;
+ final StringBuilder builder = new StringBuilder("[");
+ builder.append("type=").append(getNetworkTypeName(mType));
+ builder.append(", subType=");
if (COMBINE_SUBTYPE_ENABLED) {
- subTypeName = "COMBINED";
+ builder.append("COMBINED");
} else if (ConnectivityManager.isNetworkTypeMobile(mType)) {
- subTypeName = TelephonyManager.getNetworkTypeName(mSubType);
+ builder.append(TelephonyManager.getNetworkTypeName(mSubType));
} else {
- subTypeName = Integer.toString(mSubType);
+ builder.append(mSubType);
}
-
- final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
- final String roaming = mRoaming ? ", ROAMING" : "";
- return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId="
- + scrubSubscriberId + roaming + "]";
+ if (mSubscriberId != null) {
+ builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
+ }
+ if (mNetworkId != null) {
+ builder.append(", networkId=").append(mNetworkId);
+ }
+ if (mRoaming) {
+ builder.append(", ROAMING");
+ }
+ return builder.append("]").toString();
}
public int getType() {
@@ -96,6 +110,10 @@ public class NetworkIdentity {
return mSubscriberId;
}
+ public String getNetworkId() {
+ return mNetworkId;
+ }
+
public boolean getRoaming() {
return mRoaming;
}
@@ -106,8 +124,11 @@ public class NetworkIdentity {
public static String scrubSubscriberId(String subscriberId) {
if ("eng".equals(Build.TYPE)) {
return subscriberId;
+ } else if (subscriberId != null) {
+ // TODO: parse this as MCC+MNC instead of hard-coding
+ return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "...";
} else {
- return subscriberId != null ? "valid" : "null";
+ return "null";
}
}
@@ -122,8 +143,10 @@ public class NetworkIdentity {
// TODO: consider moving subscriberId over to LinkCapabilities, so it
// comes from an authoritative source.
- final String subscriberId;
- final boolean roaming;
+ String subscriberId = null;
+ String networkId = null;
+ boolean roaming = false;
+
if (isNetworkTypeMobile(type)) {
final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
Context.TELEPHONY_SERVICE);
@@ -133,10 +156,13 @@ public class NetworkIdentity {
} else {
subscriberId = telephony.getSubscriberId();
}
- } else {
- subscriberId = null;
- roaming = false;
+
+ } else if (type == TYPE_WIFI) {
+ final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ final WifiInfo info = wifi.getConnectionInfo();
+ networkId = info != null ? info.getSSID() : null;
}
- return new NetworkIdentity(type, subType, subscriberId, roaming);
+
+ return new NetworkIdentity(type, subType, subscriberId, networkId, roaming);
}
}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index c1f58a3..441db7a 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -30,6 +30,7 @@ import com.android.internal.util.Objects;
* @hide
*/
public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
+ public static final int CYCLE_NONE = -1;
public static final long WARNING_DISABLED = -1;
public static final long LIMIT_DISABLED = -1;
public static final long SNOOZE_NEVER = -1;
@@ -123,6 +124,13 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
lastLimitSnooze = SNOOZE_NEVER;
}
+ /**
+ * Test if this policy has a cycle defined, after which usage should reset.
+ */
+ public boolean hasCycle() {
+ return cycleDay != CYCLE_NONE;
+ }
+
@Override
public int compareTo(NetworkPolicy another) {
if (another == null || another.limitBytes == LIMIT_DISABLED) {
@@ -159,10 +167,17 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
@Override
public String toString() {
- return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", cycleTimezone="
- + cycleTimezone + ", warningBytes=" + warningBytes + ", limitBytes=" + limitBytes
- + ", lastWarningSnooze=" + lastWarningSnooze + ", lastLimitSnooze="
- + lastLimitSnooze + ", metered=" + metered + ", inferred=" + inferred;
+ final StringBuilder builder = new StringBuilder("NetworkPolicy");
+ builder.append("[").append(template).append("]:");
+ builder.append(" cycleDay=").append(cycleDay);
+ builder.append(", cycleTimezone=").append(cycleTimezone);
+ builder.append(", warningBytes=").append(warningBytes);
+ builder.append(", limitBytes=").append(limitBytes);
+ builder.append(", lastWarningSnooze=").append(lastWarningSnooze);
+ builder.append(", lastLimitSnooze=").append(lastLimitSnooze);
+ builder.append(", metered=").append(metered);
+ builder.append(", inferred=").append(inferred);
+ return builder.toString();
}
public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index c09c676..2b36131 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -17,6 +17,7 @@
package android.net;
import static android.content.pm.PackageManager.GET_SIGNATURES;
+import static android.net.NetworkPolicy.CYCLE_NONE;
import static android.text.format.Time.MONTH_DAY;
import android.content.Context;
@@ -66,27 +67,10 @@ public class NetworkPolicyManager {
mService = service;
}
- public static NetworkPolicyManager getSystemService(Context context) {
+ public static NetworkPolicyManager from(Context context) {
return (NetworkPolicyManager) context.getSystemService(Context.NETWORK_POLICY_SERVICE);
}
- /** {@hide} */
- public void setNetworkPolicies(NetworkPolicy[] policies) {
- try {
- mService.setNetworkPolicies(policies);
- } catch (RemoteException e) {
- }
- }
-
- /** {@hide} */
- public NetworkPolicy[] getNetworkPolicies() {
- try {
- return mService.getNetworkPolicies();
- } catch (RemoteException e) {
- return null;
- }
- }
-
/**
* Set policy flags for specific application.
*
@@ -122,6 +106,36 @@ public class NetworkPolicyManager {
}
}
+ public void setNetworkPolicies(NetworkPolicy[] policies) {
+ try {
+ mService.setNetworkPolicies(policies);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public NetworkPolicy[] getNetworkPolicies() {
+ try {
+ return mService.getNetworkPolicies();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ public void setRestrictBackground(boolean restrictBackground) {
+ try {
+ mService.setRestrictBackground(restrictBackground);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public boolean getRestrictBackground() {
+ try {
+ return mService.getRestrictBackground();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
/**
* Compute the last cycle boundary for the given {@link NetworkPolicy}. For
* example, if cycle day is 20th, and today is June 15th, it will return May
@@ -131,6 +145,10 @@ public class NetworkPolicyManager {
* @hide
*/
public static long computeLastCycleBoundary(long currentTime, NetworkPolicy policy) {
+ if (policy.cycleDay == CYCLE_NONE) {
+ throw new IllegalArgumentException("Unable to compute boundary without cycleDay");
+ }
+
final Time now = new Time(policy.cycleTimezone);
now.set(currentTime);
@@ -157,6 +175,10 @@ public class NetworkPolicyManager {
/** {@hide} */
public static long computeNextCycleBoundary(long currentTime, NetworkPolicy policy) {
+ if (policy.cycleDay == CYCLE_NONE) {
+ throw new IllegalArgumentException("Unable to compute boundary without cycleDay");
+ }
+
final Time now = new Time(policy.cycleTimezone);
now.set(currentTime);
diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java
index 6535256..1725ed7 100644
--- a/core/java/android/net/NetworkQuotaInfo.java
+++ b/core/java/android/net/NetworkQuotaInfo.java
@@ -57,12 +57,12 @@ public class NetworkQuotaInfo implements Parcelable {
return mHardLimitBytes;
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeLong(mEstimatedBytes);
out.writeLong(mSoftLimitBytes);
@@ -70,10 +70,12 @@ public class NetworkQuotaInfo implements Parcelable {
}
public static final Creator<NetworkQuotaInfo> CREATOR = new Creator<NetworkQuotaInfo>() {
+ @Override
public NetworkQuotaInfo createFromParcel(Parcel in) {
return new NetworkQuotaInfo(in);
}
+ @Override
public NetworkQuotaInfo[] newArray(int size) {
return new NetworkQuotaInfo[size];
}
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 704111b..2fc69ad 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -52,12 +52,12 @@ public class NetworkState implements Parcelable {
subscriberId = in.readString();
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(networkInfo, flags);
out.writeParcelable(linkProperties, flags);
@@ -66,10 +66,12 @@ public class NetworkState implements Parcelable {
}
public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() {
+ @Override
public NetworkState createFromParcel(Parcel in) {
return new NetworkState(in);
}
+ @Override
public NetworkState[] newArray(int size) {
return new NetworkState[size];
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 7a1ef66..844d055 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -155,7 +155,7 @@ public class NetworkStats implements Parcelable {
operations = parcel.createLongArray();
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(elapsedRealtime);
dest.writeInt(size);
@@ -352,10 +352,9 @@ public class NetworkStats implements Parcelable {
* on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
* since operation counts are at data layer.
*/
- @Deprecated
public void spliceOperationsFrom(NetworkStats stats) {
for (int i = 0; i < size; i++) {
- final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
+ final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]);
if (j == -1) {
operations[i] = 0;
} else {
@@ -663,16 +662,18 @@ public class NetworkStats implements Parcelable {
return writer.toString();
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
public static final Creator<NetworkStats> CREATOR = new Creator<NetworkStats>() {
+ @Override
public NetworkStats createFromParcel(Parcel in) {
return new NetworkStats(in);
}
+ @Override
public NetworkStats[] newArray(int size) {
return new NetworkStats[size];
}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index faf8a3f..0003c6e 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -130,7 +130,7 @@ public class NetworkStatsHistory implements Parcelable {
totalBytes = in.readLong();
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeLong(bucketDuration);
writeLongArray(out, bucketStart, bucketCount);
@@ -191,7 +191,7 @@ public class NetworkStatsHistory implements Parcelable {
writeVarLongArray(out, operations, bucketCount);
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
@@ -586,10 +586,12 @@ public class NetworkStatsHistory implements Parcelable {
}
public static final Creator<NetworkStatsHistory> CREATOR = new Creator<NetworkStatsHistory>() {
+ @Override
public NetworkStatsHistory createFromParcel(Parcel in) {
return new NetworkStatsHistory(in);
}
+ @Override
public NetworkStatsHistory[] newArray(int size) {
return new NetworkStatsHistory[size];
}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index e1fbdcc..50432a1 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -43,15 +43,10 @@ import com.android.internal.util.Objects;
*/
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;
/**
@@ -65,37 +60,50 @@ public class NetworkTemplate implements Parcelable {
}
/**
- * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
- * networks together. Only uses statistics for requested IMSI.
+ * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
+ * the given IMSI.
*/
public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId);
+ return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null);
}
/**
- * 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.
+ * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
+ * the given IMSI that roughly meet a "3G" definition, or lower.
*/
+ @Deprecated
public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId);
+ return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null);
}
/**
- * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style
- * networks together that meet a "4G" definition. Only uses statistics for
- * requested IMSI.
+ * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
+ * the given IMSI that roughly meet a "4G" definition.
*/
+ @Deprecated
public static NetworkTemplate buildTemplateMobile4g(String subscriberId) {
- return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId);
+ return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null);
}
/**
- * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style
- * networks together.
+ * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
+ * regardless of SSID.
*/
+ public static NetworkTemplate buildTemplateWifiWildcard() {
+ return new NetworkTemplate(MATCH_WIFI, null, null);
+ }
+
+ @Deprecated
public static NetworkTemplate buildTemplateWifi() {
- return new NetworkTemplate(MATCH_WIFI, null);
+ return buildTemplateWifiWildcard();
+ }
+
+ /**
+ * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
+ * given SSID.
+ */
+ public static NetworkTemplate buildTemplateWifi(String networkId) {
+ return new NetworkTemplate(MATCH_WIFI, null, networkId);
}
/**
@@ -103,44 +111,53 @@ public class NetworkTemplate implements Parcelable {
* networks together.
*/
public static NetworkTemplate buildTemplateEthernet() {
- return new NetworkTemplate(MATCH_ETHERNET, null);
+ return new NetworkTemplate(MATCH_ETHERNET, null, null);
}
private final int mMatchRule;
private final String mSubscriberId;
+ private final String mNetworkId;
- /** {@hide} */
- public NetworkTemplate(int matchRule, String subscriberId) {
- this.mMatchRule = matchRule;
- this.mSubscriberId = subscriberId;
+ public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
+ mMatchRule = matchRule;
+ mSubscriberId = subscriberId;
+ mNetworkId = networkId;
}
private NetworkTemplate(Parcel in) {
mMatchRule = in.readInt();
mSubscriberId = in.readString();
+ mNetworkId = in.readString();
}
- /** {@inheritDoc} */
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mMatchRule);
dest.writeString(mSubscriberId);
+ dest.writeString(mNetworkId);
}
- /** {@inheritDoc} */
+ @Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
- final String scrubSubscriberId = scrubSubscriberId(mSubscriberId);
- return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId="
- + scrubSubscriberId;
+ final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
+ builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
+ if (mSubscriberId != null) {
+ builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
+ }
+ if (mNetworkId != null) {
+ builder.append(", networkId=").append(mNetworkId);
+ }
+ return builder.toString();
}
@Override
public int hashCode() {
- return Objects.hashCode(mMatchRule, mSubscriberId);
+ return Objects.hashCode(mMatchRule, mSubscriberId, mNetworkId);
}
@Override
@@ -148,21 +165,24 @@ public class NetworkTemplate implements Parcelable {
if (obj instanceof NetworkTemplate) {
final NetworkTemplate other = (NetworkTemplate) obj;
return mMatchRule == other.mMatchRule
- && Objects.equal(mSubscriberId, other.mSubscriberId);
+ && Objects.equal(mSubscriberId, other.mSubscriberId)
+ && Objects.equal(mNetworkId, other.mNetworkId);
}
return false;
}
- /** {@hide} */
public int getMatchRule() {
return mMatchRule;
}
- /** {@hide} */
public String getSubscriberId() {
return mSubscriberId;
}
+ public String getNetworkId() {
+ return mNetworkId;
+ }
+
/**
* Test if given {@link NetworkIdentity} matches this template.
*/
@@ -237,8 +257,13 @@ public class NetworkTemplate implements Parcelable {
private boolean matchesWifi(NetworkIdentity ident) {
switch (ident.mType) {
case TYPE_WIFI:
+ if (mNetworkId == null) {
+ return true;
+ } else {
+ return Objects.equal(mNetworkId, ident.mNetworkId);
+ }
case TYPE_WIFI_P2P:
- return true;
+ return mNetworkId == null;
default:
return false;
}
@@ -279,10 +304,12 @@ public class NetworkTemplate implements Parcelable {
}
public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
+ @Override
public NetworkTemplate createFromParcel(Parcel in) {
return new NetworkTemplate(in);
}
+ @Override
public NetworkTemplate[] newArray(int size) {
return new NetworkTemplate[size];
}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 973fac1..ee3e165 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -238,6 +238,19 @@ public class TrafficStats {
}
}
+ /** {@hide} */
+ public static void closeQuietly(INetworkStatsSession session) {
+ // TODO: move to NetworkStatsService once it exists
+ if (session != null) {
+ try {
+ session.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
/**
* Get the total number of packets transmitted through the mobile interface.
*
diff --git a/core/java/android/net/nsd/DnsSdServiceInfo.java b/core/java/android/net/nsd/DnsSdServiceInfo.java
new file mode 100644
index 0000000..47d6ec6
--- /dev/null
+++ b/core/java/android/net/nsd/DnsSdServiceInfo.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2012 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.nsd;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * Defines a service based on DNS service discovery
+ * {@hide}
+ */
+public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable {
+
+ private String mServiceName;
+
+ private String mRegistrationType;
+
+ private DnsSdTxtRecord mTxtRecord;
+
+ private String mHostname;
+
+ private int mPort;
+
+ DnsSdServiceInfo() {
+ }
+
+ DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) {
+ mServiceName = sn;
+ mRegistrationType = rt;
+ mTxtRecord = tr;
+ }
+
+ @Override
+ /** @hide */
+ public String getServiceName() {
+ return mServiceName;
+ }
+
+ @Override
+ /** @hide */
+ public void setServiceName(String s) {
+ mServiceName = s;
+ }
+
+ @Override
+ /** @hide */
+ public String getServiceType() {
+ return mRegistrationType;
+ }
+
+ @Override
+ /** @hide */
+ public void setServiceType(String s) {
+ mRegistrationType = s;
+ }
+
+ public DnsSdTxtRecord getTxtRecord() {
+ return mTxtRecord;
+ }
+
+ public void setTxtRecord(DnsSdTxtRecord t) {
+ mTxtRecord = new DnsSdTxtRecord(t);
+ }
+
+ public String getHostName() {
+ return mHostname;
+ }
+
+ public void setHostName(String s) {
+ mHostname = s;
+ }
+
+ public int getPort() {
+ return mPort;
+ }
+
+ public void setPort(int p) {
+ mPort = p;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("name: ").append(mServiceName).
+ append("type: ").append(mRegistrationType).
+ append("txtRecord: ").append(mTxtRecord);
+ return sb.toString();
+ }
+
+ /** Implement the Parcelable interface */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mServiceName);
+ dest.writeString(mRegistrationType);
+ dest.writeParcelable(mTxtRecord, flags);
+ dest.writeString(mHostname);
+ dest.writeInt(mPort);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Creator<DnsSdServiceInfo> CREATOR =
+ new Creator<DnsSdServiceInfo>() {
+ public DnsSdServiceInfo createFromParcel(Parcel in) {
+ DnsSdServiceInfo info = new DnsSdServiceInfo();
+ info.mServiceName = in.readString();
+ info.mRegistrationType = in.readString();
+ info.mTxtRecord = in.readParcelable(null);
+ info.mHostname = in.readString();
+ info.mPort = in.readInt();
+ return info;
+ }
+
+ public DnsSdServiceInfo[] newArray(int size) {
+ return new DnsSdServiceInfo[size];
+ }
+ };
+
+}
diff --git a/core/java/android/net/nsd/DnsSdTxtRecord.java b/core/java/android/net/nsd/DnsSdTxtRecord.java
new file mode 100644
index 0000000..6d4342c
--- /dev/null
+++ b/core/java/android/net/nsd/DnsSdTxtRecord.java
@@ -0,0 +1,305 @@
+/* -*- Mode: Java; tab-width: 4 -*-
+ *
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * 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.
+
+ To do:
+ - implement remove()
+ - fix set() to replace existing values
+ */
+
+package android.net.nsd;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/**
+ * This class handles TXT record data for DNS based service discovery as specified at
+ * http://tools.ietf.org/html/draft-cheshire-dnsext-dns-sd-11
+ *
+ * DNS-SD specifies that a TXT record corresponding to an SRV record consist of
+ * a packed array of bytes, each preceded by a length byte. Each string
+ * is an attribute-value pair.
+ *
+ * The DnsSdTxtRecord object stores the entire TXT data as a single byte array, traversing it
+ * as need be to implement its various methods.
+ *
+ * @hide
+ */
+public class DnsSdTxtRecord implements Parcelable {
+ private static final byte mSeperator = '=';
+
+ private byte[] mData;
+
+ /** Constructs a new, empty TXT record. */
+ public DnsSdTxtRecord() {
+ mData = new byte[0];
+ }
+
+ /** Constructs a new TXT record from a byte array in the standard format. */
+ public DnsSdTxtRecord(byte[] data) {
+ mData = (byte[]) data.clone();
+ }
+
+ /** Copy constructor */
+ public DnsSdTxtRecord(DnsSdTxtRecord src) {
+ if (src != null && src.mData != null) {
+ mData = (byte[]) src.mData.clone();
+ }
+ }
+
+ /**
+ * Set a key/value pair. Setting an existing key will replace its value.
+ * @param key Must be ascii with no '='
+ * @param value matching value to key
+ */
+ public void set(String key, String value) {
+ byte[] keyBytes;
+ byte[] valBytes;
+ int valLen;
+
+ if (value != null) {
+ valBytes = value.getBytes();
+ valLen = valBytes.length;
+ } else {
+ valBytes = null;
+ valLen = 0;
+ }
+
+ try {
+ keyBytes = key.getBytes("US-ASCII");
+ }
+ catch (java.io.UnsupportedEncodingException e) {
+ throw new IllegalArgumentException("key should be US-ASCII");
+ }
+
+ for (int i = 0; i < keyBytes.length; i++) {
+ if (keyBytes[i] == '=') {
+ throw new IllegalArgumentException("= is not a valid character in key");
+ }
+ }
+
+ if (keyBytes.length + valLen >= 255) {
+ throw new IllegalArgumentException("Key and Value length cannot exceed 255 bytes");
+ }
+
+ int currentLoc = remove(key);
+ if (currentLoc == -1)
+ currentLoc = keyCount();
+
+ insert(keyBytes, valBytes, currentLoc);
+ }
+
+ /**
+ * Get a value for a key
+ *
+ * @param key
+ * @return The value associated with the key
+ */
+ public String get(String key) {
+ byte[] val = this.getValue(key);
+ return val != null ? new String(val) : null;
+ }
+
+ /** Remove a key/value pair. If found, returns the index or -1 if not found */
+ public int remove(String key) {
+ int avStart = 0;
+
+ for (int i=0; avStart < mData.length; i++) {
+ int avLen = mData[avStart];
+ if (key.length() <= avLen &&
+ (key.length() == avLen || mData[avStart + key.length() + 1] == mSeperator)) {
+ String s = new String(mData, avStart + 1, key.length());
+ if (0 == key.compareToIgnoreCase(s)) {
+ byte[] oldBytes = mData;
+ mData = new byte[oldBytes.length - avLen - 1];
+ System.arraycopy(oldBytes, 0, mData, 0, avStart);
+ System.arraycopy(oldBytes, avStart + avLen + 1, mData, avStart,
+ oldBytes.length - avStart - avLen - 1);
+ return i;
+ }
+ }
+ avStart += (0xFF & (avLen + 1));
+ }
+ return -1;
+ }
+
+ /** Return the count of keys */
+ public int keyCount() {
+ int count = 0, nextKey;
+ for (nextKey = 0; nextKey < mData.length; count++) {
+ nextKey += (0xFF & (mData[nextKey] + 1));
+ }
+ return count;
+ }
+
+ /** Return true if key is present, false if not. */
+ public boolean contains(String key) {
+ String s = null;
+ for (int i = 0; null != (s = this.getKey(i)); i++) {
+ if (0 == key.compareToIgnoreCase(s)) return true;
+ }
+ return false;
+ }
+
+ /* Gets the size in bytes */
+ public int size() {
+ return mData.length;
+ }
+
+ /* Gets the raw data in bytes */
+ public byte[] getRawData() {
+ return mData;
+ }
+
+ private void insert(byte[] keyBytes, byte[] value, int index) {
+ byte[] oldBytes = mData;
+ int valLen = (value != null) ? value.length : 0;
+ int insertion = 0;
+ int newLen, avLen;
+
+ for (int i = 0; i < index && insertion < mData.length; i++) {
+ insertion += (0xFF & (mData[insertion] + 1));
+ }
+
+ avLen = keyBytes.length + valLen + (value != null ? 1 : 0);
+ newLen = avLen + oldBytes.length + 1;
+
+ mData = new byte[newLen];
+ System.arraycopy(oldBytes, 0, mData, 0, insertion);
+ int secondHalfLen = oldBytes.length - insertion;
+ System.arraycopy(oldBytes, insertion, mData, newLen - secondHalfLen, secondHalfLen);
+ mData[insertion] = (byte) avLen;
+ System.arraycopy(keyBytes, 0, mData, insertion + 1, keyBytes.length);
+ if (value != null) {
+ mData[insertion + 1 + keyBytes.length] = mSeperator;
+ System.arraycopy(value, 0, mData, insertion + keyBytes.length + 2, valLen);
+ }
+ }
+
+ /** Return a key in the TXT record by zero-based index. Returns null if index exceeds the total number of keys. */
+ private String getKey(int index) {
+ int avStart = 0;
+
+ for (int i=0; i < index && avStart < mData.length; i++) {
+ avStart += mData[avStart] + 1;
+ }
+
+ if (avStart < mData.length) {
+ int avLen = mData[avStart];
+ int aLen = 0;
+
+ for (aLen=0; aLen < avLen; aLen++) {
+ if (mData[avStart + aLen + 1] == mSeperator) break;
+ }
+ return new String(mData, avStart + 1, aLen);
+ }
+ return null;
+ }
+
+ /**
+ * Look up a key in the TXT record by zero-based index and return its value.
+ * Returns null if index exceeds the total number of keys.
+ * Returns null if the key is present with no value.
+ */
+ private byte[] getValue(int index) {
+ int avStart = 0;
+ byte[] value = null;
+
+ for (int i=0; i < index && avStart < mData.length; i++) {
+ avStart += mData[avStart] + 1;
+ }
+
+ if (avStart < mData.length) {
+ int avLen = mData[avStart];
+ int aLen = 0;
+
+ for (aLen=0; aLen < avLen; aLen++) {
+ if (mData[avStart + aLen + 1] == mSeperator) {
+ value = new byte[avLen - aLen - 1];
+ System.arraycopy(mData, avStart + aLen + 2, value, 0, avLen - aLen - 1);
+ break;
+ }
+ }
+ }
+ return value;
+ }
+
+ private String getValueAsString(int index) {
+ byte[] value = this.getValue(index);
+ return value != null ? new String(value) : null;
+ }
+
+ private byte[] getValue(String forKey) {
+ String s = null;
+ int i;
+
+ for (i = 0; null != (s = this.getKey(i)); i++) {
+ if (0 == forKey.compareToIgnoreCase(s)) {
+ return this.getValue(i);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Return a string representation.
+ * Example : {key1=value1},{key2=value2}..
+ *
+ * For a key say like "key3" with null value
+ * {key1=value1},{key2=value2}{key3}
+ */
+ public String toString() {
+ String a, result = null;
+
+ for (int i = 0; null != (a = this.getKey(i)); i++) {
+ String av = "{" + a;
+ String val = this.getValueAsString(i);
+ if (val != null)
+ av += "=" + val + "}";
+ else
+ av += "}";
+ if (result == null)
+ result = av;
+ else
+ result = result + ", " + av;
+ }
+ return result != null ? result : "";
+ }
+
+ /** Implement the Parcelable interface */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeByteArray(mData);
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Creator<DnsSdTxtRecord> CREATOR =
+ new Creator<DnsSdTxtRecord>() {
+ public DnsSdTxtRecord createFromParcel(Parcel in) {
+ DnsSdTxtRecord info = new DnsSdTxtRecord();
+ in.readByteArray(info.mData);
+ return info;
+ }
+
+ public DnsSdTxtRecord[] newArray(int size) {
+ return new DnsSdTxtRecord[size];
+ }
+ };
+}
diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl
new file mode 100644
index 0000000..077a675
--- /dev/null
+++ b/core/java/android/net/nsd/INsdManager.aidl
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2012, 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.nsd;
+
+import android.os.Messenger;
+
+/**
+ * Interface that NsdService implements
+ *
+ * {@hide}
+ */
+interface INsdManager
+{
+ Messenger getMessenger();
+}
diff --git a/core/java/android/net/nsd/NetworkServiceInfo.java b/core/java/android/net/nsd/NetworkServiceInfo.java
new file mode 100644
index 0000000..34d83d1
--- /dev/null
+++ b/core/java/android/net/nsd/NetworkServiceInfo.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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.nsd;
+
+/**
+ * Interface for a network service.
+ *
+ * {@hide}
+ */
+public interface NetworkServiceInfo {
+
+ String getServiceName();
+ void setServiceName(String s);
+
+ String getServiceType();
+ void setServiceType(String s);
+
+}
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
new file mode 100644
index 0000000..a109a98
--- /dev/null
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2012 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.nsd;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.Messenger;
+import android.util.Log;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+/**
+ * The Network Service Discovery Manager class provides the API for service
+ * discovery. Service discovery enables applications to discover and connect with services
+ * on a network. Example applications include a game application discovering another instance
+ * of the game application or a printer application discovering other printers on a network.
+ *
+ * <p> The API is asynchronous and responses to requests from an application are on listener
+ * callbacks provided by the application. The application needs to do an initialization with
+ * {@link #initialize} before doing any operation.
+ *
+ * <p> Android currently supports DNS based service discovery and it is limited to a local
+ * network with the use of multicast DNS. In future, this class will be
+ * extended to support other service discovery mechanisms.
+ *
+ * Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
+ * Context.getSystemService(Context.NSD_SERVICE)}.
+ * @hide
+ *
+ */
+public class NsdManager {
+ private static final String TAG = "NsdManager";
+ INsdManager mService;
+
+ private static final int BASE = Protocol.BASE_NSD_MANAGER;
+
+ /** @hide */
+ public static final int DISCOVER_SERVICES = BASE + 1;
+ /** @hide */
+ public static final int DISCOVER_SERVICES_STARTED = BASE + 2;
+ /** @hide */
+ public static final int DISCOVER_SERVICES_FAILED = BASE + 3;
+ /** @hide */
+ public static final int SERVICE_FOUND = BASE + 4;
+ /** @hide */
+ public static final int SERVICE_LOST = BASE + 5;
+
+ /** @hide */
+ public static final int STOP_DISCOVERY = BASE + 6;
+ /** @hide */
+ public static final int STOP_DISCOVERY_FAILED = BASE + 7;
+ /** @hide */
+ public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 8;
+
+ /** @hide */
+ public static final int REGISTER_SERVICE = BASE + 9;
+ /** @hide */
+ public static final int REGISTER_SERVICE_FAILED = BASE + 10;
+ /** @hide */
+ public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11;
+
+ /** @hide */
+ public static final int UPDATE_SERVICE = BASE + 12;
+ /** @hide */
+ public static final int UPDATE_SERVICE_FAILED = BASE + 13;
+ /** @hide */
+ public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 14;
+
+ /** @hide */
+ public static final int RESOLVE_SERVICE = BASE + 15;
+ /** @hide */
+ public static final int RESOLVE_SERVICE_FAILED = BASE + 16;
+ /** @hide */
+ public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 17;
+
+ /**
+ * Create a new Nsd instance. Applications use
+ * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
+ * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}.
+ * @param service the Binder interface
+ * @hide - hide this because it takes in a parameter of type INsdManager, which
+ * is a system private class.
+ */
+ public NsdManager(INsdManager service) {
+ mService = service;
+ }
+
+ /**
+ * Indicates that the operation failed due to an internal error.
+ */
+ public static final int ERROR = 0;
+
+ /**
+ * Indicates that the operation failed because service discovery is unsupported on the device.
+ */
+ public static final int UNSUPPORTED = 1;
+
+ /**
+ * Indicates that the operation failed because the framework is busy and
+ * unable to service the request
+ */
+ public static final int BUSY = 2;
+
+ /** Interface for callback invocation when framework channel is connected or lost */
+ public interface ChannelListener {
+ public void onChannelConnected(Channel c);
+ /**
+ * The channel to the framework has been disconnected.
+ * Application could try re-initializing using {@link #initialize}
+ */
+ public void onChannelDisconnected();
+ }
+
+ public interface ActionListener {
+
+ public void onFailure(int errorCode);
+
+ public void onSuccess();
+ }
+
+ public interface DnsSdDiscoveryListener {
+
+ public void onFailure(int errorCode);
+
+ public void onStarted(String registrationType);
+
+ public void onServiceFound(DnsSdServiceInfo serviceInfo);
+
+ public void onServiceLost(DnsSdServiceInfo serviceInfo);
+
+ }
+
+ public interface DnsSdRegisterListener {
+
+ public void onFailure(int errorCode);
+
+ public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo);
+ }
+
+ public interface DnsSdUpdateRegistrationListener {
+
+ public void onFailure(int errorCode);
+
+ public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord);
+ }
+
+ public interface DnsSdResolveListener {
+
+ public void onFailure(int errorCode);
+
+ public void onServiceResolved(DnsSdServiceInfo serviceInfo);
+ }
+
+ /**
+ * A channel that connects the application to the NetworkService framework.
+ * Most service operations require a Channel as an argument. An instance of Channel is obtained
+ * by doing a call on {@link #initialize}
+ */
+ public static class Channel {
+ Channel(Looper looper, ChannelListener l) {
+ mAsyncChannel = new AsyncChannel();
+ mHandler = new ServiceHandler(looper);
+ mChannelListener = l;
+ }
+ private ChannelListener mChannelListener;
+ private DnsSdDiscoveryListener mDnsSdDiscoveryListener;
+ private ActionListener mDnsSdStopDiscoveryListener;
+ private DnsSdRegisterListener mDnsSdRegisterListener;
+ private DnsSdUpdateRegistrationListener mDnsSdUpdateListener;
+ private DnsSdResolveListener mDnsSdResolveListener;
+
+ AsyncChannel mAsyncChannel;
+ ServiceHandler mHandler;
+ class ServiceHandler extends Handler {
+ ServiceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ break;
+ case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
+ if (mChannelListener != null) {
+ mChannelListener.onChannelConnected(Channel.this);
+ }
+ break;
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ if (mChannelListener != null) {
+ mChannelListener.onChannelDisconnected();
+ mChannelListener = null;
+ }
+ break;
+ case DISCOVER_SERVICES_STARTED:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onStarted((String) message.obj);
+ }
+ break;
+ case DISCOVER_SERVICES_FAILED:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onFailure(message.arg1);
+ }
+ break;
+ case SERVICE_FOUND:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onServiceFound(
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ case SERVICE_LOST:
+ if (mDnsSdDiscoveryListener != null) {
+ mDnsSdDiscoveryListener.onServiceLost(
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ case STOP_DISCOVERY_FAILED:
+ if (mDnsSdStopDiscoveryListener != null) {
+ mDnsSdStopDiscoveryListener.onFailure(message.arg1);
+ }
+ break;
+ case STOP_DISCOVERY_SUCCEEDED:
+ if (mDnsSdStopDiscoveryListener != null) {
+ mDnsSdStopDiscoveryListener.onSuccess();
+ }
+ break;
+ case REGISTER_SERVICE_FAILED:
+ if (mDnsSdRegisterListener != null) {
+ mDnsSdRegisterListener.onFailure(message.arg1);
+ }
+ break;
+ case REGISTER_SERVICE_SUCCEEDED:
+ if (mDnsSdRegisterListener != null) {
+ mDnsSdRegisterListener.onServiceRegistered(message.arg1,
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ case UPDATE_SERVICE_FAILED:
+ if (mDnsSdUpdateListener != null) {
+ mDnsSdUpdateListener.onFailure(message.arg1);
+ }
+ break;
+ case UPDATE_SERVICE_SUCCEEDED:
+ if (mDnsSdUpdateListener != null) {
+ mDnsSdUpdateListener.onServiceUpdated(message.arg1,
+ (DnsSdTxtRecord) message.obj);
+ }
+ break;
+ case RESOLVE_SERVICE_FAILED:
+ if (mDnsSdResolveListener != null) {
+ mDnsSdResolveListener.onFailure(message.arg1);
+ }
+ break;
+ case RESOLVE_SERVICE_SUCCEEDED:
+ if (mDnsSdResolveListener != null) {
+ mDnsSdResolveListener.onServiceResolved(
+ (DnsSdServiceInfo) message.obj);
+ }
+ break;
+ default:
+ Log.d(TAG, "Ignored " + message);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Registers the application with the service discovery framework. This function
+ * must be the first to be called before any other operations are performed. No service
+ * discovery operations must be performed until the ChannelListener callback notifies
+ * that the channel is connected
+ *
+ * @param srcContext is the context of the source
+ * @param srcLooper is the Looper on which the callbacks are receivied
+ * @param listener for callback at loss of framework communication.
+ */
+ public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
+ Messenger messenger = getMessenger();
+ if (messenger == null) throw new RuntimeException("Failed to initialize");
+ if (listener == null) throw new IllegalArgumentException("ChannelListener cannot be null");
+
+ Channel c = new Channel(srcLooper, listener);
+ c.mAsyncChannel.connect(srcContext, c.mHandler, messenger);
+ }
+
+ /**
+ * Set the listener for service discovery. Can be null.
+ */
+ public void setDiscoveryListener(Channel c, DnsSdDiscoveryListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdDiscoveryListener = b;
+ }
+
+ /**
+ * Set the listener for stop service discovery. Can be null.
+ */
+ public void setStopDiscoveryListener(Channel c, ActionListener a) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdStopDiscoveryListener = a;
+ }
+
+ /**
+ * Set the listener for service registration. Can be null.
+ */
+ public void setRegisterListener(Channel c, DnsSdRegisterListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdRegisterListener = b;
+ }
+
+ /**
+ * Set the listener for service registration. Can be null.
+ */
+ public void setUpdateRegistrationListener(Channel c, DnsSdUpdateRegistrationListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdUpdateListener = b;
+ }
+
+ /**
+ * Set the listener for service resolution. Can be null.
+ */
+ public void setResolveListener(Channel c, DnsSdResolveListener b) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mDnsSdResolveListener = b;
+ }
+
+ public void registerService(Channel c, DnsSdServiceInfo serviceInfo) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
+ c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo);
+ }
+
+ public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord);
+ }
+
+ public void discoverServices(Channel c, String serviceType) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ if (c.mDnsSdDiscoveryListener == null) throw new
+ IllegalStateException("Discovery listener needs to be set first");
+ DnsSdServiceInfo s = new DnsSdServiceInfo();
+ s.setServiceType(serviceType);
+ c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s);
+ }
+
+ public void stopServiceDiscovery(Channel c) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ c.mAsyncChannel.sendMessage(STOP_DISCOVERY);
+ }
+
+ public void resolveService(Channel c, DnsSdServiceInfo serviceInfo) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
+ if (c.mDnsSdResolveListener == null) throw new
+ IllegalStateException("Resolve listener needs to be set first");
+ c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo);
+ }
+
+ /**
+ * Get a reference to NetworkService handler. This is used to establish
+ * an AsyncChannel communication with the service
+ *
+ * @return Messenger pointing to the NetworkService handler
+ */
+ private Messenger getMessenger() {
+ try {
+ return mService.getMessenger();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/nfc/INdefPushCallback.aidl b/core/java/android/nfc/INdefPushCallback.aidl
index e60a5b0..4e79822 100644
--- a/core/java/android/nfc/INdefPushCallback.aidl
+++ b/core/java/android/nfc/INdefPushCallback.aidl
@@ -17,6 +17,7 @@
package android.nfc;
import android.nfc.NdefMessage;
+import android.net.Uri;
/**
* @hide
@@ -24,5 +25,7 @@ import android.nfc.NdefMessage;
interface INdefPushCallback
{
NdefMessage createMessage();
+ Uri getUri();
+ String getMimeType();
void onNdefPushComplete();
}
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index 2223255..3ac1dcc 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -45,4 +45,5 @@ interface INfcTag
void resetTimeouts();
boolean canMakeReadOnly(int ndefType);
int getMaxTransceiveLength(int technology);
+ boolean getExtendedLengthApdusSupported();
}
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 2c73056..f80dae4 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -18,6 +18,7 @@ package android.nfc;
import android.app.Activity;
import android.app.Application;
+import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
@@ -107,10 +108,16 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
NdefMessage ndefMessage = null; // static NDEF message
NfcAdapter.CreateNdefMessageCallback ndefMessageCallback = null;
NfcAdapter.OnNdefPushCompleteCallback onNdefPushCompleteCallback = null;
+ Uri uri = null;
+ String mimeType = null;
public NfcActivityState(Activity activity) {
if (activity.getWindow().isDestroyed()) {
throw new IllegalStateException("activity is already destroyed");
}
+ // Check if activity is resumed right now, as we will not
+ // immediately get a callback for that.
+ resumed = activity.isResumed();
+
this.activity = activity;
registerApplication(activity.getApplication());
}
@@ -121,12 +128,14 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
ndefMessage = null;
ndefMessageCallback = null;
onNdefPushCompleteCallback = null;
+ uri = null;
+ mimeType = null;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder("[").append(" ");
s.append(ndefMessage).append(" ").append(ndefMessageCallback).append(" ");
- s.append(onNdefPushCompleteCallback).append("]");
+ s.append(onNdefPushCompleteCallback).append(" ").append(uri).append("]");
return s.toString();
}
}
@@ -175,6 +184,19 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
mDefaultEvent = new NfcEvent(mAdapter);
}
+ public void setNdefPushContentUri(Activity activity, String mimeType, Uri uri) {
+ boolean isResumed;
+ synchronized (NfcActivityManager.this) {
+ NfcActivityState state = getActivityState(activity);
+ state.uri = uri;
+ state.mimeType = mimeType;
+ isResumed = state.resumed;
+ }
+ if (isResumed) {
+ requestNfcServiceCallback(true);
+ }
+ }
+
public void setNdefPushMessage(Activity activity, NdefMessage message) {
boolean isResumed;
synchronized (NfcActivityManager.this) {
@@ -249,6 +271,26 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
/** Callback from NFC service, usually on binder thread */
@Override
+ public Uri getUri() {
+ synchronized (NfcActivityManager.this) {
+ NfcActivityState state = findResumedActivityState();
+ if (state == null) return null;
+
+ return state.uri;
+ }
+ }
+ /** Callback from NFC service, usually on binder thread */
+ @Override
+ public String getMimeType() {
+ synchronized (NfcActivityManager.this) {
+ NfcActivityState state = findResumedActivityState();
+ if (state == null) return null;
+
+ return state.mimeType;
+ }
+ }
+ /** Callback from NFC service, usually on binder thread */
+ @Override
public void onNdefPushComplete() {
NfcAdapter.OnNdefPushCompleteCallback callback;
synchronized (NfcActivityManager.this) {
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index b7a7bd5..917751c 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.net.Uri;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.Ndef;
import android.nfc.tech.NfcA;
@@ -555,6 +556,18 @@ public final class NfcAdapter {
}
}
+ //TODO: Consider a callback alternative
+ //TOOD: See if we get rid of mimeType
+ //TODO: make sure NFC service has permission for URI
+ //TODO: javadoc
+ /** @hide */
+ public void setBeamPushUri(String mimeType, Uri uri, Activity activity) {
+ if (activity == null) {
+ throw new NullPointerException("activity cannot be null");
+ }
+ mNfcActivityManager.setNdefPushContentUri(activity, mimeType, uri);
+ }
+
/**
* Set a static {@link NdefMessage} to send using Android Beam (TM).
*
@@ -580,7 +593,18 @@ public final class NfcAdapter {
* and/or {@link #setNdefPushMessageCallback} is called with a null callback,
* then NDEF push will be completely disabled for the specified activity(s).
* This also disables any default NDEF message the Android OS would have
- * otherwise sent on your behalf.
+ * otherwise sent on your behalf for those activity(s).
+ *
+ * <p>If you want to prevent the Android OS from sending default NDEF
+ * messages completely (for all activities), you can include a
+ * <code><meta-data></code> element inside the <code><application></code>
+ * element of your AndroidManifest.xml file, like this:
+ * <pre>{@code
+ * <application ...>
+ * <meta-data android:name="android.nfc.disable_beam_default"
+ * android:value="true" />
+ * </application>
+ * }</pre>
*
* <p>The API allows for multiple activities to be specified at a time,
* but it is strongly recommended to just register one at a time,
@@ -664,7 +688,18 @@ public final class NfcAdapter {
* and/or {@link #setNdefPushMessageCallback} is called with a null callback,
* then NDEF push will be completely disabled for the specified activity(s).
* This also disables any default NDEF message the Android OS would have
- * otherwise sent on your behalf.
+ * otherwise sent on your behalf for those activity(s).
+ *
+ * <p>If you want to prevent the Android OS from sending default NDEF
+ * messages completely (for all activities), you can include a
+ * <code><meta-data></code> element inside the <code><application></code>
+ * element of your AndroidManifest.xml file, like this:
+ * <pre>{@code
+ * <application ...>
+ * <meta-data android:name="android.nfc.disable_beam_default"
+ * android:value="true" />
+ * </application>
+ * }</pre>
*
* <p>The API allows for multiple activities to be specified at a time,
* but it is strongly recommended to just register one at a time,
diff --git a/core/java/android/nfc/tech/IsoDep.java b/core/java/android/nfc/tech/IsoDep.java
index 1859877..089b159 100644
--- a/core/java/android/nfc/tech/IsoDep.java
+++ b/core/java/android/nfc/tech/IsoDep.java
@@ -179,4 +179,27 @@ public final class IsoDep extends BasicTagTechnology {
public int getMaxTransceiveLength() {
return getMaxTransceiveLengthInternal();
}
+
+ /**
+ * <p>Standard APDUs have a 1-byte length field, allowing a maximum of
+ * 255 payload bytes, which results in a maximum APDU length of 261 bytes.
+ *
+ * <p>Extended length APDUs have a 3-byte length field, allowing 65535
+ * payload bytes.
+ *
+ * <p>Some NFC adapters, like the one used in the Nexus S and the Galaxy Nexus
+ * do not support extended length APDUs. They are expected to be well-supported
+ * in the future though. Use this method to check for extended length APDU
+ * support.
+ *
+ * @return whether the NFC adapter on this device supports extended length APDUs.
+ */
+ public boolean isExtendedLengthApduSupported() {
+ try {
+ return mTag.getTagService().getExtendedLengthApdusSupported();
+ } catch (RemoteException e) {
+ Log.e(TAG, "NFC service dead", e);
+ return false;
+ }
+ }
}
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java
index 9d1e6a1..8c92288 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/core/java/android/nfc/tech/MifareClassic.java
@@ -150,6 +150,7 @@ public final class MifareClassic extends BasicTagTechnology {
mIsEmulated = false;
switch (a.getSak()) {
+ case 0x01:
case 0x08:
mType = TYPE_CLASSIC;
mSize = SIZE_1K;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 74a376d..8df4339 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -497,27 +497,30 @@ public class Preference implements Comparable<Preference>, OnDependencyChangeLis
* @see #onCreateView(ViewGroup)
*/
protected void onBindView(View view) {
- TextView textView = (TextView) view.findViewById(com.android.internal.R.id.title);
- if (textView != null) {
- textView.setText(getTitle());
+ final TextView titleView = (TextView) view.findViewById(
+ com.android.internal.R.id.title);
+ if (titleView != null) {
+ final CharSequence title = getTitle();
+ if (!TextUtils.isEmpty(title)) {
+ titleView.setText(title);
+ titleView.setVisibility(View.VISIBLE);
+ } else {
+ titleView.setVisibility(View.GONE);
+ }
}
-
- textView = (TextView) view.findViewById(com.android.internal.R.id.summary);
- if (textView != null) {
+
+ final TextView summaryView = (TextView) view.findViewById(
+ com.android.internal.R.id.summary);
+ if (summaryView != null) {
final CharSequence summary = getSummary();
if (!TextUtils.isEmpty(summary)) {
- if (textView.getVisibility() != View.VISIBLE) {
- textView.setVisibility(View.VISIBLE);
- }
-
- textView.setText(getSummary());
+ summaryView.setText(summary);
+ summaryView.setVisibility(View.VISIBLE);
} else {
- if (textView.getVisibility() != View.GONE) {
- textView.setVisibility(View.GONE);
- }
+ summaryView.setVisibility(View.GONE);
}
}
-
+
ImageView imageView = (ImageView) view.findViewById(com.android.internal.R.id.icon);
if (imageView != null) {
if (mIconResId != 0 || mIcon != null) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d724d56..0e9306b 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4531,8 +4531,6 @@ public final class ContactsContract {
/**
* The phone number's E164 representation.
* <P>Type: TEXT</P>
- *
- * @hide
*/
public static final String NORMALIZED_NUMBER = "normalized_number";
}
@@ -5408,10 +5406,10 @@ public final class ContactsContract {
public static final String NUMBER = DATA;
/**
- * The phone number's E164 representation.
+ * The phone number's E164 representation. This value can be omitted in which
+ * case the provider will try to automatically infer it. If present, {@link #NUMBER}
+ * has to be set as well (it will be ignored otherwise).
* <P>Type: TEXT</P>
- *
- * @hide
*/
public static final String NORMALIZED_NUMBER = DATA4;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d74ccb8..2aaf548 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -36,14 +36,20 @@ import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.os.UserId;
import android.speech.tts.TextToSpeech;
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.Log;
import android.view.WindowOrientationListener;
+import com.android.internal.widget.ILockSettings;
+
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
@@ -1506,13 +1512,22 @@ public final class Settings {
public static final String VOLUME_MASTER = "volume_master";
/**
- * Whether the notifications should use the ring volume (value of 1) or a separate
- * notification volume (value of 0). In most cases, users will have this enabled so the
- * notification and ringer volumes will be the same. However, power users can disable this
- * and use the separate notification volume control.
+ * Master volume mute (int 1 = mute, 0 = not muted).
+ *
+ * @hide
+ */
+ public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
+
+ /**
+ * Whether the notifications should use the ring volume (value of 1) or
+ * a separate notification volume (value of 0). In most cases, users
+ * will have this enabled so the notification and ringer volumes will be
+ * the same. However, power users can disable this and use the separate
+ * notification volume control.
* <p>
- * Note: This is a one-off setting that will be removed in the future when there is profile
- * support. For this reason, it is kept hidden from the public APIs.
+ * Note: This is a one-off setting that will be removed in the future
+ * when there is profile support. For this reason, it is kept hidden
+ * from the public APIs.
*
* @hide
* @deprecated
@@ -2244,6 +2259,17 @@ public final class Settings {
// Populated lazily, guarded by class object:
private static NameValueCache sNameValueCache = null;
+ private static ILockSettings sLockSettings = null;
+
+ private static boolean sIsSystemProcess;
+ private static final HashSet<String> MOVED_TO_LOCK_SETTINGS;
+ static {
+ MOVED_TO_LOCK_SETTINGS = new HashSet<String>(3);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE);
+ MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED);
+ }
+
/**
* Look up a name in the database.
* @param resolver to access the database with
@@ -2255,6 +2281,21 @@ public final class Settings {
sNameValueCache = new NameValueCache(SYS_PROP_SETTING_VERSION, CONTENT_URI,
CALL_METHOD_GET_SECURE);
}
+
+ if (sLockSettings == null) {
+ sLockSettings = ILockSettings.Stub.asInterface(
+ (IBinder) ServiceManager.getService("lock_settings"));
+ sIsSystemProcess = Process.myUid() == Process.SYSTEM_UID;
+ }
+ if (sLockSettings != null && !sIsSystemProcess
+ && MOVED_TO_LOCK_SETTINGS.contains(name)) {
+ try {
+ return sLockSettings.getString(name, "0", UserId.getCallingUserId());
+ } catch (RemoteException re) {
+ // Fall through
+ }
+ }
+
return sNameValueCache.getString(resolver, name);
}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index f7a7eb8..ae9042c 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -125,28 +125,24 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
}
private void resizeFor(int size) {
- int newlen = ArrayUtils.idealCharArraySize(size + 1);
- char[] newtext = new char[newlen];
+ final int oldLength = mText.length;
+ final int newLength = ArrayUtils.idealCharArraySize(size + 1);
+ final int after = oldLength - (mGapStart + mGapLength);
- int after = mText.length - (mGapStart + mGapLength);
+ char[] newText = new char[newLength];
+ System.arraycopy(mText, 0, newText, 0, mGapStart);
+ System.arraycopy(mText, oldLength - after, newText, newLength - after, after);
+ mText = newText;
- System.arraycopy(mText, 0, newtext, 0, mGapStart);
- System.arraycopy(mText, mText.length - after,
- newtext, newlen - after, after);
+ final int delta = newLength - oldLength;
+ mGapLength += delta;
+ if (mGapLength < 1)
+ new Exception("mGapLength < 1").printStackTrace();
for (int i = 0; i < mSpanCount; i++) {
- if (mSpanStarts[i] > mGapStart)
- mSpanStarts[i] += newlen - mText.length;
- if (mSpanEnds[i] > mGapStart)
- mSpanEnds[i] += newlen - mText.length;
+ if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
+ if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
}
-
- int oldlen = mText.length;
- mText = newtext;
- mGapLength += mText.length - oldlen;
-
- if (mGapLength < 1)
- new Exception("mGapLength < 1").printStackTrace();
}
private void moveGapTo(int where) {
@@ -157,14 +153,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
if (where < mGapStart) {
int overlap = mGapStart - where;
-
- System.arraycopy(mText, where,
- mText, mGapStart + mGapLength - overlap, overlap);
+ System.arraycopy(mText, where, mText, mGapStart + mGapLength - overlap, overlap);
} else /* where > mGapStart */ {
int overlap = where - mGapStart;
-
- System.arraycopy(mText, where + mGapLength - overlap,
- mText, mGapStart, overlap);
+ System.arraycopy(mText, where + mGapLength - overlap, mText, mGapStart, overlap);
}
// XXX be more clever
@@ -340,18 +332,17 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
boolean atEnd = (mGapStart + mGapLength == mText.length);
for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpanStarts[i] >= start &&
- mSpanStarts[i] < mGapStart + mGapLength) {
+ if (mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength) {
int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
- if (flag == POINT || (flag == PARAGRAPH && atEnd))
- mSpanStarts[i] = mGapStart + mGapLength;
- else
- mSpanStarts[i] = start;
+ if (flag == POINT || (flag == PARAGRAPH && atEnd)) {
+ mSpanStarts[i] = mGapStart + mGapLength;
+ } else {
+ mSpanStarts[i] = start;
+ }
}
- if (mSpanEnds[i] >= start &&
- mSpanEnds[i] < mGapStart + mGapLength) {
+ if (mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength) {
int flag = (mSpanFlags[i] & END_MASK);
if (flag == POINT || (flag == PARAGRAPH && atEnd))
@@ -360,7 +351,8 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanEnds[i] = start;
}
- // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE
+ // remove 0-length SPAN_EXCLUSIVE_EXCLUSIVE, which are POINT_MARK and could
+ // get their boundaries swapped by the above code
if (mSpanEnds[i] < mSpanStarts[i]) {
removeSpan(i);
}
@@ -520,6 +512,11 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
}
}
+ if (flags == Spanned.SPAN_EXCLUSIVE_EXCLUSIVE && start == end) {
+ throw new IllegalArgumentException(
+ "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+ }
+
if (start > mGapStart) {
start += mGapLength;
} else if (start == mGapStart) {
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
index cbb908b..16a13cf 100644
--- a/core/java/android/view/GLES20TextureLayer.java
+++ b/core/java/android/view/GLES20TextureLayer.java
@@ -42,6 +42,12 @@ class GLES20TextureLayer extends GLES20Layer {
}
}
+ GLES20TextureLayer(SurfaceTexture surface, boolean isOpaque) {
+ this(isOpaque);
+ mSurface = surface;
+ mSurface.attachToGLContext(mTexture);
+ }
+
@Override
boolean isValid() {
return mLayer != 0 && mTexture != 0;
@@ -72,6 +78,14 @@ class GLES20TextureLayer extends GLES20Layer {
return mSurface;
}
+ void setSurfaceTexture(SurfaceTexture surfaceTexture) {
+ if (mSurface != null) {
+ mSurface.release();
+ }
+ mSurface = surfaceTexture;
+ mSurface.attachToGLContext(mTexture);
+ }
+
@Override
void update(int width, int height, boolean isOpaque) {
super.update(width, height, isOpaque);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 9ef2621..b0399fd 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -87,7 +87,7 @@ public abstract class HardwareRenderer {
/**
* System property used to enable or disable hardware rendering profiling.
* The default value of this property is assumed to be false.
- *
+ *
* When profiling is enabled, the adb shell dumpsys gfxinfo command will
* output extra information about the time taken to execute by the last
* frames.
@@ -99,6 +99,20 @@ public abstract class HardwareRenderer {
static final String PROFILE_PROPERTY = "hwui.profile";
/**
+ * System property used to specify the number of frames to be used
+ * when doing hardware rendering profiling.
+ * The default value of this property is #PROFILE_MAX_FRAMES.
+ *
+ * When profiling is enabled, the adb shell dumpsys gfxinfo command will
+ * output extra information about the time taken to execute by the last
+ * frames.
+ *
+ * Possible values:
+ * "60", to set the limit of frames to 60
+ */
+ static final String PROFILE_MAXFRAMES_PROPERTY = "hwui.profile.maxframes";
+
+ /**
* System property used to debug EGL configuration choice.
*
* Possible values:
@@ -134,7 +148,7 @@ public abstract class HardwareRenderer {
/**
* Number of frames to profile.
*/
- private static final int PROFILE_MAX_FRAMES = 120;
+ private static final int PROFILE_MAX_FRAMES = 64;
/**
* Number of floats per profiled frame.
@@ -377,9 +391,9 @@ public abstract class HardwareRenderer {
* @param isOpaque Whether the layer should be opaque or not
*
* @return A hardware layer
- */
+ */
abstract HardwareLayer createHardwareLayer(boolean isOpaque);
-
+
/**
* Creates a new hardware layer.
*
@@ -403,6 +417,15 @@ public abstract class HardwareRenderer {
abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
/**
+ * Sets the {@link android.graphics.SurfaceTexture} that will be used to
+ * render into the specified hardware layer.
+ *
+ * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
+ * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
+ */
+ abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
+
+ /**
* Initializes the hardware renderer for the specified surface and setup the
* renderer for drawing, if needed. This is invoked when the ViewAncestor has
* potentially lost the hardware renderer. The hardware renderer should be
@@ -503,7 +526,7 @@ public abstract class HardwareRenderer {
static final int SURFACE_STATE_SUCCESS = 1;
static final int SURFACE_STATE_UPDATED = 2;
- static final int FUNCTOR_PROCESS_DELAY = 2;
+ static final int FUNCTOR_PROCESS_DELAY = 4;
static EGL10 sEgl;
static EGLDisplay sEglDisplay;
@@ -579,7 +602,13 @@ public abstract class HardwareRenderer {
}
if (mProfileEnabled) {
- mProfileData = new float[PROFILE_MAX_FRAMES * PROFILE_FRAME_DATA_COUNT];
+ property = SystemProperties.get(PROFILE_MAXFRAMES_PROPERTY,
+ Integer.toString(PROFILE_MAX_FRAMES));
+ int maxProfileFrames = Integer.valueOf(property);
+ mProfileData = new float[maxProfileFrames * PROFILE_FRAME_DATA_COUNT];
+ for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+ mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
+ }
} else {
mProfileData = null;
}
@@ -596,9 +625,14 @@ public abstract class HardwareRenderer {
if (mProfileEnabled) {
pw.printf("\n\tDraw\tProcess\tExecute\n");
for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+ if (mProfileData[i] < 0) {
+ break;
+ }
pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
mProfileData[i + 2]);
+ mProfileData[i] = mProfileData[i + 1] = mProfileData[i + 2] = -1;
}
+ mProfileCurrentFrame = mProfileData.length;
}
}
@@ -1320,6 +1354,11 @@ public abstract class HardwareRenderer {
}
@Override
+ void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
+ ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
+ }
+
+ @Override
void destroyLayers(View view) {
if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) {
destroyHardwareLayer(view);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 14cd48f..8fe8e40 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -62,18 +62,9 @@ interface IWindowManager
void setForcedDisplaySize(int longDimen, int shortDimen);
void clearForcedDisplaySize();
- // Is device configured with a hideable status bar or a tablet system bar?
- boolean canStatusBarHide();
-
- // These can only be called when injecting events to your own window,
- // or by holding the INJECT_EVENTS permission. These methods may block
- // until pending input events are finished being dispatched even when 'sync' is false.
- // Avoid calling these methods on your UI thread or use the 'NoWait' version instead.
- boolean injectKeyEvent(in KeyEvent ev, boolean sync);
- boolean injectPointerEvent(in MotionEvent ev, boolean sync);
- boolean injectTrackballEvent(in MotionEvent ev, boolean sync);
- boolean injectInputEventNoWait(in InputEvent ev);
-
+ // Is the device configured to have a full system bar for larger screens?
+ boolean hasSystemNavBar();
+
// These can only be called when holding the MANAGE_APP_TOKENS permission.
void pauseKeyDispatching(IBinder token);
void resumeKeyDispatching(IBinder token);
@@ -128,26 +119,6 @@ interface IWindowManager
void setAnimationScale(int which, float scale);
void setAnimationScales(in float[] scales);
- // These require the READ_INPUT_STATE permission.
- int getSwitchState(int sw);
- int getSwitchStateForDevice(int devid, int sw);
- int getScancodeState(int sw);
- int getScancodeStateForDevice(int devid, int sw);
- int getTrackballScancodeState(int sw);
- int getDPadScancodeState(int sw);
- int getKeycodeState(int sw);
- int getKeycodeStateForDevice(int devid, int sw);
- int getTrackballKeycodeState(int sw);
- int getDPadKeycodeState(int sw);
- InputChannel monitorInput(String inputChannelName);
-
- // Report whether the hardware supports the given keys; returns true if successful
- boolean hasKeys(in int[] keycodes, inout boolean[] keyExists);
-
- // Get input device information.
- InputDevice getInputDevice(int deviceId);
- int[] getInputDeviceIds();
-
// For testing
void setInTouchMode(boolean showFocus);
@@ -171,8 +142,10 @@ interface IWindowManager
* @param alwaysSendConfiguration Flag to force a new configuration to
* be evaluated. This can be used when there are other parameters in
* configuration that are changing.
+ * @param forceRelayout If true, the window manager will always do a relayout
+ * of its windows even if the rotation hasn't changed.
*/
- void updateRotation(boolean alwaysSendConfiguration);
+ void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout);
/**
* Retrieve the current screen orientation, constants as per
@@ -218,11 +191,6 @@ interface IWindowManager
void statusBarVisibilityChanged(int visibility);
/**
- * Called by the settings application to temporarily set the pointer speed.
- */
- void setPointerSpeed(int speed);
-
- /**
* Block until the given window has been drawn to the screen.
*/
void waitForWindowDrawn(IBinder token, in IRemoteCallback callback);
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 8115b36..6f8d09b 100755
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -16,9 +16,9 @@
package android.view;
+import android.hardware.input.InputManager;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
import java.util.ArrayList;
import java.util.List;
@@ -26,7 +26,7 @@ import java.util.List;
/**
* Describes the capabilities of a particular input device.
* <p>
- * Each input device may support multiple classes of input. For example, a multifunction
+ * Each input device may support multiple classes of input. For example, a multi-function
* keyboard may compose the capabilities of a standard keyboard together with a track pad mouse
* or other pointing device.
* </p><p>
@@ -41,6 +41,7 @@ import java.util.List;
public final class InputDevice implements Parcelable {
private int mId;
private String mName;
+ private String mDescriptor;
private int mSources;
private int mKeyboardType;
private String mKeyCharacterMapFile;
@@ -118,7 +119,11 @@ public final class InputDevice implements Parcelable {
/**
* The input source is a keyboard.
- *
+ *
+ * This source indicates pretty much anything that has buttons. Use
+ * {@link #getKeyboardType()} to determine whether the keyboard has alphabetic keys
+ * and can be used to enter text.
+ *
* @see #SOURCE_CLASS_BUTTON
*/
public static final int SOURCE_KEYBOARD = 0x00000100 | SOURCE_CLASS_BUTTON;
@@ -297,13 +302,7 @@ public final class InputDevice implements Parcelable {
* @return The input device or null if not found.
*/
public static InputDevice getDevice(int id) {
- IWindowManager wm = Display.getWindowManager();
- try {
- return wm.getInputDevice(id);
- } catch (RemoteException ex) {
- throw new RuntimeException(
- "Could not get input device information from Window Manager.", ex);
- }
+ return InputManager.getInputDevice(id);
}
/**
@@ -311,23 +310,51 @@ public final class InputDevice implements Parcelable {
* @return The input device ids.
*/
public static int[] getDeviceIds() {
- IWindowManager wm = Display.getWindowManager();
- try {
- return wm.getInputDeviceIds();
- } catch (RemoteException ex) {
- throw new RuntimeException(
- "Could not get input device ids from Window Manager.", ex);
- }
+ return InputManager.getInputDeviceIds();
}
-
+
/**
* Gets the input device id.
+ * <p>
+ * Each input device receives a unique id when it is first configured
+ * by the system. The input device id may change when the system is restarted or if the
+ * input device is disconnected, reconnected or reconfigured at any time.
+ * If you require a stable identifier for a device that persists across
+ * boots and reconfigurations, use {@link #getDescriptor()}.
+ * </p>
+ *
* @return The input device id.
*/
public int getId() {
return mId;
}
-
+
+ /**
+ * Gets the input device descriptor, which is a stable identifier for an input device.
+ * <p>
+ * An input device descriptor uniquely identifies an input device. Its value
+ * is intended to be persistent across system restarts, and should not change even
+ * if the input device is disconnected, reconnected or reconfigured at any time.
+ * </p><p>
+ * It is possible for there to be multiple {@link InputDevice} instances that have the
+ * same input device descriptor. This might happen in situations where a single
+ * human input device registers multiple {@link InputDevice} instances (HID collections)
+ * that describe separate features of the device, such as a keyboard that also
+ * has a trackpad. Alternately, it may be that the input devices are simply
+ * indistinguishable, such as two keyboards made by the same manufacturer.
+ * </p><p>
+ * The input device descriptor returned by {@link #getDescriptor} should only bt
+ * used when an application needs to remember settings associated with a particular
+ * input device. For all other purposes when referring to a logical
+ * {@link InputDevice} instance at runtime use the id returned by {@link #getId()}.
+ * </p>
+ *
+ * @return The input device descriptor.
+ */
+ public String getDescriptor() {
+ return mDescriptor;
+ }
+
/**
* Gets the name of this input device.
* @return The input device name.
@@ -534,6 +561,7 @@ public final class InputDevice implements Parcelable {
private void readFromParcel(Parcel in) {
mId = in.readInt();
mName = in.readString();
+ mDescriptor = in.readString();
mSources = in.readInt();
mKeyboardType = in.readInt();
mKeyCharacterMapFile = in.readString();
@@ -552,6 +580,7 @@ public final class InputDevice implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mId);
out.writeString(mName);
+ out.writeString(mDescriptor);
out.writeInt(mSources);
out.writeInt(mKeyboardType);
out.writeString(mKeyCharacterMapFile);
@@ -578,7 +607,8 @@ public final class InputDevice implements Parcelable {
public String toString() {
StringBuilder description = new StringBuilder();
description.append("Input Device ").append(mId).append(": ").append(mName).append("\n");
-
+ description.append(" Descriptor: ").append(mDescriptor).append("\n");
+
description.append(" Keyboard Type: ");
switch (mKeyboardType) {
case KEYBOARD_TYPE_NONE:
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index 575af3b..b03f086 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -19,7 +19,7 @@ package android.view;
import android.text.method.MetaKeyKeyListener;
import android.util.AndroidRuntimeException;
import android.util.SparseIntArray;
-import android.os.RemoteException;
+import android.hardware.input.InputManager;
import android.util.SparseArray;
import java.lang.Character;
@@ -196,6 +196,14 @@ public class KeyCharacterMap {
}
/**
+ * TODO implement this
+ * @hide
+ */
+ public static KeyCharacterMap load(CharSequence contents) {
+ return null;
+ }
+
+ /**
* Gets the Unicode character generated by the specified key and meta
* key state combination.
* <p>
@@ -456,7 +464,8 @@ public class KeyCharacterMap {
/**
* Gets the keyboard type.
- * Returns {@link #NUMERIC}, {@link #PREDICTIVE}, {@link #ALPHA} or {@link #FULL}.
+ * Returns {@link #NUMERIC}, {@link #PREDICTIVE}, {@link #ALPHA}, {@link #FULL}
+ * or {@link #SPECIAL_FUNCTION}.
* <p>
* Different keyboard types have different semantics. Refer to the documentation
* associated with the keyboard type constants for details.
@@ -518,10 +527,7 @@ public class KeyCharacterMap {
* @return True if at least one attached keyboard supports the specified key code.
*/
public static boolean deviceHasKey(int keyCode) {
- int[] codeArray = new int[1];
- codeArray[0] = keyCode;
- boolean[] ret = deviceHasKeys(codeArray);
- return ret[0];
+ return InputManager.deviceHasKeys(new int[] { keyCode })[0];
}
/**
@@ -535,14 +541,7 @@ public class KeyCharacterMap {
* at the same index in the key codes array.
*/
public static boolean[] deviceHasKeys(int[] keyCodes) {
- boolean[] ret = new boolean[keyCodes.length];
- IWindowManager wm = Display.getWindowManager();
- try {
- wm.hasKeys(keyCodes, ret);
- } catch (RemoteException e) {
- // no fallback; just return the empty array
- }
- return ret;
+ return InputManager.deviceHasKeys(keyCodes);
}
/**
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 83999a1..3cd8b71 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -115,6 +115,7 @@ public class TextureView extends View {
private final Object[] mLock = new Object[0];
private boolean mUpdateLayer;
+ private boolean mUpdateSurface;
private SurfaceTexture.OnFrameAvailableListener mUpdateListener;
@@ -208,6 +209,8 @@ public class TextureView extends View {
private void destroySurface() {
if (mLayer != null) {
+ mSurface.detachFromGLContext();
+
boolean shouldRelease = true;
if (mListener != null) {
shouldRelease = mListener.onSurfaceTextureDestroyed(mSurface);
@@ -322,9 +325,13 @@ public class TextureView extends View {
}
mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
- mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
+ if (!mUpdateSurface) {
+ // We already have a SurfaceTexture to use, and we will pass it
+ // to mLayer below.
+ mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
+ }
nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
- nCreateNativeWindow(mSurface);
+ nCreateNativeWindow(mSurface);
mUpdateListener = new SurfaceTexture.OnFrameAvailableListener() {
@Override
@@ -344,6 +351,15 @@ public class TextureView extends View {
}
}
+ if (mUpdateSurface) {
+ // Someone has requested that we use a specific SurfaceTexture, so
+ // tell mLayer about it and set the SurfaceTexture to use the
+ // current view size.
+ mUpdateSurface = false;
+ mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
+ nSetDefaultBufferSize(mSurface, getWidth(), getHeight());
+ }
+
applyUpdate();
applyTransformMatrix();
@@ -371,7 +387,7 @@ public class TextureView extends View {
mUpdateLayer = true;
invalidate();
}
-
+
private void applyUpdate() {
if (mLayer == null) {
return;
@@ -636,6 +652,32 @@ public class TextureView extends View {
}
/**
+ * Set the {@link SurfaceTexture} for this view to use. If a {@link
+ * SurfaceTexture} is already being used by this view, it is immediately
+ * released and not be usable any more. The {@link
+ * SurfaceTextureListener#onSurfaceTextureDestroyed} callback is <b>not</b>
+ * called.
+ *
+ * The {@link SurfaceTexture} object must be detached from all OpenGL ES
+ * contexts prior to calling this method.
+ *
+ * @param surfaceTexture The {@link SurfaceTexture} that the view should use.
+ * @see SurfaceTexture#detachFromGLContext()
+ * @hide
+ */
+ public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
+ if (surfaceTexture == null) {
+ throw new NullPointerException("surfaceTexture must not be null");
+ }
+ if (mSurface != null) {
+ mSurface.release();
+ }
+ mSurface = surfaceTexture;
+ mUpdateSurface = true;
+ invalidateParentIfNeeded();
+ }
+
+ /**
* Returns the {@link SurfaceTextureListener} currently associated with this
* texture view.
*
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c40a7d5..d62e32f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -71,6 +71,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.ScrollBarDrawable;
import static android.os.Build.VERSION_CODES.*;
+import static java.lang.Math.max;
import com.android.internal.R;
import com.android.internal.util.Predicate;
@@ -126,7 +127,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* example, all views will let you set a listener to be notified when the view
* gains or loses focus. You can register such a listener using
* {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}.
- * Other view subclasses offer more specialized listeners. For example, a Button
+ * Other view subclasses offer more specialized listeners. For example, a Button
* exposes a listener to notify clients when the button is clicked.</li>
* <li><strong>Set visibility:</strong> You can hide or show views using
* {@link #setVisibility(int)}.</li>
@@ -579,6 +580,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* @attr ref android.R.styleable#View_duplicateParentState
* @attr ref android.R.styleable#View_id
* @attr ref android.R.styleable#View_requiresFadingEdge
+ * @attr ref android.R.styleable#View_fadeScrollbars
* @attr ref android.R.styleable#View_fadingEdgeLength
* @attr ref android.R.styleable#View_filterTouchesWhenObscured
* @attr ref android.R.styleable#View_fitsSystemWindows
@@ -624,6 +626,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
+ * @attr ref android.R.styleable#View_textAlignment
* @attr ref android.R.styleable#View_transformPivotX
* @attr ref android.R.styleable#View_transformPivotY
* @attr ref android.R.styleable#View_translationX
@@ -1827,15 +1830,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
public static final int TEXT_DIRECTION_LOCALE = 5;
/**
- * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED)
- * @hide
+ * Default text direction is inherited
*/
- static final int TEXT_DIRECTION_MASK_SHIFT = 6;
+ protected static int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
/**
- * Default text direction is inherited
+ * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED)
+ * @hide
*/
- protected static int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
+ static final int TEXT_DIRECTION_MASK_SHIFT = 6;
/**
* Mask for use with private flags indicating bits used for text direction.
@@ -1882,6 +1885,113 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
static final int TEXT_DIRECTION_RESOLVED_DEFAULT =
TEXT_DIRECTION_FIRST_STRONG << TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+ /*
+ * Default text alignment. The text alignment of this View is inherited from its parent.
+ * Use with {@link #setTextAlignment(int)}
+ */
+ public static final int TEXT_ALIGNMENT_INHERIT = 0;
+
+ /**
+ * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL,
+ * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction.
+ *
+ * Use with {@link #setTextAlignment(int)}
+ */
+ public static final int TEXT_ALIGNMENT_GRAVITY = 1;
+
+ /**
+ * Align to the start of the paragraph, e.g. ALIGN_NORMAL.
+ *
+ * Use with {@link #setTextAlignment(int)}
+ */
+ public static final int TEXT_ALIGNMENT_TEXT_START = 2;
+
+ /**
+ * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE.
+ *
+ * Use with {@link #setTextAlignment(int)}
+ */
+ public static final int TEXT_ALIGNMENT_TEXT_END = 3;
+
+ /**
+ * Center the paragraph, e.g. ALIGN_CENTER.
+ *
+ * Use with {@link #setTextAlignment(int)}
+ */
+ public static final int TEXT_ALIGNMENT_CENTER = 4;
+
+ /**
+ * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved
+ * layoutDirection is LTR, and ALIGN_RIGHT otherwise.
+ *
+ * Use with {@link #setTextAlignment(int)}
+ */
+ public static final int TEXT_ALIGNMENT_VIEW_START = 5;
+
+ /**
+ * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved
+ * layoutDirection is LTR, and ALIGN_LEFT otherwise.
+ *
+ * Use with {@link #setTextAlignment(int)}
+ */
+ public static final int TEXT_ALIGNMENT_VIEW_END = 6;
+
+ /**
+ * Default text alignment is inherited
+ */
+ protected static int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
+
+ /**
+ * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
+ * @hide
+ */
+ static final int TEXT_ALIGNMENT_MASK_SHIFT = 13;
+
+ /**
+ * Mask for use with private flags indicating bits used for text alignment.
+ * @hide
+ */
+ static final int TEXT_ALIGNMENT_MASK = 0x00000007 << TEXT_ALIGNMENT_MASK_SHIFT;
+
+ /**
+ * Array of text direction flags for mapping attribute "textAlignment" to correct
+ * flag value.
+ * @hide
+ */
+ private static final int[] TEXT_ALIGNMENT_FLAGS = {
+ TEXT_ALIGNMENT_INHERIT << TEXT_ALIGNMENT_MASK_SHIFT,
+ TEXT_ALIGNMENT_GRAVITY << TEXT_ALIGNMENT_MASK_SHIFT,
+ TEXT_ALIGNMENT_TEXT_START << TEXT_ALIGNMENT_MASK_SHIFT,
+ TEXT_ALIGNMENT_TEXT_END << TEXT_ALIGNMENT_MASK_SHIFT,
+ TEXT_ALIGNMENT_CENTER << TEXT_ALIGNMENT_MASK_SHIFT,
+ TEXT_ALIGNMENT_VIEW_START << TEXT_ALIGNMENT_MASK_SHIFT,
+ TEXT_ALIGNMENT_VIEW_END << TEXT_ALIGNMENT_MASK_SHIFT
+ };
+
+ /**
+ * Indicates whether the view text alignment has been resolved.
+ * @hide
+ */
+ static final int TEXT_ALIGNMENT_RESOLVED = 0x00000008 << TEXT_ALIGNMENT_MASK_SHIFT;
+
+ /**
+ * Bit shift to get the resolved text alignment.
+ * @hide
+ */
+ static final int TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17;
+
+ /**
+ * Mask for use with private flags indicating bits used for text alignment.
+ * @hide
+ */
+ static final int TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+
+ /**
+ * Indicates whether if the view text alignment has been resolved to gravity
+ */
+ public static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT =
+ TEXT_ALIGNMENT_GRAVITY << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+
/* End of masks for mPrivateFlags2 */
@@ -1926,7 +2036,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* system UI to enter an unobtrusive "low profile" mode.
*
* <p>This is for use in games, book readers, video players, or any other
- * "immersive" application where the usual system chrome is deemed too distracting.
+ * "immersive" application where the usual system chrome is deemed too distracting.
*
* <p>In low profile mode, the status bar and/or navigation icons may dim.
*
@@ -1942,7 +2052,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls
* (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause
* those to disappear. This is useful (in conjunction with the
- * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and
+ * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and
* {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN}
* window flags) for displaying content using every last pixel on the display.
*
@@ -2339,7 +2449,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*/
private int mPrevWidth = -1;
private int mPrevHeight = -1;
-
+
/**
* The degrees rotation around the vertical axis through the pivot point.
*/
@@ -2546,7 +2656,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*/
int mOldHeightMeasureSpec = Integer.MIN_VALUE;
- private Drawable mBGDrawable;
+ private Drawable mBackground;
private int mBackgroundResource;
private boolean mBackgroundSizeChanged;
@@ -2620,7 +2730,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* Set to true when drawing cache is enabled and cannot be created.
- *
+ *
* @hide
*/
public boolean mCachingFailed;
@@ -2841,7 +2951,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
// Set layout and text direction defaults
mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << LAYOUT_DIRECTION_MASK_SHIFT) |
- (TEXT_DIRECTION_DEFAULT << TEXT_DIRECTION_MASK_SHIFT);
+ (TEXT_DIRECTION_DEFAULT << TEXT_DIRECTION_MASK_SHIFT) |
+ (TEXT_ALIGNMENT_DEFAULT << TEXT_ALIGNMENT_MASK_SHIFT);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
mUserPaddingStart = -1;
@@ -3222,6 +3333,13 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
mPrivateFlags2 |= TEXT_DIRECTION_FLAGS[textDirection];
}
break;
+ case R.styleable.View_textAlignment:
+ // Clear any text alignment flag already set
+ mPrivateFlags2 &= ~TEXT_ALIGNMENT_MASK;
+ // Set the text alignment flag depending on the value of the attribute
+ final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT);
+ mPrivateFlags2 |= TEXT_ALIGNMENT_FLAGS[textAlignment];
+ break;
}
}
@@ -3230,7 +3348,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
setOverScrollMode(overScrollMode);
if (background != null) {
- setBackgroundDrawable(background);
+ setBackground(background);
}
// Cache user padding as we cannot fully resolve padding here (we dont have yet the resolved
@@ -3494,6 +3612,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
}
+ private ScrollabilityCache getScrollCache() {
+ initScrollCache();
+ return mScrollCache;
+ }
+
/**
* Set the position of the vertical scroll bar. Should be one of
* {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or
@@ -3909,8 +4032,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* <p>
* <strong>Note:</strong> When a View clears focus the framework is trying
* to give focus to the first focusable View from the top. Hence, if this
- * View is the first from the top that can take focus, then its focus will
- * not be cleared nor will the focus change callback be invoked.
+ * View is the first from the top that can take focus, then all callbacks
+ * related to clearing focus will be invoked after wich the framework will
+ * give focus to this view.
* </p>
*/
public void clearFocus() {
@@ -3927,25 +4051,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
onFocusChanged(false, 0, null);
refreshDrawableState();
+
+ ensureInputFocusOnFirstFocusable();
}
}
- /**
- * Called to clear the focus of a view that is about to be removed.
- * Doesn't call clearChildFocus, which prevents this view from taking
- * focus again before it has been removed from the parent
- */
- void clearFocusForRemoval() {
- if ((mPrivateFlags & FOCUSED) != 0) {
- mPrivateFlags &= ~FOCUSED;
-
- onFocusChanged(false, 0, null);
- refreshDrawableState();
-
- // The view cleared focus and invoked the callbacks, so now is the
- // time to give focus to the the first focusable from the top to
- // ensure that the gain focus is announced after clear focus.
- getRootView().requestFocus(FOCUS_FORWARD);
+ void ensureInputFocusOnFirstFocusable() {
+ View root = getRootView();
+ if (root != null) {
+ root.requestFocus(FOCUS_FORWARD);
}
}
@@ -4562,11 +4676,26 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
+ * Indicates whether this view is one of the set of scrollable containers in
+ * its window.
+ *
+ * @return whether this view is one of the set of scrollable containers in
+ * its window
+ *
+ * @attr ref android.R.styleable#View_isScrollContainer
+ */
+ public boolean isScrollContainer() {
+ return (mPrivateFlags & SCROLL_CONTAINER_ADDED) != 0;
+ }
+
+ /**
* Change whether this view is one of the set of scrollable containers in
* its window. This will be used to determine whether the window can
* resize or must pan when a soft input area is open -- scrollable
* containers allow the window to use resize mode since the container
* will appropriately shrink.
+ *
+ * @attr ref android.R.styleable#View_isScrollContainer
*/
public void setScrollContainer(boolean isScrollContainer) {
if (isScrollContainer) {
@@ -4898,7 +5027,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
@RemotableViewMethod
public void setVisibility(int visibility) {
setFlags(visibility, VISIBILITY_MASK);
- if (mBGDrawable != null) mBGDrawable.setVisible(visibility == VISIBLE, false);
+ if (mBackground != null) mBackground.setVisible(visibility == VISIBLE, false);
}
/**
@@ -5279,7 +5408,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link #setPressed(boolean)} is explicitly called, only clickable views can enter
* the pressed state.
*
- * @see #setPressed(boolean)
+ * @see #setPressed(boolean)
* @see #isClickable()
* @see #setClickable(boolean)
*
@@ -5965,7 +6094,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* Dispatch a hover event.
* <p>
- * Do not call this method directly.
+ * Do not call this method directly.
* Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead.
* </p>
*
@@ -6152,7 +6281,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @param visibility The new visibility of the window.
*
- * @see #onWindowVisibilityChanged(int)
+ * @see #onWindowVisibilityChanged(int)
*/
public void dispatchWindowVisibilityChanged(int visibility) {
onWindowVisibilityChanged(visibility);
@@ -6228,7 +6357,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @param newConfig The new resource configuration.
*
- * @see #onConfigurationChanged(android.content.res.Configuration)
+ * @see #onConfigurationChanged(android.content.res.Configuration)
*/
public void dispatchConfigurationChanged(Configuration newConfig) {
onConfigurationChanged(newConfig);
@@ -7096,7 +7225,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
if ((changed & DRAW_MASK) != 0) {
if ((mViewFlags & WILL_NOT_DRAW) != 0) {
- if (mBGDrawable != null) {
+ if (mBackground != null) {
mPrivateFlags &= ~SKIP_DRAW;
mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
} else {
@@ -7484,39 +7613,39 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* views are drawn) from the camera to this view. The camera's distance
* affects 3D transformations, for instance rotations around the X and Y
* axis. If the rotationX or rotationY properties are changed and this view is
- * large (more than half the size of the screen), it is recommended to always
+ * large (more than half the size of the screen), it is recommended to always
* use a camera distance that's greater than the height (X axis rotation) or
* the width (Y axis rotation) of this view.</p>
- *
+ *
* <p>The distance of the camera from the view plane can have an affect on the
* perspective distortion of the view when it is rotated around the x or y axis.
* For example, a large distance will result in a large viewing angle, and there
* will not be much perspective distortion of the view as it rotates. A short
- * distance may cause much more perspective distortion upon rotation, and can
+ * distance may cause much more perspective distortion upon rotation, and can
* also result in some drawing artifacts if the rotated view ends up partially
* behind the camera (which is why the recommendation is to use a distance at
* least as far as the size of the view, if the view is to be rotated.)</p>
- *
+ *
* <p>The distance is expressed in "depth pixels." The default distance depends
* on the screen density. For instance, on a medium density display, the
* default distance is 1280. On a high density display, the default distance
* is 1920.</p>
- *
+ *
* <p>If you want to specify a distance that leads to visually consistent
* results across various densities, use the following formula:</p>
* <pre>
* float scale = context.getResources().getDisplayMetrics().density;
* view.setCameraDistance(distance * scale);
* </pre>
- *
+ *
* <p>The density scale factor of a high density display is 1.5,
* and 1920 = 1280 * 1.5.</p>
- *
+ *
* @param distance The distance in "depth pixels", if negative the opposite
* value is used
- *
- * @see #setRotationX(float)
- * @see #setRotationY(float)
+ *
+ * @see #setRotationX(float)
+ * @see #setRotationY(float)
*/
public void setCameraDistance(float distance) {
invalidateViewProperty(true, false);
@@ -7541,10 +7670,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* The degrees that the view is rotated around the pivot point.
*
- * @see #setRotation(float)
+ * @see #setRotation(float)
* @see #getPivotX()
* @see #getPivotY()
- *
+ *
* @return The degrees of rotation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
@@ -7557,12 +7686,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* result in clockwise rotation.
*
* @param rotation The degrees of rotation.
- *
- * @see #getRotation()
+ *
+ * @see #getRotation()
* @see #getPivotX()
* @see #getPivotY()
- * @see #setRotationX(float)
- * @see #setRotationY(float)
+ * @see #setRotationX(float)
+ * @see #setRotationY(float)
*
* @attr ref android.R.styleable#View_rotation
*/
@@ -7586,8 +7715,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @see #getPivotX()
* @see #getPivotY()
- * @see #setRotationY(float)
- *
+ * @see #setRotationY(float)
+ *
* @return The degrees of Y rotation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
@@ -7599,18 +7728,18 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Sets the degrees that the view is rotated around the vertical axis through the pivot point.
* Increasing values result in counter-clockwise rotation from the viewpoint of looking
* down the y axis.
- *
+ *
* When rotating large views, it is recommended to adjust the camera distance
* accordingly. Refer to {@link #setCameraDistance(float)} for more information.
*
* @param rotationY The degrees of Y rotation.
- *
- * @see #getRotationY()
+ *
+ * @see #getRotationY()
* @see #getPivotX()
* @see #getPivotY()
* @see #setRotation(float)
- * @see #setRotationX(float)
- * @see #setCameraDistance(float)
+ * @see #setRotationX(float)
+ * @see #setCameraDistance(float)
*
* @attr ref android.R.styleable#View_rotationY
*/
@@ -7633,8 +7762,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @see #getPivotX()
* @see #getPivotY()
- * @see #setRotationX(float)
- *
+ * @see #setRotationX(float)
+ *
* @return The degrees of X rotation.
*/
@ViewDebug.ExportedProperty(category = "drawing")
@@ -7646,18 +7775,18 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Sets the degrees that the view is rotated around the horizontal axis through the pivot point.
* Increasing values result in clockwise rotation from the viewpoint of looking down the
* x axis.
- *
+ *
* When rotating large views, it is recommended to adjust the camera distance
* accordingly. Refer to {@link #setCameraDistance(float)} for more information.
*
* @param rotationX The degrees of X rotation.
- *
- * @see #getRotationX()
+ *
+ * @see #getRotationX()
* @see #getPivotX()
* @see #getPivotY()
* @see #setRotation(float)
- * @see #setRotationY(float)
- * @see #setCameraDistance(float)
+ * @see #setRotationY(float)
+ * @see #setCameraDistance(float)
*
* @attr ref android.R.styleable#View_rotationX
*/
@@ -7762,6 +7891,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #getScaleY()
* @see #getPivotY()
* @return The x location of the pivot point.
+ *
+ * @attr ref android.R.styleable#View_transformPivotX
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getPivotX() {
@@ -7807,6 +7938,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #getScaleY()
* @see #getPivotY()
* @return The y location of the pivot point.
+ *
+ * @attr ref android.R.styleable#View_transformPivotY
*/
@ViewDebug.ExportedProperty(category = "drawing")
public float getPivotY() {
@@ -9022,7 +9155,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
// - Background is opaque
// - Doesn't have scrollbars or scrollbars are inside overlay
- if (mBGDrawable != null && mBGDrawable.getOpacity() == PixelFormat.OPAQUE) {
+ if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) {
mPrivateFlags |= OPAQUE_BACKGROUND;
} else {
mPrivateFlags &= ~OPAQUE_BACKGROUND;
@@ -9070,7 +9203,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* <p>Causes the Runnable to be added to the message queue.
* The runnable will be run on the user interface thread.</p>
- *
+ *
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
@@ -9094,7 +9227,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* <p>Causes the Runnable to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the user interface thread.</p>
- *
+ *
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
@@ -9168,7 +9301,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* <p>Removes the specified Runnable from the message queue.</p>
- *
+ *
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
@@ -9200,7 +9333,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
- *
+ *
* @see #invalidate()
*/
public void postInvalidate() {
@@ -9210,7 +9343,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* <p>Cause an invalidate of the specified area to happen on a subsequent cycle
* through the event loop. Use this to invalidate the View from a non-UI thread.</p>
- *
+ *
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
@@ -9229,7 +9362,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* <p>Cause an invalidate to happen on a subsequent cycle through the event
* loop. Waits for the specified amount of time.</p>
- *
+ *
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
@@ -9248,7 +9381,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* <p>Cause an invalidate of the specified area to happen on a subsequent cycle
* through the event loop. Waits for the specified amount of time.</p>
- *
+ *
* <p>This method can be invoked from outside of the UI thread
* only when this View is attached to a window.</p>
*
@@ -9358,6 +9491,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* otherwise
*
* @see #setHorizontalFadingEdgeEnabled(boolean)
+ *
* @attr ref android.R.styleable#View_requiresFadingEdge
*/
public boolean isHorizontalFadingEdgeEnabled() {
@@ -9373,6 +9507,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* horizontally
*
* @see #isHorizontalFadingEdgeEnabled()
+ *
* @attr ref android.R.styleable#View_requiresFadingEdge
*/
public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {
@@ -9393,6 +9528,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* otherwise
*
* @see #setVerticalFadingEdgeEnabled(boolean)
+ *
* @attr ref android.R.styleable#View_requiresFadingEdge
*/
public boolean isVerticalFadingEdgeEnabled() {
@@ -9408,6 +9544,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* vertically
*
* @see #isVerticalFadingEdgeEnabled()
+ *
* @attr ref android.R.styleable#View_requiresFadingEdge
*/
public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) {
@@ -9550,6 +9687,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @param fadeScrollbars wheter to enable fading
*
+ * @attr ref android.R.styleable#View_fadeScrollbars
*/
public void setScrollbarFadingEnabled(boolean fadeScrollbars) {
initScrollCache();
@@ -9567,12 +9705,86 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Returns true if scrollbars will fade when this view is not scrolling
*
* @return true if scrollbar fading is enabled
+ *
+ * @attr ref android.R.styleable#View_fadeScrollbars
*/
public boolean isScrollbarFadingEnabled() {
return mScrollCache != null && mScrollCache.fadeScrollBars;
}
/**
+ *
+ * Returns the delay before scrollbars fade.
+ *
+ * @return the delay before scrollbars fade
+ *
+ * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade
+ */
+ public int getScrollBarDefaultDelayBeforeFade() {
+ return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() :
+ mScrollCache.scrollBarDefaultDelayBeforeFade;
+ }
+
+ /**
+ * Define the delay before scrollbars fade.
+ *
+ * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade
+ *
+ * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade
+ */
+ public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) {
+ getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade;
+ }
+
+ /**
+ *
+ * Returns the scrollbar fade duration.
+ *
+ * @return the scrollbar fade duration
+ *
+ * @attr ref android.R.styleable#View_scrollbarFadeDuration
+ */
+ public int getScrollBarFadeDuration() {
+ return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() :
+ mScrollCache.scrollBarFadeDuration;
+ }
+
+ /**
+ * Define the scrollbar fade duration.
+ *
+ * @param scrollBarFadeDuration - the scrollbar fade duration
+ *
+ * @attr ref android.R.styleable#View_scrollbarFadeDuration
+ */
+ public void setScrollBarFadeDuration(int scrollBarFadeDuration) {
+ getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration;
+ }
+
+ /**
+ *
+ * Returns the scrollbar size.
+ *
+ * @return the scrollbar size
+ *
+ * @attr ref android.R.styleable#View_scrollbarSize
+ */
+ public int getScrollBarSize() {
+ return mScrollCache == null ? ViewConfiguration.getScrollBarSize() :
+ mScrollCache.scrollBarSize;
+ }
+
+ /**
+ * Define the scrollbar size.
+ *
+ * @param scrollBarSize - the scrollbar size
+ *
+ * @attr ref android.R.styleable#View_scrollbarSize
+ */
+ public void setScrollBarSize(int scrollBarSize) {
+ getScrollCache().scrollBarSize = scrollBarSize;
+ }
+
+ /**
* <p>Specify the style of the scrollbars. The scrollbars can be overlaid or
* inset. When inset, they add to the padding of the view. And the scrollbars
* can be drawn inside the padding area or on the edge of the view. For example,
@@ -9588,6 +9800,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #SCROLLBARS_INSIDE_INSET
* @see #SCROLLBARS_OUTSIDE_OVERLAY
* @see #SCROLLBARS_OUTSIDE_INSET
+ *
+ * @attr ref android.R.styleable#View_scrollbarStyle
*/
public void setScrollBarStyle(int style) {
if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) {
@@ -9604,6 +9818,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @see #SCROLLBARS_INSIDE_INSET
* @see #SCROLLBARS_OUTSIDE_OVERLAY
* @see #SCROLLBARS_OUTSIDE_INSET
+ *
+ * @attr ref android.R.styleable#View_scrollbarStyle
*/
@ViewDebug.ExportedProperty(mapping = {
@ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"),
@@ -9989,6 +10205,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
resolveLayoutDirection();
resolvePadding();
resolveTextDirection();
+ resolveTextAlignment();
if (isFocused()) {
InputMethodManager imm = InputMethodManager.peekInstance();
imm.focusIn(this);
@@ -10218,6 +10435,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
mCurrentAnimation = null;
resetResolvedLayoutDirection();
+ resetResolvedTextAlignment();
}
/**
@@ -10348,9 +10566,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @param container The SparseArray in which to save the view's state.
*
- * @see #restoreHierarchyState(android.util.SparseArray)
- * @see #dispatchSaveInstanceState(android.util.SparseArray)
- * @see #onSaveInstanceState()
+ * @see #restoreHierarchyState(android.util.SparseArray)
+ * @see #dispatchSaveInstanceState(android.util.SparseArray)
+ * @see #onSaveInstanceState()
*/
public void saveHierarchyState(SparseArray<Parcelable> container) {
dispatchSaveInstanceState(container);
@@ -10363,9 +10581,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @param container The SparseArray in which to save the view's state.
*
- * @see #dispatchRestoreInstanceState(android.util.SparseArray)
- * @see #saveHierarchyState(android.util.SparseArray)
- * @see #onSaveInstanceState()
+ * @see #dispatchRestoreInstanceState(android.util.SparseArray)
+ * @see #saveHierarchyState(android.util.SparseArray)
+ * @see #onSaveInstanceState()
*/
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
@@ -10399,9 +10617,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return Returns a Parcelable object containing the view's current dynamic
* state, or null if there is nothing interesting to save. The
* default implementation returns null.
- * @see #onRestoreInstanceState(android.os.Parcelable)
- * @see #saveHierarchyState(android.util.SparseArray)
- * @see #dispatchSaveInstanceState(android.util.SparseArray)
+ * @see #onRestoreInstanceState(android.os.Parcelable)
+ * @see #saveHierarchyState(android.util.SparseArray)
+ * @see #dispatchSaveInstanceState(android.util.SparseArray)
* @see #setSaveEnabled(boolean)
*/
protected Parcelable onSaveInstanceState() {
@@ -10414,9 +10632,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @param container The SparseArray which holds previously frozen states.
*
- * @see #saveHierarchyState(android.util.SparseArray)
- * @see #dispatchRestoreInstanceState(android.util.SparseArray)
- * @see #onRestoreInstanceState(android.os.Parcelable)
+ * @see #saveHierarchyState(android.util.SparseArray)
+ * @see #dispatchRestoreInstanceState(android.util.SparseArray)
+ * @see #onRestoreInstanceState(android.os.Parcelable)
*/
public void restoreHierarchyState(SparseArray<Parcelable> container) {
dispatchRestoreInstanceState(container);
@@ -10430,9 +10648,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @param container The SparseArray which holds previously saved state.
*
- * @see #dispatchSaveInstanceState(android.util.SparseArray)
- * @see #restoreHierarchyState(android.util.SparseArray)
- * @see #onRestoreInstanceState(android.os.Parcelable)
+ * @see #dispatchSaveInstanceState(android.util.SparseArray)
+ * @see #restoreHierarchyState(android.util.SparseArray)
+ * @see #onRestoreInstanceState(android.os.Parcelable)
*/
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
if (mID != NO_ID) {
@@ -10458,9 +10676,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @param state The frozen state that had previously been returned by
* {@link #onSaveInstanceState}.
*
- * @see #onSaveInstanceState()
- * @see #restoreHierarchyState(android.util.SparseArray)
- * @see #dispatchRestoreInstanceState(android.util.SparseArray)
+ * @see #onSaveInstanceState()
+ * @see #restoreHierarchyState(android.util.SparseArray)
+ * @see #dispatchRestoreInstanceState(android.util.SparseArray)
*/
protected void onRestoreInstanceState(Parcelable state) {
mPrivateFlags |= SAVE_STATE_CALLED;
@@ -10614,7 +10832,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link #LAYER_TYPE_HARDWARE}
*
* @see #setLayerType(int, android.graphics.Paint)
- * @see #buildLayer()
+ * @see #buildLayer()
* @see #LAYER_TYPE_NONE
* @see #LAYER_TYPE_SOFTWARE
* @see #LAYER_TYPE_HARDWARE
@@ -10627,14 +10845,14 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Forces this view's layer to be created and this view to be rendered
* into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE},
* invoking this method will have no effect.
- *
+ *
* This method can for instance be used to render a view into its layer before
* starting an animation. If this view is complex, rendering into the layer
* before starting the animation will avoid skipping frames.
- *
+ *
* @throws IllegalStateException If this view is not attached to a window
- *
- * @see #setLayerType(int, android.graphics.Paint)
+ *
+ * @see #setLayerType(int, android.graphics.Paint)
*/
public void buildLayer() {
if (mLayerType == LAYER_TYPE_NONE) return;
@@ -10656,7 +10874,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
break;
}
}
-
+
// Make sure the HardwareRenderer.validate() was invoked before calling this method
void flushLayer() {
if (mLayerType == LAYER_TYPE_HARDWARE && mHardwareLayer != null) {
@@ -10675,7 +10893,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
!mAttachInfo.mHardwareRenderer.isEnabled()) {
return null;
}
-
+
if (!mAttachInfo.mHardwareRenderer.validate()) return null;
final int width = mRight - mLeft;
@@ -10709,10 +10927,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* Destroys this View's hardware layer if possible.
- *
+ *
* @return True if the layer was destroyed, false otherwise.
- *
- * @see #setLayerType(int, android.graphics.Paint)
+ *
+ * @see #setLayerType(int, android.graphics.Paint)
* @see #LAYER_TYPE_HARDWARE
*/
boolean destroyLayer(boolean valid) {
@@ -10736,11 +10954,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Destroys all hardware rendering resources. This method is invoked
* when the system needs to reclaim resources. Upon execution of this
* method, you should free any OpenGL resources created by the view.
- *
+ *
* Note: you <strong>must</strong> call
* <code>super.destroyHardwareResources()</code> when overriding
* this method.
- *
+ *
* @hide
*/
protected void destroyHardwareResources() {
@@ -11451,17 +11669,17 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
if (offsetRequired) top += getTopPaddingOffset();
return top;
}
-
+
/**
* @hide
* @param offsetRequired
*/
protected int getFadeHeight(boolean offsetRequired) {
int padding = mPaddingTop;
- if (offsetRequired) padding += getTopPaddingOffset();
+ if (offsetRequired) padding += getTopPaddingOffset();
return mBottom - mTop - mPaddingBottom - padding;
}
-
+
/**
* <p>Indicates whether this view is attached to a hardware accelerated
* window or not.</p>
@@ -11962,7 +12180,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
int saveCount;
if (!dirtyOpaque) {
- final Drawable background = mBGDrawable;
+ final Drawable background = mBackground;
if (background != null) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
@@ -12036,7 +12254,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
final ScrollabilityCache scrollabilityCache = mScrollCache;
- final float fadeHeight = scrollabilityCache.fadingEdgeLength;
+ final float fadeHeight = scrollabilityCache.fadingEdgeLength;
int length = (int) fadeHeight;
// clip the fade length if top and bottom fades overlap
@@ -12143,8 +12361,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* optimize the drawing of the fading edges. If you do return a non-zero color, the alpha
* should be set to 0xFF.
*
- * @see #setVerticalFadingEdgeEnabled(boolean)
- * @see #setHorizontalFadingEdgeEnabled(boolean)
+ * @see #setVerticalFadingEdgeEnabled(boolean)
+ * @see #setHorizontalFadingEdgeEnabled(boolean)
*
* @return The known solid color background for this view, or 0 if the color may vary
*/
@@ -12493,7 +12711,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @param who the Drawable to query
*/
public int getResolvedLayoutDirection(Drawable who) {
- return (who == mBGDrawable) ? getResolvedLayoutDirection() : LAYOUT_DIRECTION_DEFAULT;
+ return (who == mBackground) ? getResolvedLayoutDirection() : LAYOUT_DIRECTION_DEFAULT;
}
/**
@@ -12512,11 +12730,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return boolean If true than the Drawable is being displayed in the
* view; else false and it is not allowed to animate.
*
- * @see #unscheduleDrawable(android.graphics.drawable.Drawable)
- * @see #drawableStateChanged()
+ * @see #unscheduleDrawable(android.graphics.drawable.Drawable)
+ * @see #drawableStateChanged()
*/
protected boolean verifyDrawable(Drawable who) {
- return who == mBGDrawable;
+ return who == mBackground;
}
/**
@@ -12526,10 +12744,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* <p>Be sure to call through to the superclass when overriding this
* function.
*
- * @see Drawable#setState(int[])
+ * @see Drawable#setState(int[])
*/
protected void drawableStateChanged() {
- Drawable d = mBGDrawable;
+ Drawable d = mBackground;
if (d != null && d.isStateful()) {
d.setState(getDrawableState());
}
@@ -12559,9 +12777,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*
* @return The current drawable state
*
- * @see Drawable#setState(int[])
- * @see #drawableStateChanged()
- * @see #onCreateDrawableState(int)
+ * @see Drawable#setState(int[])
+ * @see #drawableStateChanged()
+ * @see #onCreateDrawableState(int)
*/
public final int[] getDrawableState() {
if ((mDrawableState != null) && ((mPrivateFlags & DRAWABLE_STATE_DIRTY) == 0)) {
@@ -12586,7 +12804,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return Returns an array holding the current {@link Drawable} state of
* the view.
*
- * @see #mergeDrawableStates(int[], int[])
+ * @see #mergeDrawableStates(int[], int[])
*/
protected int[] onCreateDrawableState(int extraSpace) {
if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE &&
@@ -12662,7 +12880,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return As a convenience, the <var>baseState</var> array you originally
* passed into the function is returned.
*
- * @see #onCreateDrawableState(int)
+ * @see #onCreateDrawableState(int)
*/
protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) {
final int N = baseState.length;
@@ -12679,8 +12897,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* on all Drawable objects associated with this view.
*/
public void jumpDrawablesToCurrentState() {
- if (mBGDrawable != null) {
- mBGDrawable.jumpToCurrentState();
+ if (mBackground != null) {
+ mBackground.jumpToCurrentState();
}
}
@@ -12690,10 +12908,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
*/
@RemotableViewMethod
public void setBackgroundColor(int color) {
- if (mBGDrawable instanceof ColorDrawable) {
- ((ColorDrawable) mBGDrawable).setColor(color);
+ if (mBackground instanceof ColorDrawable) {
+ ((ColorDrawable) mBackground).setColor(color);
} else {
- setBackgroundDrawable(new ColorDrawable(color));
+ setBackground(new ColorDrawable(color));
}
}
@@ -12701,6 +12919,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Set the background to a given resource. The resource should refer to
* a Drawable object or 0 to remove the background.
* @param resid The identifier of the resource.
+ *
* @attr ref android.R.styleable#View_background
*/
@RemotableViewMethod
@@ -12713,7 +12932,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
if (resid != 0) {
d = mResources.getDrawable(resid);
}
- setBackgroundDrawable(d);
+ setBackground(d);
mBackgroundResource = resid;
}
@@ -12725,11 +12944,19 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* touched. If setting the padding is desired, please use
* {@link #setPadding(int, int, int, int)}.
*
- * @param d The Drawable to use as the background, or null to remove the
+ * @param background The Drawable to use as the background, or null to remove the
* background
*/
- public void setBackgroundDrawable(Drawable d) {
- if (d == mBGDrawable) {
+ public void setBackground(Drawable background) {
+ setBackgroundDrawable(background);
+ }
+
+ /**
+ * @deprecated use {@link #setBackground(Drawable)} instead
+ */
+ @Deprecated
+ public void setBackgroundDrawable(Drawable background) {
+ if (background == mBackground) {
return;
}
@@ -12741,19 +12968,19 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* Regardless of whether we're setting a new background or not, we want
* to clear the previous drawable.
*/
- if (mBGDrawable != null) {
- mBGDrawable.setCallback(null);
- unscheduleDrawable(mBGDrawable);
+ if (mBackground != null) {
+ mBackground.setCallback(null);
+ unscheduleDrawable(mBackground);
}
- if (d != null) {
+ if (background != null) {
Rect padding = sThreadLocal.get();
if (padding == null) {
padding = new Rect();
sThreadLocal.set(padding);
}
- if (d.getPadding(padding)) {
- switch (d.getResolvedLayoutDirectionSelf()) {
+ if (background.getPadding(padding)) {
+ switch (background.getResolvedLayoutDirectionSelf()) {
case LAYOUT_DIRECTION_RTL:
setPadding(padding.right, padding.top, padding.left, padding.bottom);
break;
@@ -12765,17 +12992,17 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
// Compare the minimum sizes of the old Drawable and the new. If there isn't an old or
// if it has a different minimum size, we should layout again
- if (mBGDrawable == null || mBGDrawable.getMinimumHeight() != d.getMinimumHeight() ||
- mBGDrawable.getMinimumWidth() != d.getMinimumWidth()) {
+ if (mBackground == null || mBackground.getMinimumHeight() != background.getMinimumHeight() ||
+ mBackground.getMinimumWidth() != background.getMinimumWidth()) {
requestLayout = true;
}
- d.setCallback(this);
- if (d.isStateful()) {
- d.setState(getDrawableState());
+ background.setCallback(this);
+ if (background.isStateful()) {
+ background.setState(getDrawableState());
}
- d.setVisible(getVisibility() == VISIBLE, false);
- mBGDrawable = d;
+ background.setVisible(getVisibility() == VISIBLE, false);
+ mBackground = background;
if ((mPrivateFlags & SKIP_DRAW) != 0) {
mPrivateFlags &= ~SKIP_DRAW;
@@ -12784,7 +13011,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
} else {
/* Remove the background */
- mBGDrawable = null;
+ mBackground = null;
if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) {
/*
@@ -12820,10 +13047,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
/**
* Gets the background drawable
+ *
* @return The drawable used as the background for this view, if any.
+ *
+ * @see #setBackground(Drawable)
+ *
+ * @attr ref android.R.styleable#View_background
*/
public Drawable getBackground() {
- return mBGDrawable;
+ return mBackground;
}
/**
@@ -13364,8 +13596,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* number.
*
* @see #NO_ID
- * @see #getId()
- * @see #findViewById(int)
+ * @see #getId()
+ * @see #findViewById(int)
*
* @param id a number used to identify the view
*
@@ -13404,8 +13636,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return a positive integer used to identify the view or {@link #NO_ID}
* if the view has no ID
*
- * @see #setId(int)
- * @see #findViewById(int)
+ * @see #setId(int)
+ * @see #findViewById(int)
* @attr ref android.R.styleable#View_id
*/
@ViewDebug.CapturedViewProperty
@@ -13917,16 +14149,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return The suggested minimum height of the view.
*/
protected int getSuggestedMinimumHeight() {
- int suggestedMinHeight = mMinHeight;
+ return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());
- if (mBGDrawable != null) {
- final int bgMinHeight = mBGDrawable.getMinimumHeight();
- if (suggestedMinHeight < bgMinHeight) {
- suggestedMinHeight = bgMinHeight;
- }
- }
-
- return suggestedMinHeight;
}
/**
@@ -13941,16 +14165,20 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* @return The suggested minimum width of the view.
*/
protected int getSuggestedMinimumWidth() {
- int suggestedMinWidth = mMinWidth;
-
- if (mBGDrawable != null) {
- final int bgMinWidth = mBGDrawable.getMinimumWidth();
- if (suggestedMinWidth < bgMinWidth) {
- suggestedMinWidth = bgMinWidth;
- }
- }
+ return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
+ }
- return suggestedMinWidth;
+ /**
+ * Returns the minimum height of the view.
+ *
+ * @return the minimum height the view will try to be.
+ *
+ * @see #setMinimumHeight(int)
+ *
+ * @attr ref android.R.styleable#View_minHeight
+ */
+ public int getMinimumHeight() {
+ return mMinHeight;
}
/**
@@ -13959,9 +14187,27 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* constrains it with less available height).
*
* @param minHeight The minimum height the view will try to be.
+ *
+ * @see #getMinimumHeight()
+ *
+ * @attr ref android.R.styleable#View_minHeight
*/
public void setMinimumHeight(int minHeight) {
mMinHeight = minHeight;
+ requestLayout();
+ }
+
+ /**
+ * Returns the minimum width of the view.
+ *
+ * @return the minimum width the view will try to be.
+ *
+ * @see #setMinimumWidth(int)
+ *
+ * @attr ref android.R.styleable#View_minWidth
+ */
+ public int getMinimumWidth() {
+ return mMinWidth;
}
/**
@@ -13970,9 +14216,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* constrains it with less available width).
*
* @param minWidth The minimum width the view will try to be.
+ *
+ * @see #getMinimumWidth()
+ *
+ * @attr ref android.R.styleable#View_minWidth
*/
public void setMinimumWidth(int minWidth) {
mMinWidth = minWidth;
+ requestLayout();
+
}
/**
@@ -14091,11 +14343,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
getLocationInWindow(location);
region.op(location[0], location[1], location[0] + mRight - mLeft,
location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
- } else if ((pflags & ONLY_DRAWS_BACKGROUND) != 0 && mBGDrawable != null) {
+ } else if ((pflags & ONLY_DRAWS_BACKGROUND) != 0 && mBackground != null) {
// The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable
// exists, so we remove the background drawable's non-transparent
// parts from this transparent region.
- applyDrawableToTransparentRegion(mBGDrawable, region);
+ applyDrawableToTransparentRegion(mBackground, region);
}
}
return true;
@@ -14162,9 +14414,48 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
- * Request that the visibility of the status bar be changed.
- * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.
+ * Request that the visibility of the status bar or other screen/window
+ * decorations be changed.
+ *
+ * <p>This method is used to put the over device UI into temporary modes
+ * where the user's attention is focused more on the application content,
+ * by dimming or hiding surrounding system affordances. This is typically
+ * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY
+ * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content
+ * to be placed behind the action bar (and with these flags other system
+ * affordances) so that smooth transitions between hiding and showing them
+ * can be done.
+ *
+ * <p>Two representative examples of the use of system UI visibility is
+ * implementing a content browsing application (like a magazine reader)
+ * and a video playing application.
+ *
+ * <p>The first code shows a typical implementation of a View in a content
+ * browsing application. In this implementation, the application goes
+ * into a content-oriented mode by hiding the status bar and action bar,
+ * and putting the navigation elements into lights out mode. The user can
+ * then interact with content while in this mode. Such an application should
+ * provide an easy way for the user to toggle out of the mode (such as to
+ * check information in the status bar or access notifications). In the
+ * implementation here, this is done simply by tapping on the content.
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java
+ * content}
+ *
+ * <p>This second code sample shows a typical implementation of a View
+ * in a video playing application. In this situation, while the video is
+ * playing the application would like to go into a complete full-screen mode,
+ * to use as much of the display as possible for the video. When in this state
+ * the user can not interact with the application; the system intercepts
+ * touching on the screen to pop the UI out of full screen mode.
+ *
+ * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java
+ * content}
+ *
+ * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
+ * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
+ * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
+ * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
*/
public void setSystemUiVisibility(int visibility) {
if (visibility != mSystemUiVisibility) {
@@ -14176,9 +14467,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
- * Returns the status bar visibility that this view has requested.
- * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE} or
- * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}.
+ * Returns the last {@link #setSystemUiVisibility(int) that this view has requested.
+ * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE},
+ * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN},
+ * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION},
+ * and {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
*/
public int getSystemUiVisibility() {
return mSystemUiVisibility;
@@ -14766,7 +15059,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link #TEXT_DIRECTION_ANY_RTL},
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
- * {@link #TEXT_DIRECTION_LOCALE},
+ * {@link #TEXT_DIRECTION_LOCALE}
*/
@ViewDebug.ExportedProperty(category = "text", mapping = {
@ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"),
@@ -14790,7 +15083,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link #TEXT_DIRECTION_ANY_RTL},
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
- * {@link #TEXT_DIRECTION_LOCALE},
+ * {@link #TEXT_DIRECTION_LOCALE}
*/
public void setTextDirection(int textDirection) {
if (getTextDirection() != textDirection) {
@@ -14799,6 +15092,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
resetResolvedTextDirection();
// Set the new text direction
mPrivateFlags2 |= ((textDirection << TEXT_DIRECTION_MASK_SHIFT) & TEXT_DIRECTION_MASK);
+ // Refresh
requestLayout();
invalidate(true);
}
@@ -14818,7 +15112,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* {@link #TEXT_DIRECTION_ANY_RTL},
* {@link #TEXT_DIRECTION_LTR},
* {@link #TEXT_DIRECTION_RTL},
- * {@link #TEXT_DIRECTION_LOCALE},
+ * {@link #TEXT_DIRECTION_LOCALE}
*/
public int getResolvedTextDirection() {
// The text direction will be resolved only if needed
@@ -14927,6 +15221,199 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
public void onResolvedTextDirectionReset() {
}
+ /**
+ * Return the value specifying the text alignment or policy that was set with
+ * {@link #setTextAlignment(int)}.
+ *
+ * @return the defined text alignment. It can be one of:
+ *
+ * {@link #TEXT_ALIGNMENT_INHERIT},
+ * {@link #TEXT_ALIGNMENT_GRAVITY},
+ * {@link #TEXT_ALIGNMENT_CENTER},
+ * {@link #TEXT_ALIGNMENT_TEXT_START},
+ * {@link #TEXT_ALIGNMENT_TEXT_END},
+ * {@link #TEXT_ALIGNMENT_VIEW_START},
+ * {@link #TEXT_ALIGNMENT_VIEW_END}
+ */
+ @ViewDebug.ExportedProperty(category = "text", mapping = {
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
+ })
+ public int getTextAlignment() {
+ return (mPrivateFlags2 & TEXT_ALIGNMENT_MASK) >> TEXT_ALIGNMENT_MASK_SHIFT;
+ }
+
+ /**
+ * Set the text alignment.
+ *
+ * @param textAlignment The text alignment to set. Should be one of
+ *
+ * {@link #TEXT_ALIGNMENT_INHERIT},
+ * {@link #TEXT_ALIGNMENT_GRAVITY},
+ * {@link #TEXT_ALIGNMENT_CENTER},
+ * {@link #TEXT_ALIGNMENT_TEXT_START},
+ * {@link #TEXT_ALIGNMENT_TEXT_END},
+ * {@link #TEXT_ALIGNMENT_VIEW_START},
+ * {@link #TEXT_ALIGNMENT_VIEW_END}
+ *
+ * @attr ref android.R.styleable#View_textAlignment
+ */
+ public void setTextAlignment(int textAlignment) {
+ if (textAlignment != getTextAlignment()) {
+ // Reset the current and resolved text alignment
+ mPrivateFlags2 &= ~TEXT_ALIGNMENT_MASK;
+ resetResolvedTextAlignment();
+ // Set the new text alignment
+ mPrivateFlags2 |= ((textAlignment << TEXT_ALIGNMENT_MASK_SHIFT) & TEXT_ALIGNMENT_MASK);
+ // Refresh
+ requestLayout();
+ invalidate(true);
+ }
+ }
+
+ /**
+ * Return the resolved text alignment.
+ *
+ * The resolved text alignment. This needs resolution if the value is
+ * TEXT_ALIGNMENT_INHERIT. The resolution matches {@link #setTextAlignment(int)} if it is
+ * not TEXT_ALIGNMENT_INHERIT, otherwise resolution proceeds up the parent chain of the view.
+ *
+ * @return the resolved text alignment. Returns one of:
+ *
+ * {@link #TEXT_ALIGNMENT_GRAVITY},
+ * {@link #TEXT_ALIGNMENT_CENTER},
+ * {@link #TEXT_ALIGNMENT_TEXT_START},
+ * {@link #TEXT_ALIGNMENT_TEXT_END},
+ * {@link #TEXT_ALIGNMENT_VIEW_START},
+ * {@link #TEXT_ALIGNMENT_VIEW_END}
+ */
+ @ViewDebug.ExportedProperty(category = "text", mapping = {
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"),
+ @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
+ })
+ public int getResolvedTextAlignment() {
+ // If text alignment is not resolved, then resolve it
+ if ((mPrivateFlags2 & TEXT_ALIGNMENT_RESOLVED) != TEXT_ALIGNMENT_RESOLVED) {
+ resolveTextAlignment();
+ }
+ return (mPrivateFlags2 & TEXT_ALIGNMENT_RESOLVED_MASK) >> TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+ }
+
+ /**
+ * Resolve the text alignment. Will call {@link View#onResolvedTextAlignmentChanged} when
+ * resolution is done.
+ */
+ public void resolveTextAlignment() {
+ // Reset any previous text alignment resolution
+ mPrivateFlags2 &= ~(TEXT_ALIGNMENT_RESOLVED | TEXT_ALIGNMENT_RESOLVED_MASK);
+
+ if (hasRtlSupport()) {
+ // Set resolved text alignment flag depending on text alignment flag
+ final int textAlignment = getTextAlignment();
+ switch (textAlignment) {
+ case TEXT_ALIGNMENT_INHERIT:
+ // Check if we can resolve the text alignment
+ if (canResolveLayoutDirection() && mParent instanceof View) {
+ View view = (View) mParent;
+
+ final int parentResolvedTextAlignment = view.getResolvedTextAlignment();
+ switch (parentResolvedTextAlignment) {
+ case TEXT_ALIGNMENT_GRAVITY:
+ case TEXT_ALIGNMENT_TEXT_START:
+ case TEXT_ALIGNMENT_TEXT_END:
+ case TEXT_ALIGNMENT_CENTER:
+ case TEXT_ALIGNMENT_VIEW_START:
+ case TEXT_ALIGNMENT_VIEW_END:
+ // Resolved text alignment is the same as the parent resolved
+ // text alignment
+ mPrivateFlags2 |=
+ (parentResolvedTextAlignment << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
+ break;
+ default:
+ // Use default resolved text alignment
+ mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+ }
+ }
+ else {
+ // We cannot do the resolution if there is no parent so use the default
+ mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+ }
+ break;
+ case TEXT_ALIGNMENT_GRAVITY:
+ case TEXT_ALIGNMENT_TEXT_START:
+ case TEXT_ALIGNMENT_TEXT_END:
+ case TEXT_ALIGNMENT_CENTER:
+ case TEXT_ALIGNMENT_VIEW_START:
+ case TEXT_ALIGNMENT_VIEW_END:
+ // Resolved text alignment is the same as text alignment
+ mPrivateFlags2 |= (textAlignment << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
+ break;
+ default:
+ // Use default resolved text alignment
+ mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+ }
+ } else {
+ // Use default resolved text alignment
+ mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+ }
+
+ // Set the resolved
+ mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED;
+ onResolvedTextAlignmentChanged();
+ }
+
+ /**
+ * Check if text alignment resolution can be done.
+ *
+ * @return true if text alignment resolution can be done otherwise return false.
+ */
+ public boolean canResolveTextAlignment() {
+ switch (getTextAlignment()) {
+ case TEXT_DIRECTION_INHERIT:
+ return (mParent != null);
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Called when text alignment has been resolved. Subclasses that care about text alignment
+ * resolution should override this method.
+ *
+ * The default implementation does nothing.
+ */
+ public void onResolvedTextAlignmentChanged() {
+ }
+
+ /**
+ * Reset resolved text alignment. Text alignment can be resolved with a call to
+ * getResolvedTextAlignment(). Will call {@link View#onResolvedTextAlignmentReset} when
+ * reset is done.
+ */
+ public void resetResolvedTextAlignment() {
+ // Reset any previous text alignment resolution
+ mPrivateFlags2 &= ~(TEXT_ALIGNMENT_RESOLVED | TEXT_ALIGNMENT_RESOLVED_MASK);
+ onResolvedTextAlignmentReset();
+ }
+
+ /**
+ * Called when text alignment is reset. Subclasses that care about text alignment reset should
+ * override this method and do a reset of the text alignment of their children. The default
+ * implementation does nothing.
+ */
+ public void onResolvedTextAlignmentReset() {
+ }
+
//
// Properties
//
@@ -15419,7 +15906,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
* visibility. This reports <strong>global</strong> changes to the system UI
* state, not just what the application is requesting.
*
- * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener)
+ * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener)
*/
public interface OnSystemUiVisibilityChangeListener {
/**
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index b9924c7..9d06145 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -315,7 +315,7 @@ public class ViewConfiguration {
if (!sHasPermanentMenuKeySet) {
IWindowManager wm = Display.getWindowManager();
try {
- sHasPermanentMenuKey = wm.canStatusBarHide() && !wm.hasNavigationBar();
+ sHasPermanentMenuKey = !wm.hasSystemNavBar() && !wm.hasNavigationBar();
sHasPermanentMenuKeySet = true;
} catch (RemoteException ex) {
sHasPermanentMenuKey = false;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d5c783f..121b544 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3375,7 +3375,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
boolean clearChildFocus = false;
if (view == mFocused) {
- view.clearFocusForRemoval();
+ view.unFocus();
clearChildFocus = true;
}
@@ -3398,6 +3398,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (clearChildFocus) {
clearChildFocus(view);
+ ensureInputFocusOnFirstFocusable();
}
}
@@ -3450,7 +3451,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
if (view == focused) {
- view.clearFocusForRemoval();
+ view.unFocus();
clearChildFocus = view;
}
@@ -3474,6 +3475,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (clearChildFocus != null) {
clearChildFocus(clearChildFocus);
+ ensureInputFocusOnFirstFocusable();
}
}
@@ -3519,7 +3521,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
if (view == focused) {
- view.clearFocusForRemoval();
+ view.unFocus();
clearChildFocus = view;
}
@@ -3542,6 +3544,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (clearChildFocus != null) {
clearChildFocus(clearChildFocus);
+ ensureInputFocusOnFirstFocusable();
}
}
@@ -5056,6 +5059,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
+ @Override
+ public void onResolvedTextAlignmentReset() {
+ // Take care of resetting the children resolution too
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getTextAlignment() == TEXT_ALIGNMENT_INHERIT) {
+ child.resetResolvedTextAlignment();
+ }
+ }
+ }
+
/**
* Return true if the pressed state should be delayed for children or descendants of this
* ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d72f3b7..899fb32 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2039,9 +2039,10 @@ public final class ViewRootImpl implements ViewParent,
scrollToRectOrFocus(null, false);
- if (mAttachInfo.mViewScrollChanged) {
- mAttachInfo.mViewScrollChanged = false;
- mAttachInfo.mTreeObserver.dispatchOnScrollChanged();
+ final AttachInfo attachInfo = mAttachInfo;
+ if (attachInfo.mViewScrollChanged) {
+ attachInfo.mViewScrollChanged = false;
+ attachInfo.mTreeObserver.dispatchOnScrollChanged();
}
int yoff;
@@ -2056,8 +2057,8 @@ public final class ViewRootImpl implements ViewParent,
fullRedrawNeeded = true;
}
- final float appScale = mAttachInfo.mApplicationScale;
- final boolean scalingRequired = mAttachInfo.mScalingRequired;
+ final float appScale = attachInfo.mApplicationScale;
+ final boolean scalingRequired = attachInfo.mScalingRequired;
int resizeAlpha = 0;
if (mResizeBuffer != null) {
@@ -2086,7 +2087,7 @@ public final class ViewRootImpl implements ViewParent,
}
if (fullRedrawNeeded) {
- mAttachInfo.mIgnoreDirtyState = true;
+ attachInfo.mIgnoreDirtyState = true;
dirty.set(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
}
@@ -2099,8 +2100,10 @@ public final class ViewRootImpl implements ViewParent,
appScale + ", width=" + mWidth + ", height=" + mHeight);
}
+ attachInfo.mTreeObserver.dispatchOnDraw();
+
if (!dirty.isEmpty() || mIsAnimating) {
- if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
+ if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
// Draw with hardware renderer.
mIsAnimating = false;
mHardwareYOffset = yoff;
@@ -2111,154 +2114,164 @@ public final class ViewRootImpl implements ViewParent,
mPreviousDirty.set(dirty);
dirty.setEmpty();
- if (mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this,
+ if (attachInfo.mHardwareRenderer.draw(mView, attachInfo, this,
animating ? null : mCurrentDirty)) {
mPreviousDirty.set(0, 0, mWidth, mHeight);
}
- } else {
- // Draw with software renderer.
- Canvas canvas;
- try {
- int left = dirty.left;
- int top = dirty.top;
- int right = dirty.right;
- int bottom = dirty.bottom;
-
- final long lockCanvasStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
- lockCanvasStartTime = System.nanoTime();
- }
-
- canvas = mSurface.lockCanvas(dirty);
+ } else if (!drawSoftware(surface, attachInfo, yoff, scalingRequired, dirty)) {
+ return;
+ }
+ }
- if (ViewDebug.DEBUG_LATENCY) {
- long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- lockCanvas() took "
- + ((now - lockCanvasStartTime) * 0.000001f) + "ms");
- }
+ if (animating) {
+ mFullRedrawNeeded = true;
+ scheduleTraversals();
+ }
+ }
- if (left != dirty.left || top != dirty.top || right != dirty.right ||
- bottom != dirty.bottom) {
- mAttachInfo.mIgnoreDirtyState = true;
- }
+ /**
+ * @return true if drawing was succesfull, false if an error occurred
+ */
+ private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int yoff,
+ boolean scalingRequired, Rect dirty) {
- // TODO: Do this in native
- canvas.setDensity(mDensity);
- } catch (Surface.OutOfResourcesException e) {
- Log.e(TAG, "OutOfResourcesException locking surface", e);
- try {
- if (!sWindowSession.outOfMemory(mWindow)) {
- Slog.w(TAG, "No processes killed for memory; killing self");
- Process.killProcess(Process.myPid());
- }
- } catch (RemoteException ex) {
- }
- mLayoutRequested = true; // ask wm for a new surface next time.
- return;
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "IllegalArgumentException locking surface", e);
- // Don't assume this is due to out of memory, it could be
- // something else, and if it is something else then we could
- // kill stuff (or ourself) for no reason.
- mLayoutRequested = true; // ask wm for a new surface next time.
- return;
- }
+ // Draw with software renderer.
+ Canvas canvas;
+ try {
+ int left = dirty.left;
+ int top = dirty.top;
+ int right = dirty.right;
+ int bottom = dirty.bottom;
- try {
- if (DEBUG_ORIENTATION || DEBUG_DRAW) {
- Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
- + canvas.getWidth() + ", h=" + canvas.getHeight());
- //canvas.drawARGB(255, 255, 0, 0);
- }
+ final long lockCanvasStartTime;
+ if (ViewDebug.DEBUG_LATENCY) {
+ lockCanvasStartTime = System.nanoTime();
+ }
- long startTime = 0L;
- if (ViewDebug.DEBUG_PROFILE_DRAWING) {
- startTime = SystemClock.elapsedRealtime();
- }
+ canvas = mSurface.lockCanvas(dirty);
- // If this bitmap's format includes an alpha channel, we
- // need to clear it before drawing so that the child will
- // properly re-composite its drawing on a transparent
- // background. This automatically respects the clip/dirty region
- // or
- // If we are applying an offset, we need to clear the area
- // where the offset doesn't appear to avoid having garbage
- // left in the blank areas.
- if (!canvas.isOpaque() || yoff != 0) {
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
- }
+ if (ViewDebug.DEBUG_LATENCY) {
+ long now = System.nanoTime();
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- lockCanvas() took "
+ + ((now - lockCanvasStartTime) * 0.000001f) + "ms");
+ }
- dirty.setEmpty();
- mIsAnimating = false;
- mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
- mView.mPrivateFlags |= View.DRAWN;
+ if (left != dirty.left || top != dirty.top || right != dirty.right ||
+ bottom != dirty.bottom) {
+ attachInfo.mIgnoreDirtyState = true;
+ }
- if (DEBUG_DRAW) {
- Context cxt = mView.getContext();
- Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
- ", metrics=" + cxt.getResources().getDisplayMetrics() +
- ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
- }
- try {
- canvas.translate(0, -yoff);
- if (mTranslator != null) {
- mTranslator.translateCanvas(canvas);
- }
- canvas.setScreenDensity(scalingRequired
- ? DisplayMetrics.DENSITY_DEVICE : 0);
- mAttachInfo.mSetIgnoreDirtyState = false;
+ // TODO: Do this in native
+ canvas.setDensity(mDensity);
+ } catch (Surface.OutOfResourcesException e) {
+ Log.e(TAG, "OutOfResourcesException locking surface", e);
+ try {
+ if (!sWindowSession.outOfMemory(mWindow)) {
+ Slog.w(TAG, "No processes killed for memory; killing self");
+ Process.killProcess(Process.myPid());
+ }
+ } catch (RemoteException ex) {
+ }
+ mLayoutRequested = true; // ask wm for a new surface next time.
+ return false;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "IllegalArgumentException locking surface", e);
+ // Don't assume this is due to out of memory, it could be
+ // something else, and if it is something else then we could
+ // kill stuff (or ourself) for no reason.
+ mLayoutRequested = true; // ask wm for a new surface next time.
+ return false;
+ }
- final long drawStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
- drawStartTime = System.nanoTime();
- }
+ try {
+ if (DEBUG_ORIENTATION || DEBUG_DRAW) {
+ Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
+ + canvas.getWidth() + ", h=" + canvas.getHeight());
+ //canvas.drawARGB(255, 255, 0, 0);
+ }
- mView.draw(canvas);
+ long startTime = 0L;
+ if (ViewDebug.DEBUG_PROFILE_DRAWING) {
+ startTime = SystemClock.elapsedRealtime();
+ }
- if (ViewDebug.DEBUG_LATENCY) {
- long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- draw() took "
- + ((now - drawStartTime) * 0.000001f) + "ms");
- }
- } finally {
- if (!mAttachInfo.mSetIgnoreDirtyState) {
- // Only clear the flag if it was not set during the mView.draw() call
- mAttachInfo.mIgnoreDirtyState = false;
- }
- }
+ // If this bitmap's format includes an alpha channel, we
+ // need to clear it before drawing so that the child will
+ // properly re-composite its drawing on a transparent
+ // background. This automatically respects the clip/dirty region
+ // or
+ // If we are applying an offset, we need to clear the area
+ // where the offset doesn't appear to avoid having garbage
+ // left in the blank areas.
+ if (!canvas.isOpaque() || yoff != 0) {
+ canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+ }
- if (false && ViewDebug.consistencyCheckEnabled) {
- mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
- }
+ dirty.setEmpty();
+ mIsAnimating = false;
+ attachInfo.mDrawingTime = SystemClock.uptimeMillis();
+ mView.mPrivateFlags |= View.DRAWN;
- if (ViewDebug.DEBUG_PROFILE_DRAWING) {
- EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
- }
- } finally {
- final long unlockCanvasAndPostStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
- unlockCanvasAndPostStartTime = System.nanoTime();
- }
+ if (DEBUG_DRAW) {
+ Context cxt = mView.getContext();
+ Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
+ ", metrics=" + cxt.getResources().getDisplayMetrics() +
+ ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
+ }
+ try {
+ canvas.translate(0, -yoff);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(canvas);
+ }
+ canvas.setScreenDensity(scalingRequired
+ ? DisplayMetrics.DENSITY_DEVICE : 0);
+ attachInfo.mSetIgnoreDirtyState = false;
- surface.unlockCanvasAndPost(canvas);
+ final long drawStartTime;
+ if (ViewDebug.DEBUG_LATENCY) {
+ drawStartTime = System.nanoTime();
+ }
- if (ViewDebug.DEBUG_LATENCY) {
- long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- unlockCanvasAndPost() took "
- + ((now - unlockCanvasAndPostStartTime) * 0.000001f) + "ms");
- }
+ mView.draw(canvas);
- if (LOCAL_LOGV) {
- Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
- }
+ if (ViewDebug.DEBUG_LATENCY) {
+ long now = System.nanoTime();
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- draw() took "
+ + ((now - drawStartTime) * 0.000001f) + "ms");
+ }
+ } finally {
+ if (!attachInfo.mSetIgnoreDirtyState) {
+ // Only clear the flag if it was not set during the mView.draw() call
+ attachInfo.mIgnoreDirtyState = false;
}
}
- }
- if (animating) {
- mFullRedrawNeeded = true;
- scheduleTraversals();
+ if (false && ViewDebug.consistencyCheckEnabled) {
+ mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
+ }
+
+ if (ViewDebug.DEBUG_PROFILE_DRAWING) {
+ EventLog.writeEvent(60000, SystemClock.elapsedRealtime() - startTime);
+ }
+ } finally {
+ final long unlockCanvasAndPostStartTime;
+ if (ViewDebug.DEBUG_LATENCY) {
+ unlockCanvasAndPostStartTime = System.nanoTime();
+ }
+
+ surface.unlockCanvasAndPost(canvas);
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ long now = System.nanoTime();
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- unlockCanvasAndPost() took "
+ + ((now - unlockCanvasAndPostStartTime) * 0.000001f) + "ms");
+ }
+
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
+ }
}
+ return true;
}
void invalidateDisplayLists() {
@@ -3830,30 +3843,33 @@ public final class ViewRootImpl implements ViewParent,
if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
synchronized (this) {
if (mAdded) {
- mAdded = false;
dispatchDetachedFromWindow();
}
if (mAdded && !mFirst) {
destroyHardwareRenderer();
- int viewVisibility = mView.getVisibility();
- boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
- if (mWindowAttributesChanged || viewVisibilityChanged) {
- // If layout params have been changed, first give them
- // to the window manager to make sure it has the correct
- // animation info.
- try {
- if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
- & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
- sWindowSession.finishDrawing(mWindow);
+ if (mView != null) {
+ int viewVisibility = mView.getVisibility();
+ boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
+ if (mWindowAttributesChanged || viewVisibilityChanged) {
+ // If layout params have been changed, first give them
+ // to the window manager to make sure it has the correct
+ // animation info.
+ try {
+ if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
+ & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
+ sWindowSession.finishDrawing(mWindow);
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
+
+ mSurface.release();
}
-
- mSurface.release();
}
+
+ mAdded = false;
}
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index 7fd3389..1c5d436 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -38,6 +38,7 @@ public final class ViewTreeObserver {
private CopyOnWriteArrayList<OnComputeInternalInsetsListener> mOnComputeInternalInsetsListeners;
private CopyOnWriteArrayList<OnScrollChangedListener> mOnScrollChangedListeners;
private ArrayList<OnPreDrawListener> mOnPreDrawListeners;
+ private ArrayList<OnDrawListener> mOnDrawListeners;
private boolean mAlive = true;
@@ -90,6 +91,27 @@ public final class ViewTreeObserver {
}
/**
+ * Interface definition for a callback to be invoked when the view tree is about to be drawn.
+ */
+ public interface OnDrawListener {
+ /**
+ * <p>Callback method to be invoked when the view tree is about to be drawn. At this point,
+ * views cannot be modified in any way.</p>
+ *
+ * <p>Unlike with {@link OnPreDrawListener}, this method cannot be used to cancel the
+ * current drawing pass.</p>
+ *
+ * <p>An {@link OnDrawListener} listener <strong>cannot be added or removed</strong>
+ * from this method.</p>
+ *
+ * @see android.view.View#onMeasure
+ * @see android.view.View#onLayout
+ * @see android.view.View#onDraw
+ */
+ public void onDraw();
+ }
+
+ /**
* Interface definition for a callback to be invoked when the touch mode changes.
*/
public interface OnTouchModeChangeListener {
@@ -171,11 +193,7 @@ public final class ViewTreeObserver {
public void setTouchableInsets(int val) {
mTouchableInsets = val;
}
-
- public int getTouchableInsets() {
- return mTouchableInsets;
- }
-
+
int mTouchableInsets;
void reset() {
@@ -184,29 +202,28 @@ public final class ViewTreeObserver {
touchableRegion.setEmpty();
mTouchableInsets = TOUCHABLE_INSETS_FRAME;
}
-
+
+ @Override
+ public int hashCode() {
+ int result = contentInsets != null ? contentInsets.hashCode() : 0;
+ result = 31 * result + (visibleInsets != null ? visibleInsets.hashCode() : 0);
+ result = 31 * result + (touchableRegion != null ? touchableRegion.hashCode() : 0);
+ result = 31 * result + mTouchableInsets;
+ return result;
+ }
+
@Override
public boolean equals(Object o) {
- try {
- if (o == null) {
- return false;
- }
- InternalInsetsInfo other = (InternalInsetsInfo)o;
- if (mTouchableInsets != other.mTouchableInsets) {
- return false;
- }
- if (!contentInsets.equals(other.contentInsets)) {
- return false;
- }
- if (!visibleInsets.equals(other.visibleInsets)) {
- return false;
- }
- return touchableRegion.equals(other.touchableRegion);
- } catch (ClassCastException e) {
- return false;
- }
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ InternalInsetsInfo other = (InternalInsetsInfo)o;
+ return mTouchableInsets == other.mTouchableInsets &&
+ contentInsets.equals(other.contentInsets) &&
+ visibleInsets.equals(other.visibleInsets) &&
+ touchableRegion.equals(other.touchableRegion);
}
-
+
void set(InternalInsetsInfo other) {
contentInsets.set(other.contentInsets);
visibleInsets.set(other.visibleInsets);
@@ -420,6 +437,44 @@ public final class ViewTreeObserver {
}
/**
+ * <p>Register a callback to be invoked when the view tree is about to be drawn.</p>
+ * <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
+ * {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
+ *
+ * @param listener The callback to add
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ */
+ public void addOnDrawListener(OnDrawListener listener) {
+ checkIsAlive();
+
+ if (mOnDrawListeners == null) {
+ mOnDrawListeners = new ArrayList<OnDrawListener>();
+ }
+
+ mOnDrawListeners.add(listener);
+ }
+
+ /**
+ * <p>Remove a previously installed pre-draw callback.</p>
+ * <p><strong>Note:</strong> this method <strong>cannot</strong> be invoked from
+ * {@link android.view.ViewTreeObserver.OnDrawListener#onDraw()}.</p>
+ *
+ * @param victim The callback to remove
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @see #addOnDrawListener(OnDrawListener)
+ */
+ public void removeOnDrawListener(OnDrawListener victim) {
+ checkIsAlive();
+ if (mOnDrawListeners == null) {
+ return;
+ }
+ mOnDrawListeners.remove(victim);
+ }
+
+ /**
* Register a callback to be invoked when a view has been scrolled.
*
* @param listener The callback to add
@@ -601,6 +656,7 @@ public final class ViewTreeObserver {
*
* @return True if the current draw should be canceled and resceduled, false otherwise.
*/
+ @SuppressWarnings("unchecked")
public final boolean dispatchOnPreDraw() {
// NOTE: we *must* clone the listener list to perform the dispatching.
// The clone is a safe guard against listeners that
@@ -619,6 +675,19 @@ public final class ViewTreeObserver {
}
/**
+ * Notifies registered listeners that the drawing pass is about to start.
+ */
+ public final void dispatchOnDraw() {
+ if (mOnDrawListeners != null) {
+ final ArrayList<OnDrawListener> listeners = mOnDrawListeners;
+ int numListeners = listeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ listeners.get(i).onDraw();
+ }
+ }
+ }
+
+ /**
* Notifies registered listeners that the touch mode has changed.
*
* @param inTouchMode True if the touch mode is now enabled, false otherwise.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 75267bb..491cd67 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -326,6 +326,11 @@ public interface WindowManagerPolicy {
* Returns true if {@link #hideLw} was last called for the window.
*/
public boolean showLw(boolean doAnimation);
+
+ /**
+ * Check whether the process hosting this window is currently alive.
+ */
+ public boolean isAlive();
}
/**
@@ -344,6 +349,10 @@ public interface WindowManagerPolicy {
* between it and the policy.
*/
public interface WindowManagerFuncs {
+ public static final int LID_ABSENT = -1;
+ public static final int LID_CLOSED = 0;
+ public static final int LID_OPEN = 1;
+
/**
* Ask the window manager to re-evaluate the system UI flags.
*/
@@ -357,6 +366,16 @@ public interface WindowManagerPolicy {
InputEventReceiver.Factory inputEventReceiverFactory,
String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
boolean hasFocus, boolean touchFullscreen);
+
+ /**
+ * Returns a code that describes the current state of the lid switch.
+ */
+ public int getLidState();
+
+ /**
+ * Creates an input channel that will receive all input from the input dispatcher.
+ */
+ public InputChannel monitorInput(String name);
}
/**
@@ -447,7 +466,7 @@ public interface WindowManagerPolicy {
* Called by window manager once it has the initial, default native
* display dimensions.
*/
- public void setInitialDisplaySize(int width, int height);
+ public void setInitialDisplaySize(Display display, int width, int height);
/**
* Check permissions when adding a window.
@@ -514,10 +533,10 @@ public interface WindowManagerPolicy {
public int getMaxWallpaperLayer();
/**
- * Return true if the policy allows the status bar to hide. Otherwise,
- * it is a tablet-style system bar.
+ * Return true if the policy desires a full unified system nav bar. Otherwise,
+ * it is a phone-style status bar with optional nav bar.
*/
- public boolean canStatusBarHide();
+ public boolean hasSystemNavBar();
/**
* Return the display width available after excluding any screen
@@ -938,10 +957,10 @@ public interface WindowManagerPolicy {
public void setRotationLw(int rotation);
/**
- * Called when the system is mostly done booting to determine whether
+ * Called when the system is mostly done booting to set whether
* the system should go into safe mode.
*/
- public boolean detectSafeMode();
+ public void setSafeMode(boolean safeMode);
/**
* Called when the system is mostly done booting.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 17dbde8..067be39 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -405,7 +405,9 @@ public final class InputMethodManager {
}
// Check focus again in case that "onWindowFocus" is called before
// handling this message.
- checkFocus(mHasBeenInactive);
+ if (mServedView != null && mServedView.hasWindowFocus()) {
+ checkFocus(mHasBeenInactive);
+ }
}
}
return;
@@ -1202,7 +1204,9 @@ public final class InputMethodManager {
}
if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
+ " next=" + mNextServedView
- + " forceNewFocus=" + forceNewFocus);
+ + " forceNewFocus=" + forceNewFocus
+ + " package="
+ + (mServedView != null ? mServedView.getContext().getPackageName() : "<none>"));
if (mNextServedView == null) {
finishInputLocked();
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index 137743a..d05c1af 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -45,6 +45,7 @@ public final class SpellCheckerInfo implements Parcelable {
private final ResolveInfo mService;
private final String mId;
private final int mLabel;
+ private final boolean mSupportsSentenceSpellCheck;
/**
* The spell checker setting activity's name, used by the system settings to
@@ -97,6 +98,9 @@ public final class SpellCheckerInfo implements Parcelable {
label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
settingsActivityComponent = sa.getString(
com.android.internal.R.styleable.SpellChecker_settingsActivity);
+ mSupportsSentenceSpellCheck = sa.getBoolean(
+ com.android.internal.R.styleable.SpellChecker_supportsSentenceSpellCheck,
+ false);
sa.recycle();
final int depth = parser.getDepth();
@@ -138,6 +142,7 @@ public final class SpellCheckerInfo implements Parcelable {
*/
public SpellCheckerInfo(Parcel source) {
mLabel = source.readInt();
+ mSupportsSentenceSpellCheck = source.readInt() != 0;
mId = source.readString();
mSettingsActivityName = source.readString();
mService = ResolveInfo.CREATOR.createFromParcel(source);
@@ -152,6 +157,12 @@ public final class SpellCheckerInfo implements Parcelable {
return mId;
}
+ /**
+ * @hide
+ */
+ public boolean isSentenceSpellCheckSupported() {
+ return mSupportsSentenceSpellCheck;
+ }
/**
* Return the component of the service that implements.
@@ -177,6 +188,7 @@ public final class SpellCheckerInfo implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mLabel);
+ dest.writeInt(mSupportsSentenceSpellCheck ? 1 : 0);
dest.writeString(mId);
dest.writeString(mSettingsActivityName);
mService.writeToParcel(dest, flags);
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 35940ba..9dc05e4 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -436,15 +436,15 @@ public class SpellCheckerSession {
*/
public interface SpellCheckerSessionListener {
/**
- * Callback for {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
+ * Callback for {@link SpellCheckerSession#getSuggestions(TextInfo, int)}
+ * and {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
* @param results an array of {@link SuggestionsInfo}s.
* These results are suggestions for {@link TextInfo}s queried by
- * {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}.
+ * {@link SpellCheckerSession#getSuggestions(TextInfo, int)} or
+ * {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
*/
public void onGetSuggestions(SuggestionsInfo[] results);
- // TODO: Remove @hide as soon as the sample spell checker client gets fixed.
/**
- * @hide
* Callback for {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)}
* @param results an array of {@link SentenceSuggestionsInfo}s.
* These results are suggestions for {@link TextInfo}s
@@ -494,7 +494,7 @@ public class SpellCheckerSession {
}
/**
- * @hide
+ * @return true if the spell checker supports sentence level spell checking APIs
*/
public boolean isSentenceSpellCheckSupported() {
return mSubtype.containsExtraValueKey(SUPPORT_SENTENCE_SPELL_CHECK);
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 6c331ac..6b7263c 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -148,8 +148,8 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
mInput.showSoftInput(mEditText, 0);
}
- public void updateMatchCount(int matchIndex, int matchCount, boolean isNewFind) {
- if (!isNewFind) {
+ public void updateMatchCount(int matchIndex, int matchCount, boolean isEmptyFind) {
+ if (!isEmptyFind) {
mNumberOfMatches = matchCount;
mActiveMatchIndex = matchIndex;
updateMatchesString();
diff --git a/core/java/android/webkit/WebSettingsClassic.java b/core/java/android/webkit/WebSettingsClassic.java
index 94b46fc..aa3d8d3 100644
--- a/core/java/android/webkit/WebSettingsClassic.java
+++ b/core/java/android/webkit/WebSettingsClassic.java
@@ -33,7 +33,7 @@ import java.util.Locale;
*/
public class WebSettingsClassic extends WebSettings {
// TODO: Keep this up to date
- private static final String PREVIOUS_VERSION = "4.0.3";
+ private static final String PREVIOUS_VERSION = "4.0.4";
// WebView associated with this WebSettings.
private WebViewClassic mWebView;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9492e38..84632c6 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -313,7 +313,6 @@ public class WebView extends AbsoluteLayout
/**
* Interface to listen for find results.
- * @hide
*/
public interface FindListener {
/**
@@ -1249,8 +1248,7 @@ public class WebView extends AbsoluteLayout
* Register the listener to be notified as find-on-page operations progress.
* This will replace the current listener.
*
- * @param listener An implementation of {@link WebView#FindListener}.
- * @hide
+ * @param listener An implementation of {@link FindListener}.
*/
public void setFindListener(FindListener listener) {
checkThread();
@@ -1258,11 +1256,15 @@ public class WebView extends AbsoluteLayout
}
/**
- * Highlight and scroll to the next occurance of String in findAll.
- * Wraps the page infinitely, and scrolls. Must be called after
- * calling findAll.
+ * Highlight and scroll to the next match found by {@link #findAll} or
+ * {@link #findAllAsync}, wrapping around page boundaries as necessary.
+ * Notifies any registered {@link FindListener}. If neither
+ * {@link #findAll} nor {@link #findAllAsync(String)} has been called yet,
+ * or if {@link #clearMatches} has been called since the last find
+ * operation, this function does nothing.
*
* @param forward Direction to search.
+ * @see #setFindListener
*/
public void findNext(boolean forward) {
checkThread();
@@ -1271,10 +1273,13 @@ public class WebView extends AbsoluteLayout
/**
* Find all instances of find on the page and highlight them.
+ * Notifies any registered {@link FindListener}.
*
* @param find String to find.
* @return int The number of occurances of the String "find"
* that were found.
+ * @deprecated {@link #findAllAsync} is preferred.
+ * @see #setFindListener
*/
public int findAll(String find) {
checkThread();
@@ -1283,10 +1288,12 @@ public class WebView extends AbsoluteLayout
/**
* Find all instances of find on the page and highlight them,
- * asynchronously.
+ * asynchronously. Notifies any registered {@link FindListener}.
+ * Successive calls to this or {@link #findAll} will cancel any
+ * pending searches.
*
* @param find String to find.
- * @hide
+ * @see #setFindListener
*/
public void findAllAsync(String find) {
checkThread();
@@ -1333,8 +1340,9 @@ public class WebView extends AbsoluteLayout
return getFactory().getStatics().findAddress(addr);
}
- /*
- * Clear the highlighting surrounding text matches created by findAll.
+ /**
+ * Clear the highlighting surrounding text matches created by
+ * {@link #findAll} or {@link #findAllAsync}.
*/
public void clearMatches() {
checkThread();
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 4c118ac..586fcb1 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -3588,7 +3588,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
@Override
public void findNext(boolean forward) {
if (0 == mNativeClass) return; // client isn't initialized
- mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0);
+ if (mFindRequest != null) {
+ mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0, mFindRequest);
+ }
}
/**
@@ -3605,28 +3607,26 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
private int findAllBody(String find, boolean isAsync) {
if (0 == mNativeClass) return 0; // client isn't initialized
- mLastFind = find;
+ mFindRequest = null;
if (find == null) return 0;
mWebViewCore.removeMessages(EventHub.FIND_ALL);
- WebViewCore.FindAllRequest request = new
- WebViewCore.FindAllRequest(find);
+ mFindRequest = new WebViewCore.FindAllRequest(find);
if (isAsync) {
- mWebViewCore.sendMessage(EventHub.FIND_ALL, request);
+ mWebViewCore.sendMessage(EventHub.FIND_ALL, mFindRequest);
return 0; // no need to wait for response
}
- synchronized(request) {
+ synchronized(mFindRequest) {
try {
- mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL,
- request);
- while (request.mMatchCount == -1) {
- request.wait();
+ mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL, mFindRequest);
+ while (mFindRequest.mMatchCount == -1) {
+ mFindRequest.wait();
}
}
catch (InterruptedException e) {
return 0;
}
+ return mFindRequest.mMatchCount;
}
- return request.mMatchCount;
}
/**
@@ -3657,7 +3657,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
return true;
}
if (text == null) {
- text = mLastFind;
+ text = mFindRequest == null ? null : mFindRequest.mSearchText;
}
if (text != null) {
mFindCallback.setText(text);
@@ -3683,9 +3683,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// or not we draw the highlights for matches.
private boolean mFindIsUp;
- // Keep track of the last string sent, so we can search again when find is
- // reopened.
- private String mLastFind;
+ // Keep track of the last find request sent.
+ private WebViewCore.FindAllRequest mFindRequest = null;
/**
* Return the first substring consisting of the address of a physical
@@ -8476,13 +8475,27 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
}
case UPDATE_MATCH_COUNT: {
- boolean isNewFind = mLastFind == null || !mLastFind.equals(msg.obj);
- if (mFindCallback != null)
- mFindCallback.updateMatchCount(msg.arg1, msg.arg2, isNewFind);
- if (mFindListener != null)
- mFindListener.onFindResultReceived(msg.arg1, msg.arg2, true);
+ WebViewCore.FindAllRequest request = (WebViewCore.FindAllRequest)msg.obj;
+ if (request == null) {
+ if (mFindCallback != null) {
+ mFindCallback.updateMatchCount(0, 0, true);
+ }
+ } else if (request == mFindRequest) {
+ int matchCount, matchIndex;
+ synchronized (mFindRequest) {
+ matchCount = request.mMatchCount;
+ matchIndex = request.mMatchIndex;
+ }
+ if (mFindCallback != null) {
+ mFindCallback.updateMatchCount(matchIndex, matchCount, false);
+ }
+ if (mFindListener != null) {
+ mFindListener.onFindResultReceived(matchIndex, matchCount, true);
+ }
+ }
break;
}
+
case CLEAR_CARET_HANDLE:
selectionDone();
break;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b4ebc09..5549d89 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1041,9 +1041,11 @@ public final class WebViewCore {
public FindAllRequest(String text) {
mSearchText = text;
mMatchCount = -1;
+ mMatchIndex = -1;
}
- public String mSearchText;
+ public final String mSearchText;
public int mMatchCount;
+ public int mMatchIndex;
}
/**
@@ -1777,21 +1779,32 @@ public final class WebViewCore {
nativeSelectAll(mNativeClass);
break;
case FIND_ALL: {
- FindAllRequest request = (FindAllRequest) msg.obj;
- if (request == null) {
- nativeFindAll(mNativeClass, null);
- } else {
- request.mMatchCount = nativeFindAll(
- mNativeClass, request.mSearchText);
- synchronized(request) {
+ FindAllRequest request = (FindAllRequest)msg.obj;
+ if (request != null) {
+ int matchCount = nativeFindAll(mNativeClass, request.mSearchText);
+ int matchIndex = nativeFindNext(mNativeClass, true);
+ synchronized (request) {
+ request.mMatchCount = matchCount;
+ request.mMatchIndex = matchIndex;
request.notify();
}
+ } else {
+ nativeFindAll(mNativeClass, null);
}
+ Message.obtain(mWebViewClassic.mPrivateHandler,
+ WebViewClassic.UPDATE_MATCH_COUNT, request).sendToTarget();
break;
}
- case FIND_NEXT:
- nativeFindNext(mNativeClass, msg.arg1 != 0);
+ case FIND_NEXT: {
+ FindAllRequest request = (FindAllRequest)msg.obj;
+ int matchIndex = nativeFindNext(mNativeClass, msg.arg1 != 0);
+ synchronized (request) {
+ request.mMatchIndex = matchIndex;
+ }
+ Message.obtain(mWebViewClassic.mPrivateHandler,
+ WebViewClassic.UPDATE_MATCH_COUNT, request).sendToTarget();
break;
+ }
}
}
};
@@ -2825,17 +2838,6 @@ public final class WebViewCore {
.sendToTarget();
}
- // called by JNI
- private void updateMatchCount(int matchIndex, int matchCount,
- String findText) {
- if (mWebViewClassic == null) {
- return;
- }
- Message.obtain(mWebViewClassic.mPrivateHandler,
- WebViewClassic.UPDATE_MATCH_COUNT, matchIndex, matchCount,
- findText).sendToTarget();
- }
-
private native void nativeRevealSelection(int nativeClass);
private native String nativeRequestLabel(int nativeClass, int framePtr,
int nodePtr);
@@ -3086,7 +3088,7 @@ public final class WebViewCore {
private native void nativeAutoFillForm(int nativeClass, int queryId);
private native void nativeScrollLayer(int nativeClass, int layer, Rect rect);
private native int nativeFindAll(int nativeClass, String text);
- private native void nativeFindNext(int nativeClass, boolean forward);
+ private native int nativeFindNext(int nativeClass, boolean forward);
/**
* Deletes editable text between two points. Note that the selection may
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index 0370049..b7a126e 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -25,6 +25,7 @@ import android.os.SystemClock;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.RemoteViews.RemoteView;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 880dc34..cbff58c 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1609,7 +1609,6 @@ public class Editor {
private boolean mCancelled;
public void run() {
- Log.d("GILLES", "blinking !!!");
if (mCancelled) {
return;
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d2a1755..9867e47 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5340,24 +5340,63 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
physicalWidth, false);
}
+ @Override
+ public void onResolvedLayoutDirectionReset() {
+ if (mLayoutAlignment != null) {
+ int resolvedTextAlignment = getResolvedTextAlignment();
+ if (resolvedTextAlignment == TEXT_ALIGNMENT_VIEW_START ||
+ resolvedTextAlignment == TEXT_ALIGNMENT_VIEW_END) {
+ mLayoutAlignment = null;
+ }
+ }
+ }
+
private Layout.Alignment getLayoutAlignment() {
if (mLayoutAlignment == null) {
- switch (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
- case Gravity.START:
+ int textAlign = getResolvedTextAlignment();
+ switch (textAlign) {
+ case TEXT_ALIGNMENT_GRAVITY:
+ switch (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.START:
+ mLayoutAlignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ case Gravity.END:
+ mLayoutAlignment = Layout.Alignment.ALIGN_OPPOSITE;
+ break;
+ case Gravity.LEFT:
+ mLayoutAlignment = Layout.Alignment.ALIGN_LEFT;
+ break;
+ case Gravity.RIGHT:
+ mLayoutAlignment = Layout.Alignment.ALIGN_RIGHT;
+ break;
+ case Gravity.CENTER_HORIZONTAL:
+ mLayoutAlignment = Layout.Alignment.ALIGN_CENTER;
+ break;
+ default:
+ mLayoutAlignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ }
+ break;
+ case TEXT_ALIGNMENT_TEXT_START:
mLayoutAlignment = Layout.Alignment.ALIGN_NORMAL;
break;
- case Gravity.END:
+ case TEXT_ALIGNMENT_TEXT_END:
mLayoutAlignment = Layout.Alignment.ALIGN_OPPOSITE;
break;
- case Gravity.LEFT:
- mLayoutAlignment = Layout.Alignment.ALIGN_LEFT;
+ case TEXT_ALIGNMENT_CENTER:
+ mLayoutAlignment = Layout.Alignment.ALIGN_CENTER;
break;
- case Gravity.RIGHT:
- mLayoutAlignment = Layout.Alignment.ALIGN_RIGHT;
+ case TEXT_ALIGNMENT_VIEW_START:
+ mLayoutAlignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
+ Layout.Alignment.ALIGN_RIGHT : Layout.Alignment.ALIGN_LEFT;
break;
- case Gravity.CENTER_HORIZONTAL:
- mLayoutAlignment = Layout.Alignment.ALIGN_CENTER;
+ case TEXT_ALIGNMENT_VIEW_END:
+ mLayoutAlignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
+ Layout.Alignment.ALIGN_LEFT : Layout.Alignment.ALIGN_RIGHT;
break;
+ case TEXT_ALIGNMENT_INHERIT:
+ // This should never happen as we have already resolved the text alignment
+ // but better safe than sorry so we just fall through
default:
mLayoutAlignment = Layout.Alignment.ALIGN_NORMAL;
break;