summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/animation/Animator.java16
-rw-r--r--core/java/android/animation/PropertyValuesHolder.java2
-rw-r--r--core/java/android/app/Activity.java7
-rw-r--r--core/java/android/app/ActivityManager.java7
-rw-r--r--core/java/android/app/ActivityManagerNative.java2
-rw-r--r--core/java/android/app/ActivityThread.java7
-rw-r--r--core/java/android/app/AlarmManager.java2
-rw-r--r--core/java/android/app/AppOpsManager.java17
-rw-r--r--core/java/android/app/ContextImpl.java15
-rw-r--r--core/java/android/app/Fragment.java1
-rw-r--r--core/java/android/app/FragmentManager.java1
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java36
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java27
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java4
-rw-r--r--core/java/android/content/ContentProvider.java205
-rw-r--r--core/java/android/content/ContentProviderClient.java29
-rw-r--r--core/java/android/content/ContentProviderNative.java65
-rw-r--r--core/java/android/content/ContentResolver.java83
-rw-r--r--core/java/android/content/Context.java14
-rw-r--r--core/java/android/content/IContentProvider.java5
-rw-r--r--core/java/android/content/Intent.java11
-rw-r--r--core/java/android/content/UndoManager.java2
-rw-r--r--core/java/android/content/UndoOperation.java2
-rw-r--r--core/java/android/content/UndoOwner.java2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java29
-rw-r--r--core/java/android/content/pm/PackageParser.java29
-rw-r--r--core/java/android/content/pm/ServiceInfo.java2
-rw-r--r--core/java/android/content/res/Configuration.java35
-rw-r--r--core/java/android/content/res/TypedArray.java5
-rw-r--r--core/java/android/database/MatrixCursor.java4
-rw-r--r--core/java/android/hardware/FlushCompleteListener.java34
-rw-r--r--core/java/android/hardware/Sensor.java20
-rw-r--r--core/java/android/hardware/SensorManager.java171
-rw-r--r--core/java/android/hardware/SystemSensorManager.java116
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java39
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java37
-rw-r--r--core/java/android/hardware/camera2/Rational.java83
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDevice.java4
-rw-r--r--core/java/android/hardware/camera2/utils/CameraBinderDecorator.java4
-rw-r--r--core/java/android/net/BaseNetworkStateTracker.java2
-rw-r--r--core/java/android/net/ConnectivityManager.java12
-rw-r--r--core/java/android/net/IConnectivityManager.aidl8
-rw-r--r--core/java/android/net/LinkInfo.java128
-rw-r--r--core/java/android/net/LinkProperties.java45
-rw-r--r--core/java/android/net/LinkQualityInfo.aidl (renamed from core/java/android/net/LinkInfo.aidl)2
-rw-r--r--core/java/android/net/LinkQualityInfo.java286
-rw-r--r--core/java/android/net/MobileDataStateTracker.java104
-rw-r--r--core/java/android/net/MobileLinkInfo.java89
-rw-r--r--core/java/android/net/MobileLinkQualityInfo.java286
-rw-r--r--core/java/android/net/NetworkInfo.java35
-rw-r--r--core/java/android/net/NetworkStateTracker.java2
-rw-r--r--core/java/android/net/SamplingDataTracker.java30
-rw-r--r--core/java/android/net/WifiLinkInfo.java75
-rw-r--r--core/java/android/net/WifiLinkQualityInfo.java149
-rw-r--r--core/java/android/nfc/IAppCallback.aidl (renamed from core/java/android/nfc/INdefPushCallback.aidl)4
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl7
-rw-r--r--core/java/android/nfc/NfcActivityManager.java47
-rw-r--r--core/java/android/nfc/NfcAdapter.java49
-rw-r--r--core/java/android/os/BatteryStats.java25
-rw-r--r--core/java/android/os/Binder.java10
-rw-r--r--core/java/android/os/Build.java4
-rw-r--r--core/java/android/os/Debug.java13
-rw-r--r--core/java/android/os/Environment.java3
-rw-r--r--core/java/android/os/INetworkManagementService.aidl5
-rw-r--r--core/java/android/os/IUserManager.aidl6
-rw-r--r--core/java/android/os/MessageQueue.java47
-rw-r--r--core/java/android/os/UserManager.java49
-rw-r--r--core/java/android/preference/PreferenceActivity.java9
-rw-r--r--core/java/android/preference/PreferenceGroup.java5
-rw-r--r--core/java/android/print/IPrinterDiscoveryObserver.aidl2
-rw-r--r--core/java/android/print/PrintAttributes.java1253
-rw-r--r--core/java/android/print/PrintDocumentAdapter.java32
-rw-r--r--core/java/android/print/PrintDocumentInfo.java239
-rw-r--r--core/java/android/print/PrintFileDocumentAdapter.java9
-rw-r--r--core/java/android/print/PrinterCapabilitiesInfo.java418
-rw-r--r--core/java/android/print/PrinterDiscoverySession.java38
-rw-r--r--core/java/android/printservice/IPrintServiceClient.aidl1
-rw-r--r--core/java/android/printservice/PrintJob.java4
-rw-r--r--core/java/android/printservice/PrintService.java6
-rw-r--r--core/java/android/printservice/PrintServiceInfo.java8
-rw-r--r--core/java/android/printservice/PrinterDiscoverySession.java170
-rw-r--r--core/java/android/printservice/package.html3
-rw-r--r--core/java/android/provider/DocumentsContract.java70
-rw-r--r--core/java/android/provider/DocumentsProvider.java68
-rw-r--r--core/java/android/provider/Settings.java38
-rw-r--r--core/java/android/security/IKeystoreService.java5
-rw-r--r--core/java/android/speech/hotword/HotwordRecognitionListener.java6
-rw-r--r--core/java/android/speech/hotword/HotwordRecognitionService.java78
-rw-r--r--core/java/android/speech/hotword/HotwordRecognizer.java51
-rw-r--r--core/java/android/speech/hotword/IHotwordRecognitionListener.aidl7
-rw-r--r--core/java/android/transition/AutoTransition.java (renamed from core/java/android/view/transition/AutoTransition.java)16
-rw-r--r--core/java/android/transition/ChangeBounds.java (renamed from core/java/android/view/transition/Move.java)37
-rw-r--r--core/java/android/transition/Crossfade.java (renamed from core/java/android/view/transition/Crossfade.java)49
-rw-r--r--core/java/android/transition/Fade.java (renamed from core/java/android/view/transition/Fade.java)50
-rw-r--r--core/java/android/transition/Recolor.java (renamed from core/java/android/view/transition/Recolor.java)29
-rw-r--r--core/java/android/transition/Rotate.java (renamed from core/java/android/view/transition/Rotate.java)15
-rw-r--r--core/java/android/transition/Scene.java (renamed from core/java/android/view/transition/Scene.java)85
-rw-r--r--core/java/android/transition/Slide.java (renamed from core/java/android/view/transition/Slide.java)8
-rw-r--r--core/java/android/transition/TextChange.java (renamed from core/java/android/view/transition/TextChange.java)49
-rw-r--r--core/java/android/transition/Transition.java (renamed from core/java/android/view/transition/Transition.java)377
-rw-r--r--core/java/android/transition/TransitionInflater.java (renamed from core/java/android/view/transition/TransitionInflater.java)156
-rw-r--r--core/java/android/transition/TransitionManager.java (renamed from core/java/android/view/transition/TransitionManager.java)112
-rw-r--r--core/java/android/transition/TransitionSet.java (renamed from core/java/android/view/transition/TransitionGroup.java)218
-rw-r--r--core/java/android/transition/TransitionValues.java (renamed from core/java/android/view/transition/TransitionValues.java)6
-rw-r--r--core/java/android/transition/TransitionValuesMaps.java (renamed from core/java/android/view/transition/TransitionValuesMaps.java)2
-rw-r--r--core/java/android/transition/Visibility.java (renamed from core/java/android/view/transition/Visibility.java)80
-rw-r--r--core/java/android/transition/package.html (renamed from core/java/android/view/transition/package.html)11
-rw-r--r--core/java/android/util/MapCollections.java4
-rw-r--r--core/java/android/util/SuperNotCalledException.java27
-rw-r--r--core/java/android/view/GestureDetector.java20
-rw-r--r--core/java/android/view/InputDevice.java13
-rw-r--r--core/java/android/view/View.java116
-rw-r--r--core/java/android/view/ViewConfiguration.java18
-rw-r--r--core/java/android/view/ViewDebug.java39
-rw-r--r--core/java/android/view/ViewGroup.java13
-rw-r--r--core/java/android/view/ViewParent.java6
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java34
-rw-r--r--core/java/android/view/ViewRootImpl.java131
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java44
-rw-r--r--core/java/android/view/accessibility/CaptioningManager.java8
-rw-r--r--core/java/android/webkit/WebSettings.java7
-rw-r--r--core/java/android/webkit/WebView.java18
-rw-r--r--core/java/android/widget/AbsListView.java33
-rw-r--r--core/java/android/widget/ActivityChooserView.java30
-rw-r--r--core/java/android/widget/FastScroller.java95
-rw-r--r--core/java/android/widget/ListPopupWindow.java6
-rw-r--r--core/java/android/widget/ListView.java8
-rw-r--r--core/java/android/widget/PopupMenu.java6
-rw-r--r--core/java/android/widget/RelativeLayout.java19
-rw-r--r--core/java/android/widget/TextView.java4
-rw-r--r--core/java/android/widget/VideoView.java191
131 files changed, 4032 insertions, 3374 deletions
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 89accbb..129e52c 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -280,19 +280,9 @@ public abstract class Animator implements Cloneable {
}
/**
- * Gets the set of {@link AnimatorPauseListener} objects that are currently
- * listening for pause/resume events on this animator.
- *
- * @return ArrayList<AnimatorListener> The set of pause listeners.
- */
- public ArrayList<AnimatorPauseListener> getPauseListeners() {
- return mPauseListeners;
- }
-
- /**
- * Removes all listeners from this object. This is equivalent to calling
- * {@link #getListeners()} and {@link #getPauseListeners()} followed by calling
- * {@link ArrayList#clear()} on the returned lists of listeners.
+ * Removes all {@link #addListener(android.animation.Animator.AnimatorListener) listeners}
+ * and {@link #addPauseListener(android.animation.Animator.AnimatorPauseListener)
+ * pauseListeners} from this object.
*/
public void removeAllListeners() {
if (mListeners != null) {
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 5b1a7cf..43014ad 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -636,7 +636,7 @@ public class PropertyValuesHolder implements Cloneable {
}
/**
- * The TypeEvaluator will the automatically determined based on the type of values
+ * The TypeEvaluator will be automatically determined based on the type of values
* supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so
* desired. This may be important in cases where either the type of the values supplied
* do not match the way that they should be interpolated between, or if the values
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e02410a..57686a4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
package android.app;
import android.util.ArrayMap;
+import android.util.SuperNotCalledException;
import com.android.internal.app.ActionBarImpl;
import com.android.internal.policy.PolicyManager;
@@ -3436,6 +3437,12 @@ public class Activity extends ContextThemeWrapper
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
+
+ final View decor = mWindow != null ? mWindow.peekDecorView() : null;
+ if (decor != null) {
+ decor.cancelPendingInputEvents();
+ }
+ // TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 7c40bb1..2d28280 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2106,7 +2106,12 @@ public class ActivityManager {
}
// If the target is not exported, then nobody else can get to it.
if (!exported) {
- Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid);
+ /*
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid,
+ here);
+ */
return PackageManager.PERMISSION_DENIED;
}
if (permission == null) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 6d72114..653559d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -3377,7 +3377,7 @@ class ActivityManagerProxy implements IActivityManager
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(packageName);
- data.writeStrongBinder(observer.asBinder());
+ data.writeStrongBinder((observer != null) ? observer.asBinder() : null);
data.writeInt(userId);
mRemote.transact(CLEAR_APP_DATA_TRANSACTION, data, reply, 0);
reply.readException();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e6960b3..018fbe0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -76,6 +76,7 @@ import android.util.Log;
import android.util.LogPrinter;
import android.util.PrintWriterPrinter;
import android.util.Slog;
+import android.util.SuperNotCalledException;
import android.view.Display;
import android.view.HardwareRenderer;
import android.view.View;
@@ -116,12 +117,6 @@ import libcore.io.IoUtils;
import dalvik.system.CloseGuard;
-final class SuperNotCalledException extends AndroidRuntimeException {
- public SuperNotCalledException(String msg) {
- super(msg);
- }
-}
-
final class RemoteServiceException extends AndroidRuntimeException {
public RemoteServiceException(String msg) {
super(msg);
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 1a56826..5c3a3e5 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -101,7 +101,7 @@ public class AlarmManager
mService = service;
final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
- mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KEY_LIME_PIE);
+ mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
}
private long legacyExactLength() {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index fe09ce1..19a028d 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -616,6 +616,23 @@ public class AppOpsManager {
}
/**
+ * Do a quick check to validate if a package name belongs to a UID.
+ *
+ * @throws SecurityException if the package name doesn't belong to the given
+ * UID, or if ownership cannot be verified.
+ */
+ public void checkPackage(int uid, String packageName) {
+ try {
+ if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
+ throw new SecurityException(
+ "Package " + packageName + " does not belong to " + uid);
+ }
+ } catch (RemoteException e) {
+ throw new SecurityException("Unable to verify package ownership", e);
+ }
+ }
+
+ /**
* Make note of an application performing an operation. Note that you must pass
* in both the uid and name of the application to be checked; this function will verify
* that these two match, and if not, return {@link #MODE_IGNORED}. If this call
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f10290d..7ff7562 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -710,7 +710,7 @@ class ContextImpl extends Context {
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
SharedPreferencesImpl sp;
- synchronized (mSync) {
+ synchronized (ContextImpl.class) {
if (sSharedPrefs == null) {
sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();
}
@@ -726,7 +726,7 @@ class ContextImpl extends Context {
// name. This happened to work because when we generated the file name
// we would stringify it to "null.xml". Nice.
if (mPackageInfo.getApplicationInfo().targetSdkVersion <
- Build.VERSION_CODES.KEY_LIME_PIE) {
+ Build.VERSION_CODES.KITKAT) {
if (name == null) {
name = "null";
}
@@ -1453,7 +1453,7 @@ class ContextImpl extends Context {
public ComponentName startServiceAsUser(Intent service, UserHandle user) {
try {
if (service.getComponent() == null && service.getPackage() == null) {
- if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KEY_LIME_PIE) {
+ if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
Log.e(TAG, "This will become an error", ex);
@@ -1485,7 +1485,7 @@ class ContextImpl extends Context {
public boolean stopServiceAsUser(Intent service, UserHandle user) {
try {
if (service.getComponent() == null && service.getPackage() == null) {
- if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KEY_LIME_PIE) {
+ if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
Log.e(TAG, "This will become an error", ex);
@@ -1528,7 +1528,7 @@ class ContextImpl extends Context {
throw new RuntimeException("Not supported in system context");
}
if (service.getComponent() == null && service.getPackage() == null) {
- if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KEY_LIME_PIE) {
+ if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
Log.e(TAG, "This will become an error", ex);
@@ -1827,6 +1827,11 @@ class ContextImpl extends Context {
message);
}
+ /**
+ * Logs a warning if the system process directly called a method such as
+ * {@link #startService(Intent)} instead of {@link #startServiceAsUser(Intent, UserHandle)}.
+ * The "AsUser" variants allow us to properly enforce the user's restrictions.
+ */
private void warnIfCallingFromSystemProcess() {
if (Process.myUid() == Process.SYSTEM_UID) {
Slog.w(TAG, "Calling a method in the system process without a qualified user: "
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f8a1d82..d626e5f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -31,6 +31,7 @@ import android.util.AttributeSet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SuperNotCalledException;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index a7789d6..4371907 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -31,6 +31,7 @@ import android.util.DebugUtils;
import android.util.Log;
import android.util.LogWriter;
import android.util.SparseArray;
+import android.util.SuperNotCalledException;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index e062fa8..676fd1f 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -924,6 +924,42 @@ public final class BluetoothAdapter {
}
/**
+ * Create a listening, L2CAP Bluetooth socket.
+ * <p>A remote device connecting to this socket will optionally be
+ * authenticated and communication on this socket will optionally be
+ * encrypted.
+ * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
+ * connections from a listening {@link BluetoothServerSocket}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ * @param secure whether security and authentication are required
+ * @param fixedChannel whether we're looking for a PSM-based connection or a fixed channel
+ * @param channel L2CAP PSM or channel to use
+ * @return a listening L2CAP BluetoothServerSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions, or channel in use.
+ * @hide
+ */
+ public BluetoothServerSocket listenUsingL2CapOn(boolean secure, boolean fixedChannel,
+ int channel) throws IOException {
+ BluetoothServerSocket socket;
+
+ if (fixedChannel) {
+ channel |= BluetoothSocket.PORT_MASK_FIXED_CHAN;
+ }
+
+ socket = new BluetoothServerSocket(
+ BluetoothSocket.TYPE_L2CAP, secure, secure, channel);
+ int errno = socket.mSocket.bindListen();
+ if (errno != 0) {
+ //TODO(BT): Throw the same exception error code
+ // that the previous code was using.
+ //socket.mSocket.throwErrnoNative(errno);
+ throw new IOException("Error: " + errno);
+ }
+ return socket;
+ }
+
+ /**
* Create a listening, secure RFCOMM Bluetooth socket.
* <p>A remote device connecting to this socket will be authenticated and
* communication on this socket will be encrypted.
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 3acd9b0..2c85382 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1144,6 +1144,33 @@ public final class BluetoothDevice implements Parcelable {
return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
}
+
+ /**
+ * Construct a L2CAP socket ready to start an outgoing connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ *
+ * @param secure select whether security will be required
+ * @param fixedChannel select if this will be a "fixed channel" L2CAP connection
+ * or a PSM-based connection
+ * @param channel fixed channel or PSM to connect to
+ * @return a L2CAP BluetoothSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothSocket createL2CapSocket(boolean secure, boolean fixedChannel, int channel)
+ throws IOException {
+
+ if (fixedChannel) {
+ channel |= BluetoothSocket.PORT_MASK_FIXED_CHAN;
+ }
+
+ return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, secure, secure, this,
+ channel, null);
+ }
+
+
/**
* Check that a pin is valid and convert to byte array.
*
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index d10eaea..191bf67 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -103,6 +103,8 @@ public final class BluetoothSocket implements Closeable {
/*package*/ static final int SEC_FLAG_ENCRYPT = 1;
/*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
+ /*package*/ static final int PORT_MASK_FIXED_CHAN = 1 << 16;
+
private final int mType; /* one of TYPE_RFCOMM etc */
private BluetoothDevice mDevice; /* remote device */
private String mAddress; /* remote address */
@@ -115,7 +117,7 @@ public final class BluetoothSocket implements Closeable {
private LocalSocket mSocket;
private InputStream mSocketIS;
private OutputStream mSocketOS;
- private int mPort; /* RFCOMM channel or L2CAP psm */
+ private int mPort; /* RFCOMM channel or L2CAP psm/channel */
private int mFd;
private String mServiceName;
private static int PROXY_CONNECTION_TIMEOUT = 5000;
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index b9121c7..3438419 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -34,7 +34,6 @@ import android.os.ICancellationSignal;
import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.Process;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
@@ -102,6 +101,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
private boolean mExported;
private boolean mNoPerms;
+ private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();
+
private Transport mTransport = new Transport();
/**
@@ -194,8 +195,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
- return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
- CancellationSignal.fromTransport(cancellationSignal));
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.query(
+ uri, projection, selection, selectionArgs, sortOrder,
+ CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -208,7 +215,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectInsert(uri, initialValues);
}
- return ContentProvider.this.insert(uri, initialValues);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.insert(uri, initialValues);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -216,7 +228,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- return ContentProvider.this.bulkInsert(uri, initialValues);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.bulkInsert(uri, initialValues);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -238,7 +255,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
}
}
- return ContentProvider.this.applyBatch(operations);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.applyBatch(operations);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -246,7 +268,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- return ContentProvider.this.delete(uri, selection, selectionArgs);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.delete(uri, selection, selectionArgs);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -255,7 +282,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
if (enforceWritePermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return 0;
}
- return ContentProvider.this.update(uri, values, selection, selectionArgs);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.update(uri, values, selection, selectionArgs);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -263,8 +295,13 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- return ContentProvider.this.openFile(
- uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.openFile(
+ uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -272,13 +309,23 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, mode);
- return ContentProvider.this.openAssetFile(
- uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.openAssetFile(
+ uri, mode, CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
public Bundle call(String callingPkg, String method, String arg, Bundle extras) {
- return ContentProvider.this.callFromPackage(callingPkg, method, arg, extras);
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.call(method, arg, extras);
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
@@ -290,15 +337,46 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType,
Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException {
enforceFilePermission(callingPkg, uri, "r");
- return ContentProvider.this.openTypedAssetFile(
- uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.openTypedAssetFile(
+ uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
+ } finally {
+ setCallingPackage(original);
+ }
}
@Override
- public ICancellationSignal createCancellationSignal() throws RemoteException {
+ public ICancellationSignal createCancellationSignal() {
return CancellationSignal.createTransport();
}
+ @Override
+ public Uri canonicalize(String callingPkg, Uri uri) {
+ if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ return null;
+ }
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.canonicalize(uri);
+ } finally {
+ setCallingPackage(original);
+ }
+ }
+
+ @Override
+ public Uri uncanonicalize(String callingPkg, Uri uri) {
+ if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
+ return null;
+ }
+ final String original = setCallingPackage(callingPkg);
+ try {
+ return ContentProvider.this.uncanonicalize(uri);
+ } finally {
+ setCallingPackage(original);
+ }
+ }
+
private void enforceFilePermission(String callingPkg, Uri uri, String mode)
throws FileNotFoundException, SecurityException {
if (mode != null && mode.indexOf('w') != -1) {
@@ -461,6 +539,38 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
+ * Set the calling package, returning the current value (or {@code null})
+ * which can be used later to restore the previous state.
+ */
+ private String setCallingPackage(String callingPackage) {
+ final String original = mCallingPackage.get();
+ mCallingPackage.set(callingPackage);
+ return original;
+ }
+
+ /**
+ * Return the package name of the caller that initiated the request being
+ * processed on the current thread. The returned package will have been
+ * verified to belong to the calling UID. Returns {@code null} if not
+ * currently processing a request.
+ * <p>
+ * This will always return {@code null} when processing
+ * {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
+ *
+ * @see Binder#getCallingUid()
+ * @see Context#grantUriPermission(String, Uri, int)
+ * @throws SecurityException if the calling package doesn't belong to the
+ * calling UID.
+ */
+ public final String getCallingPackage() {
+ final String pkg = mCallingPackage.get();
+ if (pkg != null) {
+ mTransport.mAppOpsManager.checkPackage(Binder.getCallingUid(), pkg);
+ }
+ return pkg;
+ }
+
+ /**
* Change the permission required to read data from the content
* provider. This is normally set for you from its manifest information
* when the provider is first created.
@@ -529,8 +639,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
/** @hide */
public final void setAppOps(int readOp, int writeOp) {
if (!mNoPerms) {
- mTransport.mAppOpsManager = (AppOpsManager)mContext.getSystemService(
- Context.APP_OPS_SERVICE);
mTransport.mReadOp = readOp;
mTransport.mWriteOp = writeOp;
}
@@ -768,6 +876,56 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
public abstract String getType(Uri uri);
/**
+ * Implement this to support canonicalization of URIs that refer to your
+ * content provider. A canonical URI is one that can be transported across
+ * devices, backup/restore, and other contexts, and still be able to refer
+ * to the same data item. Typically this is implemented by adding query
+ * params to the URI allowing the content provider to verify that an incoming
+ * canonical URI references the same data as it was originally intended for and,
+ * if it doesn't, to find that data (if it exists) in the current environment.
+ *
+ * <p>For example, if the content provider holds people and a normal URI in it
+ * is created with a row index into that people database, the cananical representation
+ * may have an additional query param at the end which specifies the name of the
+ * person it is intended for. Later calls into the provider with that URI will look
+ * up the row of that URI's base index and, if it doesn't match or its entry's
+ * name doesn't match the name in the query param, perform a query on its database
+ * to find the correct row to operate on.</p>
+ *
+ * <p>If you implement support for canonical URIs, <b>all</b> incoming calls with
+ * URIs (including this one) must perform this verification and recovery of any
+ * canonical URIs they receive. In addition, you must also implement
+ * {@link #uncanonicalize} to strip the canonicalization of any of these URIs.</p>
+ *
+ * <p>The default implementation of this method returns null, indicating that
+ * canonical URIs are not supported.</p>
+ *
+ * @param url The Uri to canonicalize.
+ *
+ * @return Return the canonical representation of <var>url</var>, or null if
+ * canonicalization of that Uri is not supported.
+ */
+ public Uri canonicalize(Uri url) {
+ return null;
+ }
+
+ /**
+ * Remove canonicalization from canonical URIs previously returned by
+ * {@link #canonicalize}. For example, if your implementation is to add
+ * a query param to canonicalize a URI, this method can simply trip any
+ * query params on the URI. The default implementation always returns the
+ * same <var>url</var> that was passed in.
+ *
+ * @param url The Uri to remove any canonicalization from.
+ *
+ * @return Return the non-canonical representation of <var>url</var>, or return
+ * the <var>url</var> as-is if there is nothing to do. Never return null.
+ */
+ public Uri uncanonicalize(Uri url) {
+ return url;
+ }
+
+ /**
* @hide
* Implementation when a caller has performed an insert on the content
* provider, but that call has been rejected for the operation given
@@ -1413,6 +1571,8 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
*/
if (mContext == null) {
mContext = context;
+ mTransport.mAppOpsManager = (AppOpsManager) mContext.getSystemService(
+ Context.APP_OPS_SERVICE);
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
@@ -1452,15 +1612,6 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
}
/**
- * @hide
- * Front-end to {@link #call(String, String, android.os.Bundle)} that provides the name
- * of the calling package.
- */
- public Bundle callFromPackage(String callingPackag, String method, String arg, Bundle extras) {
- return call(method, arg, extras);
- }
-
- /**
* Call a provider-defined method. This can be used to implement
* interfaces that are cheaper and/or unnatural for a table-like
* model.
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 4e8dd82..e83c727 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -110,6 +110,30 @@ public class ContentProviderClient {
}
}
+ /** See {@link ContentProvider#canonicalize} */
+ public final Uri canonicalize(Uri url) throws RemoteException {
+ try {
+ return mContentProvider.canonicalize(mPackageName, url);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
+ }
+
+ /** See {@link ContentProvider#uncanonicalize} */
+ public final Uri uncanonicalize(Uri url) throws RemoteException {
+ try {
+ return mContentProvider.uncanonicalize(mPackageName, url);
+ } catch (DeadObjectException e) {
+ if (!mStable) {
+ mContentResolver.unstableProviderDied(mContentProvider);
+ }
+ throw e;
+ }
+ }
+
/** See {@link ContentProvider#insert ContentProvider.insert} */
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException {
@@ -320,7 +344,10 @@ public class ContentProviderClient {
/** {@hide} */
public static void closeQuietly(ContentProviderClient client) {
if (client != null) {
- client.release();
+ try {
+ client.release();
+ } catch (Exception ignored) {
+ }
}
}
}
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index 744e68c..bcf0b63 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -323,6 +323,30 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
reply.writeStrongBinder(cancellationSignal.asBinder());
return true;
}
+
+ case CANONICALIZE_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
+ Uri url = Uri.CREATOR.createFromParcel(data);
+
+ Uri out = canonicalize(callingPkg, url);
+ reply.writeNoException();
+ Uri.writeToParcel(reply, out);
+ return true;
+ }
+
+ case UNCANONICALIZE_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+ String callingPkg = data.readString();
+ Uri url = Uri.CREATOR.createFromParcel(data);
+
+ Uri out = uncanonicalize(callingPkg, url);
+ reply.writeNoException();
+ Uri.writeToParcel(reply, out);
+ return true;
+ }
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -685,5 +709,46 @@ final class ContentProviderProxy implements IContentProvider
}
}
+ public Uri canonicalize(String callingPkg, Uri url) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ data.writeString(callingPkg);
+ url.writeToParcel(data, 0);
+
+ mRemote.transact(IContentProvider.CANONICALIZE_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ Uri out = Uri.CREATOR.createFromParcel(reply);
+ return out;
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
+ public Uri uncanonicalize(String callingPkg, Uri url) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ data.writeString(callingPkg);
+ url.writeToParcel(data, 0);
+
+ mRemote.transact(IContentProvider.UNCANONICALIZE_TRANSACTION, data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ Uri out = Uri.CREATOR.createFromParcel(reply);
+ return out;
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 8a5a56c..e914604 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -497,6 +497,86 @@ public abstract class ContentResolver {
}
/**
+ * Transform the given <var>url</var> to a canonical representation of
+ * its referenced resource, which can be used across devices, persisted,
+ * backed up and restored, etc. The returned Uri is still a fully capable
+ * Uri for use with its content provider, allowing you to do all of the
+ * same content provider operations as with the original Uri --
+ * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc. The
+ * only difference in behavior between the original and new Uris is that
+ * the content provider may need to do some additional work at each call
+ * using it to resolve it to the correct resource, especially if the
+ * canonical Uri has been moved to a different environment.
+ *
+ * <p>If you are moving a canonical Uri between environments, you should
+ * perform another call to {@link #canonicalize} with that original Uri to
+ * re-canonicalize it for the current environment. Alternatively, you may
+ * want to use {@link #uncanonicalize} to transform it to a non-canonical
+ * Uri that works only in the current environment but potentially more
+ * efficiently than the canonical representation.</p>
+ *
+ * @param url The {@link Uri} that is to be transformed to a canonical
+ * representation. Like all resolver calls, the input can be either
+ * a non-canonical or canonical Uri.
+ *
+ * @return Returns the official canonical representation of <var>url</var>,
+ * or null if the content provider does not support a canonical representation
+ * of the given Uri. Many providers may not support canonicalization of some
+ * or all of their Uris.
+ *
+ * @see #uncanonicalize
+ */
+ public final Uri canonicalize(Uri url) {
+ IContentProvider provider = acquireProvider(url);
+ if (provider == null) {
+ return null;
+ }
+
+ try {
+ return provider.canonicalize(mPackageName, url);
+ } catch (RemoteException e) {
+ // Arbitrary and not worth documenting, as Activity
+ // Manager will kill this process shortly anyway.
+ return null;
+ } finally {
+ releaseProvider(provider);
+ }
+ }
+
+ /**
+ * Given a canonical Uri previously generated by {@link #canonicalize}, convert
+ * it to its local non-canonical form. This can be useful in some cases where
+ * you know that you will only be using the Uri in the current environment and
+ * want to avoid any possible overhead when using it with the content
+ * provider.
+ *
+ * @param url The canonical {@link Uri} that is to be convered back to its
+ * non-canonical form.
+ *
+ * @return Returns the non-canonical representation of <var>url</var>. This
+ * function never returns null; if there is no conversion to be done, it returns
+ * the same Uri that was provided.
+ *
+ * @see #canonicalize
+ */
+ public final Uri uncanonicalize(Uri url) {
+ IContentProvider provider = acquireProvider(url);
+ if (provider == null) {
+ return null;
+ }
+
+ try {
+ return provider.uncanonicalize(mPackageName, url);
+ } catch (RemoteException e) {
+ // Arbitrary and not worth documenting, as Activity
+ // Manager will kill this process shortly anyway.
+ return null;
+ } finally {
+ releaseProvider(provider);
+ }
+ }
+
+ /**
* Open a stream on to the content associated with a content URI. If there
* is no data associated with the URI, FileNotFoundException is thrown.
*
@@ -1665,6 +1745,9 @@ public abstract class ContentResolver {
* @param extras any extras to pass to the SyncAdapter.
*/
public static void requestSync(Account account, String authority, Bundle extras) {
+ if (extras == null) {
+ throw new IllegalArgumentException("Must specify extras.");
+ }
SyncRequest request =
new SyncRequest.Builder()
.setSyncAdapter(account, authority)
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2ff9182..8df5bee 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -638,7 +638,7 @@ public abstract class Context {
* {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
* private_picture}
* <p>
- * Starting in {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, no
+ * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
* permissions are required for the owning application to read or write to
* this path. Otherwise, {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
* or {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} are required.
@@ -674,7 +674,7 @@ public abstract class Context {
* the device, including both emulated external storage and physical media
* slots. This does not include transient devices, such as USB flash drives.
* <p>
- * Starting in {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, no
+ * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
* permissions are required for the owning application to read or write to
* these paths.
* <p>
@@ -695,7 +695,7 @@ public abstract class Context {
* should ensure that multiple instances running under different users don't
* interfere with each other.
* <p>
- * Starting in {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, no
+ * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
* permissions are required for the owning application to read or write to
* this path. Otherwise,
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} or
@@ -713,7 +713,7 @@ public abstract class Context {
* the device, including both emulated external storage and physical media
* slots. This does not include transient devices, such as USB flash drives.
* <p>
- * Starting in {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, no
+ * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
* permissions are required for the owning application to read or write to
* this path.
* <p>
@@ -774,7 +774,7 @@ public abstract class Context {
* each user has their own isolated external storage. Applications only
* have access to the external storage for the user they're running as.</p>
* <p>
- * Starting in {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, no
+ * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
* permissions are required for the owning application to read or write to
* this path. Otherwise,
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} or
@@ -799,7 +799,7 @@ public abstract class Context {
* the device, including both emulated external storage and physical media
* slots. This does not include transient devices, such as USB flash drives.
* <p>
- * Starting in {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, no
+ * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no
* permissions are required for the owning application to read or write to
* these paths.
* <p>
@@ -1651,7 +1651,7 @@ public abstract class Context {
* should contain either contain the complete class name of a specific service
* implementation to start or a specific package name to target. If the
* Intent is less specified, it will either throw an {@link IllegalArgumentException}
- * (if the caller targets {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE} or later),
+ * (if the caller targets {@link android.os.Build.VERSION_CODES#KITKAT} or later),
* or which of multiple matching services it finds and uses will be undefined. If this service
* is not already running, it will be instantiated and started (creating a
* process for it if needed); if it is running then it remains running.
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 6ea8876..f92a404 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -59,6 +59,9 @@ public interface IContentProvider extends IInterface {
throws RemoteException;
public ICancellationSignal createCancellationSignal() throws RemoteException;
+ public Uri canonicalize(String callingPkg, Uri uri) throws RemoteException;
+ public Uri uncanonicalize(String callingPkg, Uri uri) throws RemoteException;
+
// Data interchange.
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri url, String mimeType,
@@ -80,4 +83,6 @@ public interface IContentProvider extends IInterface {
static final int GET_STREAM_TYPES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 21;
static final int OPEN_TYPED_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 22;
static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
+ static final int CANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 24;
+ static final int UNCANONICALIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 25;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index dfc0412..2f2aae4 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2469,16 +2469,19 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.GET_RESTRICTION_ENTRIES";
/**
+ * @hide
* Activity to challenge the user for a PIN that was configured when setting up
- * restrictions. Launch the activity using
+ * restrictions. Restrictions include blocking of apps and preventing certain user operations,
+ * controlled by {@link android.os.UserManager#setUserRestrictions(Bundle).
+ * Launch the activity using
* {@link android.app.Activity#startActivityForResult(Intent, int)} and check if the
* result is {@link android.app.Activity#RESULT_OK} for a successful response to the
* challenge.<p/>
* Before launching this activity, make sure that there is a PIN in effect, by calling
- * {@link android.os.UserManager#hasRestrictionsPin()}.
+ * {@link android.os.UserManager#hasRestrictionsChallenge()}.
*/
- public static final String ACTION_RESTRICTIONS_PIN_CHALLENGE =
- "android.intent.action.RESTRICTIONS_PIN_CHALLENGE";
+ public static final String ACTION_RESTRICTIONS_CHALLENGE =
+ "android.intent.action.RESTRICTIONS_CHALLENGE";
/**
* Sent the first time a user is starting, to allow system apps to
diff --git a/core/java/android/content/UndoManager.java b/core/java/android/content/UndoManager.java
index 1c2db47..e9ec5a4 100644
--- a/core/java/android/content/UndoManager.java
+++ b/core/java/android/content/UndoManager.java
@@ -50,6 +50,8 @@ import java.util.HashMap;
* undo/redo them without needing to impact edits in other objects; while
* within the larger document, all edits can be seen and the user must
* undo/redo them as a single stream.</p>
+ *
+ * @hide
*/
public class UndoManager {
private final HashMap<String, UndoOwner> mOwners = new HashMap<String, UndoOwner>();
diff --git a/core/java/android/content/UndoOperation.java b/core/java/android/content/UndoOperation.java
index 8084b1f..1ff32d4 100644
--- a/core/java/android/content/UndoOperation.java
+++ b/core/java/android/content/UndoOperation.java
@@ -23,6 +23,8 @@ import android.os.Parcelable;
* A single undoable operation. You must subclass this to implement the state
* and behavior for your operation. Instances of this class are placed and
* managed in an {@link UndoManager}.
+ *
+ * @hide
*/
public abstract class UndoOperation<DATA> implements Parcelable {
UndoOwner mOwner;
diff --git a/core/java/android/content/UndoOwner.java b/core/java/android/content/UndoOwner.java
index a279de6..d0cdc95 100644
--- a/core/java/android/content/UndoOwner.java
+++ b/core/java/android/content/UndoOwner.java
@@ -18,6 +18,8 @@ package android.content;
/**
* Representation of an owner of {@link UndoOperation} objects in an {@link UndoManager}.
+ *
+ * @hide
*/
public class UndoOwner {
final String mTag;
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 8154bca..b8ac3bf 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Printer;
@@ -437,20 +438,20 @@ public class ActivityInfo extends ComponentInfo
* native side given the bit we have assigned in ActivityInfo.
*/
public static int[] CONFIG_NATIVE_BITS = new int[] {
- 0x0001, // MNC
- 0x0002, // MCC
- 0x0004, // LOCALE
- 0x0008, // TOUCH SCREEN
- 0x0010, // KEYBOARD
- 0x0020, // KEYBOARD HIDDEN
- 0x0040, // NAVIGATION
- 0x0080, // ORIENTATION
- 0x0800, // SCREEN LAYOUT
- 0x1000, // UI MODE
- 0x0200, // SCREEN SIZE
- 0x2000, // SMALLEST SCREEN SIZE
- 0x0100, // DENSITY
- 0x4000, // LAYOUT DIRECTION
+ Configuration.NATIVE_CONFIG_MNC, // MNC
+ Configuration.NATIVE_CONFIG_MCC, // MCC
+ Configuration.NATIVE_CONFIG_LOCALE, // LOCALE
+ Configuration.NATIVE_CONFIG_TOUCHSCREEN, // TOUCH SCREEN
+ Configuration.NATIVE_CONFIG_KEYBOARD, // KEYBOARD
+ Configuration.NATIVE_CONFIG_KEYBOARD_HIDDEN, // KEYBOARD HIDDEN
+ Configuration.NATIVE_CONFIG_NAVIGATION, // NAVIGATION
+ Configuration.NATIVE_CONFIG_ORIENTATION, // ORIENTATION
+ Configuration.NATIVE_CONFIG_SCREEN_LAYOUT, // SCREEN LAYOUT
+ Configuration.NATIVE_CONFIG_UI_MODE, // UI MODE
+ Configuration.NATIVE_CONFIG_SCREEN_SIZE, // SCREEN SIZE
+ Configuration.NATIVE_CONFIG_SMALLEST_SCREEN_SIZE, // SMALLEST SCREEN SIZE
+ Configuration.NATIVE_CONFIG_DENSITY, // DENSITY
+ Configuration.NATIVE_CONFIG_LAYOUTDIR, // LAYOUT DIRECTION
};
/** @hide
* Convert Java change bits to native.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b432164..6760f49 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1311,6 +1311,9 @@ public class PackageParser {
// Just skip this tag
XmlUtils.skipCurrentTag(parser);
continue;
+ } else if (tagName.equals("supports-input")) {
+ XmlUtils.skipCurrentTag(parser);
+ continue;
} else if (tagName.equals("eat-comment")) {
// Just skip this tag
@@ -1861,7 +1864,8 @@ public class PackageParser {
}
String manageSpaceActivity = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity, 0);
+ com.android.internal.R.styleable.AndroidManifestApplication_manageSpaceActivity,
+ Configuration.NATIVE_CONFIG_VERSION);
if (manageSpaceActivity != null) {
ai.manageSpaceActivityName = buildClassName(pkgName, manageSpaceActivity,
outError);
@@ -1875,7 +1879,8 @@ public class PackageParser {
// backupAgent, killAfterRestore, and restoreAnyVersion are only relevant
// if backup is possible for the given application.
String backupAgent = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestApplication_backupAgent, 0);
+ com.android.internal.R.styleable.AndroidManifestApplication_backupAgent,
+ Configuration.NATIVE_CONFIG_VERSION);
if (backupAgent != null) {
ai.backupAgentName = buildClassName(pkgName, backupAgent, outError);
if (DEBUG_BACKUP) {
@@ -1996,7 +2001,8 @@ public class PackageParser {
if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
str = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity, 0);
+ com.android.internal.R.styleable.AndroidManifestApplication_taskAffinity,
+ Configuration.NATIVE_CONFIG_VERSION);
} else {
// Some older apps have been seen to use a resource reference
// here that on older builds was ignored (with a warning). We
@@ -2011,7 +2017,8 @@ public class PackageParser {
CharSequence pname;
if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
pname = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestApplication_process, 0);
+ com.android.internal.R.styleable.AndroidManifestApplication_process,
+ Configuration.NATIVE_CONFIG_VERSION);
} else {
// Some older apps have been seen to use a resource reference
// here that on older builds was ignored (with a warning). We
@@ -2275,7 +2282,8 @@ public class PackageParser {
a.info.applicationInfo.uiOptions);
String parentName = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName, 0);
+ com.android.internal.R.styleable.AndroidManifestActivity_parentActivityName,
+ Configuration.NATIVE_CONFIG_VERSION);
if (parentName != null) {
String parentClassName = buildClassName(a.info.packageName, parentName, outError);
if (outError[0] == null) {
@@ -2297,7 +2305,8 @@ public class PackageParser {
}
str = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity, 0);
+ com.android.internal.R.styleable.AndroidManifestActivity_taskAffinity,
+ Configuration.NATIVE_CONFIG_VERSION);
a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
owner.applicationInfo.taskAffinity, str, outError);
@@ -2506,7 +2515,8 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestActivityAlias);
String targetActivity = sa.getNonConfigurationString(
- com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity, 0);
+ com.android.internal.R.styleable.AndroidManifestActivityAlias_targetActivity,
+ Configuration.NATIVE_CONFIG_VERSION);
if (targetActivity == null) {
outError[0] = "<activity-alias> does not specify android:targetActivity";
sa.recycle();
@@ -2596,7 +2606,7 @@ public class PackageParser {
String parentName = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestActivityAlias_parentActivityName,
- 0);
+ Configuration.NATIVE_CONFIG_VERSION);
if (parentName != null) {
String parentClassName = buildClassName(a.info.packageName, parentName, outError);
if (outError[0] == null) {
@@ -3653,7 +3663,8 @@ public class PackageParser {
if (args.processRes != 0) {
CharSequence pname;
if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.FROYO) {
- pname = args.sa.getNonConfigurationString(args.processRes, 0);
+ pname = args.sa.getNonConfigurationString(args.processRes,
+ Configuration.NATIVE_CONFIG_VERSION);
} else {
// Some older apps have been seen to use a resource reference
// here that on older builds was ignored (with a warning). We
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 3f17dc4..3dc8717 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -52,7 +52,7 @@ public class ServiceInfo extends ComponentInfo
* Bit in {@link #flags}: If set,
* {@link android.app.Service#onProvideAssistData(android.os.Bundle)} will
* be called on the service when it is running in the foreground. Set from
- * the android.R.attr#provideAssistData attribute.
+ * the {@link android.R.attr#provideAssistData} attribute.
*/
public static final int FLAG_PROVIDE_ASSIST_DATA = 0x0004;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 0402eeb..48b6fca 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -544,7 +544,40 @@ public final class Configuration implements Parcelable, Comparable<Configuration
* @hide Internal book-keeping.
*/
public int seq;
-
+
+ /** @hide Native-specific bit mask for MCC config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_MCC = 0x0001;
+ /** @hide Native-specific bit mask for MNC config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_MNC = 0x0002;
+ /** @hide Native-specific bit mask for LOCALE config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_LOCALE = 0x0004;
+ /** @hide Native-specific bit mask for TOUCHSCREEN config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_TOUCHSCREEN = 0x0008;
+ /** @hide Native-specific bit mask for KEYBOARD config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_KEYBOARD = 0x0010;
+ /** @hide Native-specific bit mask for KEYBOARD_HIDDEN config; DO NOT USE UNLESS YOU
+ * ARE SURE. */
+ public static final int NATIVE_CONFIG_KEYBOARD_HIDDEN = 0x0020;
+ /** @hide Native-specific bit mask for NAVIGATION config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_NAVIGATION = 0x0040;
+ /** @hide Native-specific bit mask for ORIENTATION config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_ORIENTATION = 0x0080;
+ /** @hide Native-specific bit mask for DENSITY config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_DENSITY = 0x0100;
+ /** @hide Native-specific bit mask for SCREEN_SIZE config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_SCREEN_SIZE = 0x0200;
+ /** @hide Native-specific bit mask for VERSION config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_VERSION = 0x0400;
+ /** @hide Native-specific bit mask for SCREEN_LAYOUT config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_SCREEN_LAYOUT = 0x0800;
+ /** @hide Native-specific bit mask for UI_MODE config; DO NOT USE UNLESS YOU ARE SURE. */
+ public static final int NATIVE_CONFIG_UI_MODE = 0x1000;
+ /** @hide Native-specific bit mask for SMALLEST_SCREEN_SIZE config; DO NOT USE UNLESS YOU
+ * ARE SURE. */
+ public static final int NATIVE_CONFIG_SMALLEST_SCREEN_SIZE = 0x2000;
+ /** @hide Native-specific bit mask for LAYOUTDIR config ; DO NOT USE UNLESS YOU ARE SURE.*/
+ public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
+
/**
* Construct an invalid Configuration. You must call {@link #setToDefaults}
* for this object to be valid. {@more}
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 27dddd4..83d48aa 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -16,6 +16,7 @@
package android.content.res;
+import android.content.pm.ActivityInfo;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -170,8 +171,8 @@ public class TypedArray {
*
* @param index Index of attribute to retrieve.
* @param allowedChangingConfigs Bit mask of configurations from
- * ActivityInfo that are allowed to change.
- *
+ * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change.
+ *
* @return String holding string data. Any styling information is
* removed. Returns null if the attribute is not defined.
*/
diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java
index 2a0d9b9..5e107f2 100644
--- a/core/java/android/database/MatrixCursor.java
+++ b/core/java/android/database/MatrixCursor.java
@@ -186,7 +186,7 @@ public class MatrixCursor extends AbstractCursor {
* column value at a time. This follows the same ordering as the column
* names specified at cursor construction time.
* <li>Column and value pairs can be offered for possible inclusion using
- * {@link #offer(String, Object)}. If the cursor includes the given column,
+ * {@link #add(String, Object)}. If the cursor includes the given column,
* the value will be set for that column, otherwise the value is ignored.
* This approach is useful when matching data to a custom projection.
* </ul>
@@ -227,7 +227,7 @@ public class MatrixCursor extends AbstractCursor {
*
* @return this builder to support chaining
*/
- public RowBuilder offer(String columnName, Object value) {
+ public RowBuilder add(String columnName, Object value) {
for (int i = 0; i < columnNames.length; i++) {
if (columnName.equals(columnNames[i])) {
data[(row * columnCount) + i] = value;
diff --git a/core/java/android/hardware/FlushCompleteListener.java b/core/java/android/hardware/FlushCompleteListener.java
new file mode 100644
index 0000000..fbdf4c8
--- /dev/null
+++ b/core/java/android/hardware/FlushCompleteListener.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware;
+
+/**
+ * Used for receiving a notification when a flush() has been successfully completed.
+ */
+public interface FlushCompleteListener {
+ /**
+ * Called after flush() is completed. This flush() could have been initiated by this application
+ * or some other application. All the events in the batch at the point when the flush was called
+ * have been delivered to the applications registered for those sensor events.
+ * <p>
+ *
+ * @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called.
+ *
+ * @see android.hardware.SensorManager#flush(Sensor)
+ */
+ public void onFlushCompleted(Sensor sensor);
+}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 9bffdbe..89a5819 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -319,6 +319,8 @@ public final class Sensor {
private float mResolution;
private float mPower;
private int mMinDelay;
+ private int mFifoReservedEventCount;
+ private int mFifoMaxEventCount;
Sensor() {
}
@@ -381,6 +383,24 @@ public final class Sensor {
return mMinDelay;
}
+ /**
+ * @return Number of events reserved for this sensor in the batch mode FIFO. This gives a
+ * guarantee on the minimum number of events that can be batched.
+ */
+ public int getFifoReservedEventCount() {
+ return mFifoReservedEventCount;
+ }
+
+ /**
+ * @return Maximum number of events of this sensor that could be batched. If this value is zero
+ * it indicates that batch mode is not supported for this sensor. If other applications
+ * registered to batched sensors, the actual number of events that can be batched might be
+ * smaller because the hardware FiFo will be partially used to batch the other sensors.
+ */
+ public int getFifoMaxEventCount() {
+ return mFifoMaxEventCount;
+ }
+
/** @hide */
public int getHandle() {
return mHandle;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 30118f9..8a4aa1d 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -582,7 +582,7 @@ public abstract class SensorManager {
* @param sensor
* The {@link android.hardware.Sensor Sensor} to register to.
*
- * @param rate
+ * @param rateUs
* The rate {@link android.hardware.SensorEvent sensor events} are
* delivered at. This is only a hint to the system. Events may be
* received faster or slower than the specified rate. Usually events
@@ -603,13 +603,78 @@ public abstract class SensorManager {
*
* @throws IllegalArgumentException when sensor is null or a trigger sensor
*/
- public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) {
- return registerListener(listener, sensor, rate, null);
+ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs) {
+ return registerListener(listener, sensor, rateUs, null);
}
/**
- * Registers a {@link android.hardware.SensorEventListener
- * SensorEventListener} for the given sensor.
+ * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. If the
+ * underlying hardware does not support batch mode, this defaults to
+ * {@link #registerListener(SensorEventListener, Sensor, int)} and other parameters are
+ * ignored. In non-batch mode, all sensor events must be reported as soon as they are detected.
+ * While in batch mode, sensor events do not need to be reported as soon as they are detected.
+ * They can be temporarily stored in batches and reported in batches, as long as no event is
+ * delayed by more than "maxBatchReportLatency" microseconds. That is, all events since the
+ * previous batch are recorded and returned all at once. This allows to reduce the amount of
+ * interrupts sent to the SoC, and allows the SoC to switch to a lower power state (Idle) while
+ * the sensor is capturing and batching data.
+ * <p>
+ * Registering to a sensor in batch mode will not prevent the SoC from going to suspend mode. In
+ * this case, the sensor will continue to gather events and store it in a hardware FIFO. If the
+ * FIFO gets full before the AP wakes up again, some events will be lost, as the older events
+ * get overwritten by new events in the hardware FIFO. This can be avoided by holding a wake
+ * lock. If the application holds a wake lock, the SoC will not go to suspend mode, so no events
+ * will be lost, as the events will be reported before the FIFO gets full.
+ * </p>
+ * <p>
+ * Batching is always best effort. If a different application requests updates in continuous
+ * mode, this application will also get events in continuous mode. Batch mode updates can be
+ * unregistered by calling {@link #unregisterListener(SensorEventListener)}.
+ * </p>
+ * <p class="note">
+ * </p>
+ * Note: Don't use this method with a one shot trigger sensor such as
+ * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use
+ * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p>
+ *
+ * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object
+ * that will receive the sensor events.
+ * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
+ * @param rateUs The desired delay between two consecutive events in microseconds. This is only
+ * a hint to the system. Events may be received faster or slower than the specified
+ * rate. Usually events are received faster. Can be one of
+ * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
+ * {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in
+ * microseconds.
+ * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most
+ * maxBatchReportLatency microseconds. More events can be batched if this value is
+ * large. If this is set to zero, batch mode is disabled and events are delivered in
+ * continuous mode as soon as they are available which is equivalent to calling
+ * {@link #registerListener(SensorEventListener, Sensor, int)}.
+ * @param reservedFlags Always set to Zero.
+ * @param flushCompleteListener A {@link android.hardware.FlushCompleteListener
+ * FlushCompleteListener} object which is called when any application calls flush()
+ * on this sensor and all the events in the batch at the time of calling flush() are
+ * successfully delivered to the listeners.
+ * @return true if batch mode is successfully enabled for this sensor, false otherwise.
+ * @see #registerListener(SensorEventListener, Sensor, int)
+ * @see #unregisterListener(SensorEventListener)
+ * @see #flush(Sensor)
+ * @throws IllegalArgumentException when sensor or listener is null or a trigger sensor.
+ */
+ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
+ int maxBatchReportLatencyUs, int reservedFlags,
+ FlushCompleteListener flushCompleteListener) {
+ int delay = getDelay(rateUs);
+ return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs,
+ reservedFlags, flushCompleteListener);
+ }
+
+ /**
+ * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given
+ * sensor. Events are delivered in continuous mode as soon as they are available. To reduce the
+ * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int, int,
+ * FlushCompleteListener)} which enables batch mode for the sensor.
*
* <p class="note"></p>
* Note: Don't use this method with a one shot trigger sensor such as
@@ -624,7 +689,7 @@ public abstract class SensorManager {
* @param sensor
* The {@link android.hardware.Sensor Sensor} to register to.
*
- * @param rate
+ * @param rateUs
* The rate {@link android.hardware.SensorEvent sensor events} are
* delivered at. This is only a hint to the system. Events may be
* received faster or slower than the specified rate. Usually events
@@ -649,37 +714,59 @@ public abstract class SensorManager {
*
* @throws IllegalArgumentException when sensor is null or a trigger sensor
*/
- public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
+ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
Handler handler) {
if (listener == null || sensor == null) {
return false;
}
- int delay = -1;
- switch (rate) {
- case SENSOR_DELAY_FASTEST:
- delay = 0;
- break;
- case SENSOR_DELAY_GAME:
- delay = 20000;
- break;
- case SENSOR_DELAY_UI:
- delay = 66667;
- break;
- case SENSOR_DELAY_NORMAL:
- delay = 200000;
- break;
- default:
- delay = rate;
- break;
- }
+ int delay = getDelay(rateUs);
+ return registerListenerImpl(listener, sensor, delay, handler, 0, 0, null);
+ }
- return registerListenerImpl(listener, sensor, delay, handler);
+ /**
+ * Enables batch mode for a sensor with the given rate and maxBatchReportLatency.
+ * @param handler
+ * The {@link android.os.Handler Handler} the
+ * {@link android.hardware.SensorEvent sensor events} will be
+ * delivered to.
+ *
+ * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener)
+ */
+ public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs,
+ int maxBatchReportLatencyUs, int reservedFlags, Handler handler,
+ FlushCompleteListener flushCompleteListener) {
+ int delayUs = getDelay(rateUs);
+ return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs,
+ reservedFlags, flushCompleteListener);
}
/** @hide */
protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
- int delay, Handler handler);
+ int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags,
+ FlushCompleteListener flushCompleteListener);
+
+
+ /**
+ * Flushes the batch FIFO of the given sensor. If there are events in the FIFO of this sensor,
+ * they are returned as if the batch timeout has expired. Events are returned in the
+ * usual way through the SensorEventListener. This call doesn't effect the batch timeout for
+ * this sensor. This call is asynchronous and returns immediately. FlushCompleteListener is
+ * called after all the events in the batch at the time of calling this method have been
+ * delivered successfully.
+ * @param sensor
+ * The {@link android.hardware.Sensor Sensor} to flush.
+ * @return true if the flush is initiated successfully. false if the sensor isn't active
+ * i.e no application is registered for updates from this sensor.
+ * @see #registerListener(SensorEventListener, Sensor, int, int, int, FlushCompleteListener)
+ * @throws IllegalArgumentException when sensor is null or a trigger sensor.
+ */
+ public boolean flush(Sensor sensor) {
+ return flushImpl(sensor);
+ }
+
+ /** @hide */
+ protected abstract boolean flushImpl(Sensor sensor);
/**
* <p>
@@ -1079,15 +1166,15 @@ public abstract class SensorManager {
* <p>
* All three angles above are in <b>radians</b> and <b>positive</b> in the
* <b>counter-clockwise</b> direction.
- *
+ *
* @param R
* rotation matrix see {@link #getRotationMatrix}.
- *
+ *
* @param values
* an array of 3 floats to hold the result.
- *
+ *
* @return The array values passed as argument.
- *
+ *
* @see #getRotationMatrix(float[], float[], float[], float[])
* @see GeomagneticField
*/
@@ -1407,4 +1494,26 @@ public abstract class SensorManager {
return mLegacySensorManager;
}
}
+
+ private static int getDelay(int rate) {
+ int delay = -1;
+ switch (rate) {
+ case SENSOR_DELAY_FASTEST:
+ delay = 0;
+ break;
+ case SENSOR_DELAY_GAME:
+ delay = 20000;
+ break;
+ case SENSOR_DELAY_UI:
+ delay = 66667;
+ break;
+ case SENSOR_DELAY_NORMAL:
+ delay = 200000;
+ break;
+ default:
+ delay = rate;
+ break;
+ }
+ return delay;
+ }
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 852cf4a..9747f0d 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -93,30 +93,35 @@ public class SystemSensorManager extends SensorManager {
/** @hide */
@Override
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
- int delay, Handler handler)
- {
+ int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags,
+ FlushCompleteListener flushCompleteListener) {
+ if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
+ if (listener == null) throw new IllegalArgumentException("listener cannot be null");
+ if (reservedFlags != 0) throw new IllegalArgumentException("reservedFlags should be zero");
+ if (delayUs < 0) throw new IllegalArgumentException("rateUs should be positive");
+ if (maxBatchReportLatencyUs < 0)
+ throw new IllegalArgumentException("maxBatchReportLatencyUs should be positive");
+ // Trigger Sensors should use the requestTriggerSensor call.
+ if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT)
+ throw new IllegalArgumentException("Trigger Sensors cannot use registerListener");
+
// Invariants to preserve:
// - one Looper per SensorEventListener
// - one Looper per SensorEventQueue
// We map SensorEventListener to a SensorEventQueue, which holds the looper
- if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
-
- // Trigger Sensors should use the requestTriggerSensor call.
- if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) return false;
-
synchronized (mSensorListeners) {
SensorEventQueue queue = mSensorListeners.get(listener);
if (queue == null) {
Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
- queue = new SensorEventQueue(listener, looper, this);
- if (!queue.addSensor(sensor, delay)) {
+ queue = new SensorEventQueue(listener, looper, this, flushCompleteListener);
+ if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags)) {
queue.dispose();
return false;
}
mSensorListeners.put(listener, queue);
return true;
} else {
- return queue.addSensor(sensor, delay);
+ return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags);
}
}
}
@@ -157,14 +162,14 @@ public class SystemSensorManager extends SensorManager {
TriggerEventQueue queue = mTriggerListeners.get(listener);
if (queue == null) {
queue = new TriggerEventQueue(listener, mMainLooper, this);
- if (!queue.addSensor(sensor, 0)) {
+ if (!queue.addSensor(sensor, 0, 0, 0)) {
queue.dispose();
return false;
}
mTriggerListeners.put(listener, queue);
return true;
} else {
- return queue.addSensor(sensor, 0);
+ return queue.addSensor(sensor, 0, 0, 0);
}
}
}
@@ -195,6 +200,18 @@ public class SystemSensorManager extends SensorManager {
}
}
+ protected boolean flushImpl(Sensor sensor) {
+ if (sensor == null) throw new IllegalArgumentException("sensor cannot be null");
+ if(Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT)
+ throw new IllegalArgumentException("Trigger Sensors cannot call flush");
+
+ FlushEventQueue queue = new FlushEventQueue(mMainLooper, this);
+ if (queue.flushSensor(sensor) != 0) {
+ return false;
+ }
+ return true;
+ }
+
/*
* BaseEventQueue is the communication channel with the sensor service,
* SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
@@ -202,11 +219,12 @@ public class SystemSensorManager extends SensorManager {
*/
private static abstract class BaseEventQueue {
private native int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
-
float[] scratch);
- private static native int nativeEnableSensor(int eventQ, int handle, int us);
+ private static native int nativeEnableSensor(int eventQ, int handle, int rateUs,
+ int maxBatchReportLatencyUs, int reservedFlags);
private static native int nativeDisableSensor(int eventQ, int handle);
private static native void nativeDestroySensorEventQueue(int eventQ);
+ private static native int nativeFlushSensor(int eventQ, int handle);
private int nSensorEventQueue;
private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
@@ -225,7 +243,8 @@ public class SystemSensorManager extends SensorManager {
dispose(false);
}
- public boolean addSensor(Sensor sensor, int delay) {
+ public boolean addSensor(
+ Sensor sensor, int delayUs, int maxBatchReportLatencyUs, int reservedFlags) {
// Check if already present.
int handle = sensor.getHandle();
if (mActiveSensors.get(handle)) return false;
@@ -233,9 +252,13 @@ public class SystemSensorManager extends SensorManager {
// Get ready to receive events before calling enable.
mActiveSensors.put(handle, true);
addSensorEvent(sensor);
- if (enableSensor(sensor, delay) != 0) {
- removeSensor(sensor, false);
- return false;
+ if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs, reservedFlags) != 0) {
+ // Try continuous mode if batching fails.
+ if (maxBatchReportLatencyUs == 0 ||
+ maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0, 0) != 0) {
+ removeSensor(sensor, false);
+ return false;
+ }
}
return true;
}
@@ -268,6 +291,12 @@ public class SystemSensorManager extends SensorManager {
return false;
}
+ public int flushSensor(Sensor sensor) {
+ if (nSensorEventQueue == 0) throw new NullPointerException();
+ if (sensor == null) throw new NullPointerException();
+ return nativeFlushSensor(nSensorEventQueue, sensor.getHandle());
+ }
+
public boolean hasSensors() {
// no more sensors are set
return mActiveSensors.indexOfValue(true) >= 0;
@@ -295,11 +324,14 @@ public class SystemSensorManager extends SensorManager {
}
}
- private int enableSensor(Sensor sensor, int us) {
+ private int enableSensor(
+ Sensor sensor, int rateUs, int maxBatchReportLatencyUs, int reservedFlags) {
if (nSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
- return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us);
+ return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,
+ maxBatchReportLatencyUs, reservedFlags);
}
+
private int disableSensor(Sensor sensor) {
if (nSensorEventQueue == 0) throw new NullPointerException();
if (sensor == null) throw new NullPointerException();
@@ -307,6 +339,7 @@ public class SystemSensorManager extends SensorManager {
}
protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy,
long timestamp);
+ protected abstract void dispatchFlushCompleteEvent(int handle);
protected abstract void addSensorEvent(Sensor sensor);
protected abstract void removeSensorEvent(Sensor sensor);
@@ -314,12 +347,14 @@ public class SystemSensorManager extends SensorManager {
static final class SensorEventQueue extends BaseEventQueue {
private final SensorEventListener mListener;
+ private final FlushCompleteListener mFlushCompleteListener;
private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();
public SensorEventQueue(SensorEventListener listener, Looper looper,
- SystemSensorManager manager) {
+ SystemSensorManager manager, FlushCompleteListener flushCompleteListener) {
super(looper, manager);
mListener = listener;
+ mFlushCompleteListener = flushCompleteListener;
}
public void addSensorEvent(Sensor sensor) {
@@ -370,6 +405,15 @@ public class SystemSensorManager extends SensorManager {
}
mListener.onSensorChanged(t);
}
+
+ @SuppressWarnings("unused")
+ protected void dispatchFlushCompleteEvent(int handle) {
+ final Sensor sensor = sHandleToSensor.get(handle);
+ if (mFlushCompleteListener != null) {
+ mFlushCompleteListener.onFlushCompleted(sensor);
+ }
+ return;
+ }
}
static final class TriggerEventQueue extends BaseEventQueue {
@@ -415,5 +459,35 @@ public class SystemSensorManager extends SensorManager {
mListener.onTrigger(t);
}
+
+ @SuppressWarnings("unused")
+ protected void dispatchFlushCompleteEvent(int handle) {
+ }
+ }
+
+ static final class FlushEventQueue extends BaseEventQueue {
+ public FlushEventQueue(Looper looper, SystemSensorManager manager) {
+ super(looper, manager);
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
+ long timestamp) {
+ }
+
+ @Override
+ @SuppressWarnings("unused")
+ protected void addSensorEvent(Sensor sensor) {
+ }
+
+ @Override
+ @SuppressWarnings("unused")
+ protected void removeSensorEvent(Sensor sensor) {
+ }
+
+ @SuppressWarnings("unused")
+ protected void dispatchFlushCompleteEvent(int handle) {
+ }
}
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 8b5bf4a..7735146 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -182,7 +182,7 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
/**
* <p>
- * When android.sensor.awbMode is not OFF, TRANSFORM_MATRIX
+ * When android.control.awbMode is not OFF, TRANSFORM_MATRIX
* should be ignored.
* </p>
* @see #COLOR_CORRECTION_MODE_TRANSFORM_MATRIX
@@ -303,13 +303,14 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* </p>
* <p>
* Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight.
+ * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * specified coordinates.
* </p><p>
* The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left of the active pixel array, and
- * (android.sensor.info.activeArraySize.width,
- * android.sensor.info.activeArraySize.height) being the
- * bottom-right point of the active pixel array. The weight
+ * with (0,0) being the top-left pixel in the active pixel array, and
+ * (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1) being the
+ * bottom-right pixel in the active pixel array. The weight
* should be nonnegative.
* </p><p>
* If all regions have 0 weight, then no specific metering area
@@ -378,13 +379,14 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* </p>
* <p>
* Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight.
+ * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * specified coordinates.
* </p><p>
* The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left of the active pixel array, and
- * (android.sensor.info.activeArraySize.width,
- * android.sensor.info.activeArraySize.height) being the
- * bottom-right point of the active pixel array. The weight
+ * with (0,0) being the top-left pixel in the active pixel array, and
+ * (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1) being the
+ * bottom-right pixel in the active pixel array. The weight
* should be nonnegative.
* </p><p>
* If all regions have 0 weight, then no specific focus area
@@ -462,12 +464,15 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable {
* <p>
* Only used in AUTO mode.
* </p><p>
- * Each area is a rectangle plus weight: xmin, ymin, xmax,
- * ymax, weight. The coordinate system is based on the active
- * pixel array, with (0,0) being the top-left of the active
- * pixel array, and (android.sensor.info.activeArraySize.width,
- * android.sensor.info.activeArraySize.height) being the
- * bottom-right point of the active pixel array. The weight
+ * Each area is a rectangle plus weight: xmin, ymin,
+ * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * specified coordinates.
+ * </p><p>
+ * The coordinate system is based on the active pixel array,
+ * with (0,0) being the top-left pixel in the active pixel array, and
+ * (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1) being the
+ * bottom-right pixel in the active pixel array. The weight
* should be nonnegative.
* </p><p>
* If all regions have 0 weight, then no specific metering area
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index ef6aaa0..bd151a2 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -198,13 +198,14 @@ public final class CaptureResult extends CameraMetadata {
* </p>
* <p>
* Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight.
+ * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * specified coordinates.
* </p><p>
* The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left of the active pixel array, and
- * (android.sensor.info.activeArraySize.width,
- * android.sensor.info.activeArraySize.height) being the
- * bottom-right point of the active pixel array. The weight
+ * with (0,0) being the top-left pixel in the active pixel array, and
+ * (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1) being the
+ * bottom-right pixel in the active pixel array. The weight
* should be nonnegative.
* </p><p>
* If all regions have 0 weight, then no specific metering area
@@ -258,13 +259,14 @@ public final class CaptureResult extends CameraMetadata {
* </p>
* <p>
* Each area is a rectangle plus weight: xmin, ymin,
- * xmax, ymax, weight.
+ * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * specified coordinates.
* </p><p>
* The coordinate system is based on the active pixel array,
- * with (0,0) being the top-left of the active pixel array, and
- * (android.sensor.info.activeArraySize.width,
- * android.sensor.info.activeArraySize.height) being the
- * bottom-right point of the active pixel array. The weight
+ * with (0,0) being the top-left pixel in the active pixel array, and
+ * (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1) being the
+ * bottom-right pixel in the active pixel array. The weight
* should be nonnegative.
* </p><p>
* If all regions have 0 weight, then no specific focus area
@@ -342,12 +344,15 @@ public final class CaptureResult extends CameraMetadata {
* <p>
* Only used in AUTO mode.
* </p><p>
- * Each area is a rectangle plus weight: xmin, ymin, xmax,
- * ymax, weight. The coordinate system is based on the active
- * pixel array, with (0,0) being the top-left of the active
- * pixel array, and (android.sensor.info.activeArraySize.width,
- * android.sensor.info.activeArraySize.height) being the
- * bottom-right point of the active pixel array. The weight
+ * Each area is a rectangle plus weight: xmin, ymin,
+ * xmax, ymax, weight. The rectangle is defined inclusive of the
+ * specified coordinates.
+ * </p><p>
+ * The coordinate system is based on the active pixel array,
+ * with (0,0) being the top-left pixel in the active pixel array, and
+ * (android.sensor.info.activeArraySize.width - 1,
+ * android.sensor.info.activeArraySize.height - 1) being the
+ * bottom-right pixel in the active pixel array. The weight
* should be nonnegative.
* </p><p>
* If all regions have 0 weight, then no specific metering area
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/hardware/camera2/Rational.java
index 0260e02..77b8c26 100644
--- a/core/java/android/hardware/camera2/Rational.java
+++ b/core/java/android/hardware/camera2/Rational.java
@@ -26,22 +26,17 @@ public final class Rational {
/**
* <p>Create a Rational with a given numerator and denominator.</p>
*
- * <p>
- * The signs of the numerator and the denominator may be flipped such that the denominator
- * is always 0.
- * </p>
+ * <p>The signs of the numerator and the denominator may be flipped such that the denominator
+ * is always positive.</p>
+ *
+ * <p>A rational value with a 0-denominator may be constructed, but will have similar semantics
+ * as float NaN and INF values. The int getter functions return 0 in this case.</p>
*
* @param numerator the numerator of the rational
* @param denominator the denominator of the rational
- *
- * @throws IllegalArgumentException if the denominator is 0
*/
public Rational(int numerator, int denominator) {
- if (denominator == 0) {
- throw new IllegalArgumentException("Argument 'denominator' is 0");
- }
-
if (denominator < 0) {
numerator = -numerator;
denominator = -denominator;
@@ -55,6 +50,9 @@ public final class Rational {
* Gets the numerator of the rational.
*/
public int getNumerator() {
+ if (mDenominator == 0) {
+ return 0;
+ }
return mNumerator;
}
@@ -65,22 +63,41 @@ public final class Rational {
return mDenominator;
}
+ private boolean isNaN() {
+ return mDenominator == 0 && mNumerator == 0;
+ }
+
+ private boolean isInf() {
+ return mDenominator == 0 && mNumerator > 0;
+ }
+
+ private boolean isNegInf() {
+ return mDenominator == 0 && mNumerator < 0;
+ }
+
/**
* <p>Compare this Rational to another object and see if they are equal.</p>
*
* <p>A Rational object can only be equal to another Rational object (comparing against any other
* type will return false).</p>
*
- * <p>A Rational object is considered equal to another Rational object if and only if their
- * reduced forms have the same numerator and denominator.</p>
+ * <p>A Rational object is considered equal to another Rational object if and only if one of
+ * the following holds</p>:
+ * <ul><li>Both are NaN</li>
+ * <li>Both are infinities of the same sign</li>
+ * <li>Both have the same numerator and denominator in their reduced form</li>
+ * </ul>
*
* <p>A reduced form of a Rational is calculated by dividing both the numerator and the
* denominator by their greatest common divisor.</p>
*
* <pre>
- * (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true
- * (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false
- * (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction
+ * (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true
+ * (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false
+ * (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction
+ * (new Rational(0, 0)).equals(new Rational(0, 0)) == true // NaN.equals(NaN)
+ * (new Rational(1, 0)).equals(new Rational(5, 0)) == true // both are +infinity
+ * (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
* </pre>
*
* @param obj a reference to another object
@@ -91,13 +108,17 @@ public final class Rational {
public boolean equals(Object obj) {
if (obj == null) {
return false;
- }
- if (this == obj) {
- return true;
- }
- if (obj instanceof Rational) {
+ } else if (obj instanceof Rational) {
Rational other = (Rational) obj;
- if(mNumerator == other.mNumerator && mDenominator == other.mDenominator) {
+ if (mDenominator == 0 || other.mDenominator == 0) {
+ if (isNaN() && other.isNaN()) {
+ return true;
+ } else if (isInf() && other.isInf() || isNegInf() && other.isNegInf()) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (mNumerator == other.mNumerator && mDenominator == other.mDenominator) {
return true;
} else {
int thisGcd = gcd();
@@ -117,7 +138,25 @@ public final class Rational {
@Override
public String toString() {
- return mNumerator + "/" + mDenominator;
+ if (isNaN()) {
+ return "NaN";
+ } else if (isInf()) {
+ return "Infinity";
+ } else if (isNegInf()) {
+ return "-Infinity";
+ } else {
+ return mNumerator + "/" + mDenominator;
+ }
+ }
+
+ /**
+ * <p>Convert to a floating point representation.</p>
+ *
+ * @return The floating point representation of this rational number.
+ * @hide
+ */
+ public float toFloat() {
+ return (float) mNumerator / (float) mDenominator;
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 64e4dc9..86a073f 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -301,7 +301,9 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice {
synchronized (mLock) {
try {
- mRemoteDevice.disconnect();
+ if (mRemoteDevice != null) {
+ mRemoteDevice.disconnect();
+ }
} catch (CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
index fbe7ff4..2c05c58 100644
--- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
+++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
@@ -49,7 +49,7 @@ public class CameraBinderDecorator {
public static final int EACCES = -13;
public static final int EBUSY = -16;
public static final int ENODEV = -19;
- public static final int ENOTSUP = -129;
+ public static final int EOPNOTSUPP = -95;
private static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
@@ -86,7 +86,7 @@ public class CameraBinderDecorator {
case ENODEV:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_DISCONNECTED));
- case ENOTSUP:
+ case EOPNOTSUPP:
UncheckedThrow.throwAnyException(new CameraRuntimeException(
CAMERA_DEPRECATED_HAL));
}
diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java
index c39488e..476fefe 100644
--- a/core/java/android/net/BaseNetworkStateTracker.java
+++ b/core/java/android/net/BaseNetworkStateTracker.java
@@ -103,7 +103,7 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
}
@Override
- public LinkInfo getLinkInfo() {
+ public LinkQualityInfo getLinkQualityInfo() {
return null;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3874369..4cf38b6 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1426,9 +1426,9 @@ public class ConnectivityManager {
* get the information about a specific network link
* @hide
*/
- public LinkInfo getLinkInfo(int networkType) {
+ public LinkQualityInfo getLinkQualityInfo(int networkType) {
try {
- LinkInfo li = mService.getLinkInfo(networkType);
+ LinkQualityInfo li = mService.getLinkQualityInfo(networkType);
return li;
} catch (RemoteException e) {
return null;
@@ -1439,9 +1439,9 @@ public class ConnectivityManager {
* get the information of currently active network link
* @hide
*/
- public LinkInfo getActiveLinkInfo() {
+ public LinkQualityInfo getActiveLinkQualityInfo() {
try {
- LinkInfo li = mService.getActiveLinkInfo();
+ LinkQualityInfo li = mService.getActiveLinkQualityInfo();
return li;
} catch (RemoteException e) {
return null;
@@ -1452,9 +1452,9 @@ public class ConnectivityManager {
* get the information of all network links
* @hide
*/
- public LinkInfo[] getAllLinkInfo() {
+ public LinkQualityInfo[] getAllLinkQualityInfo() {
try {
- LinkInfo[] li = mService.getAllLinkInfo();
+ LinkQualityInfo[] li = mService.getAllLinkQualityInfo();
return li;
} catch (RemoteException e) {
return null;
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index c07e900..a6f10ec 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -16,7 +16,7 @@
package android.net;
-import android.net.LinkInfo;
+import android.net.LinkQualityInfo;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
@@ -149,11 +149,11 @@ interface IConnectivityManager
String getMobileRedirectedProvisioningUrl();
- LinkInfo getLinkInfo(int networkType);
+ LinkQualityInfo getLinkQualityInfo(int networkType);
- LinkInfo getActiveLinkInfo();
+ LinkQualityInfo getActiveLinkQualityInfo();
- LinkInfo[] getAllLinkInfo();
+ LinkQualityInfo[] getAllLinkQualityInfo();
void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
}
diff --git a/core/java/android/net/LinkInfo.java b/core/java/android/net/LinkInfo.java
deleted file mode 100644
index 47b8a95..0000000
--- a/core/java/android/net/LinkInfo.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2013 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.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Class that represents useful attributes of generic network links
- * such as the upload/download throughput or packet error rate.
- * Generally speaking, you should be dealing with instances of
- * LinkInfo subclasses, such as {@link android.net.#WifiLinkInfo}
- * or {@link android.net.#MobileLinkInfo} which provide additional
- * information.
- * @hide
- */
-public class LinkInfo implements Parcelable
-{
- public static final int UNKNOWN = -1;
-
- public static final int NORMALIZED_MIN_SIGNAL_STRENGTH = 0;
-
- public static final int NORMALIZED_MAX_SIGNAL_STRENGTH = 99;
-
- public static final int NORMALIZED_SIGNAL_STRENGTH_RANGE = NORMALIZED_MAX_SIGNAL_STRENGTH + 1;
-
- /* Network type as defined by ConnectivityManager */
- public int mNetworkType = ConnectivityManager.TYPE_NONE;
-
- public int mNormalizedSignalStrength = UNKNOWN;
-
- public long mPacketCount = UNKNOWN;
- public long mPacketErrorCount = UNKNOWN;
- public int mTheoreticalTxBandwidth = UNKNOWN;
- public int mTheoreticalRxBandwidth = UNKNOWN;
- public int mTheoreticalLatency = UNKNOWN;
-
- /* Timestamp when last sample was made available */
- public long mLastDataSampleTime = UNKNOWN;
-
- /* Sample duration in millisecond */
- public int mDataSampleDuration = UNKNOWN;
-
- public LinkInfo() {
-
- }
-
- /**
- * Implement the Parcelable interface
- * @hide
- */
- public int describeContents() {
- return 0;
- }
- /**
- * Implement the Parcelable interface.
- */
-
- protected static final int OBJECT_TYPE_LINKINFO = 1;
- protected static final int OBJECT_TYPE_WIFI_LINKINFO = 2;
- protected static final int OBJECT_TYPE_MOBILE_LINKINFO = 3;
-
- public void writeToParcel(Parcel dest, int flags) {
- writeToParcel(dest, flags, OBJECT_TYPE_LINKINFO);
- }
-
- public void writeToParcel(Parcel dest, int flags, int objectType) {
- dest.writeInt(objectType);
- dest.writeInt(mNetworkType);
- dest.writeInt(mNormalizedSignalStrength);
- dest.writeLong(mPacketCount);
- dest.writeLong(mPacketErrorCount);
- dest.writeInt(mTheoreticalTxBandwidth);
- dest.writeInt(mTheoreticalRxBandwidth);
- dest.writeInt(mTheoreticalLatency);
- dest.writeLong(mLastDataSampleTime);
- dest.writeInt(mDataSampleDuration);
- }
-
- public static final Creator<LinkInfo> CREATOR =
- new Creator<LinkInfo>() {
- public LinkInfo createFromParcel(Parcel in) {
- int objectType = in.readInt();
- if (objectType == OBJECT_TYPE_LINKINFO) {
- LinkInfo li = new LinkInfo();
- li.initializeFromParcel(in);
- return li;
- } else if (objectType == OBJECT_TYPE_WIFI_LINKINFO) {
- return WifiLinkInfo.createFromParcelBody(in);
- } else if (objectType == OBJECT_TYPE_MOBILE_LINKINFO) {
- return MobileLinkInfo.createFromParcelBody(in);
- } else {
- return null;
- }
- }
-
- public LinkInfo[] newArray(int size) {
- return new LinkInfo[size];
- }
- };
-
- protected void initializeFromParcel(Parcel in) {
- mNetworkType = in.readInt();
- mNormalizedSignalStrength = in.readInt();
- mPacketCount = in.readLong();
- mPacketErrorCount = in.readLong();
- mTheoreticalTxBandwidth = in.readInt();
- mTheoreticalRxBandwidth = in.readInt();
- mTheoreticalLatency = in.readInt();
- mLastDataSampleTime = in.readLong();
- mDataSampleDuration = in.readInt();
- }
-
-}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 1f73c4a..b4d07a1 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -66,6 +66,7 @@ public class LinkProperties implements Parcelable {
private String mDomains;
private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
private ProxyProperties mHttpProxy;
+ private int mMtu;
// Stores the properties of links that are "stacked" above this link.
// Indexed by interface name to allow modification and to prevent duplicates being added.
@@ -104,6 +105,7 @@ public class LinkProperties implements Parcelable {
for (LinkProperties l: source.mStackedLinks.values()) {
addStackedLink(l);
}
+ setMtu(source.getMtu());
}
}
@@ -197,6 +199,16 @@ public class LinkProperties implements Parcelable {
return addresses;
}
+ /**
+ * Replaces the LinkAddresses on this link with the given collection of addresses.
+ */
+ public void setLinkAddresses(Collection<LinkAddress> addresses) {
+ mLinkAddresses.clear();
+ for (LinkAddress address: addresses) {
+ addLinkAddress(address);
+ }
+ }
+
public void addDns(InetAddress dns) {
if (dns != null) mDnses.add(dns);
}
@@ -213,6 +225,14 @@ public class LinkProperties implements Parcelable {
mDomains = domains;
}
+ public void setMtu(int mtu) {
+ mMtu = mtu;
+ }
+
+ public int getMtu() {
+ return mMtu;
+ }
+
private RouteInfo routeWithInterface(RouteInfo route) {
return new RouteInfo(
route.getDestination(),
@@ -312,6 +332,7 @@ public class LinkProperties implements Parcelable {
mRoutes.clear();
mHttpProxy = null;
mStackedLinks.clear();
+ mMtu = 0;
}
/**
@@ -336,6 +357,8 @@ public class LinkProperties implements Parcelable {
String domainName = "Domains: " + mDomains;
+ String mtu = "MTU: " + mMtu;
+
String routes = " Routes: [";
for (RouteInfo route : mRoutes) routes += route.toString() + ",";
routes += "] ";
@@ -349,7 +372,8 @@ public class LinkProperties implements Parcelable {
}
stacked += "] ";
}
- return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}";
+ return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu
+ + proxy + stacked + "}";
}
/**
@@ -464,6 +488,16 @@ public class LinkProperties implements Parcelable {
return true;
}
+ /**
+ * Compares this {@code LinkProperties} MTU against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalMtu(LinkProperties target) {
+ return getMtu() == target.getMtu();
+ }
+
@Override
/**
* Compares this {@code LinkProperties} instance against the target
@@ -495,7 +529,8 @@ public class LinkProperties implements Parcelable {
isIdenticalDnses(target) &&
isIdenticalRoutes(target) &&
isIdenticalHttpProxy(target) &&
- isIdenticalStackedLinks(target);
+ isIdenticalStackedLinks(target) &&
+ isIdenticalMtu(target);
}
/**
@@ -597,7 +632,8 @@ public class LinkProperties implements Parcelable {
+ ((null == mDomains) ? 0 : mDomains.hashCode())
+ mRoutes.size() * 41
+ ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
- + mStackedLinks.hashCode() * 47);
+ + mStackedLinks.hashCode() * 47)
+ + mMtu * 51;
}
/**
@@ -615,7 +651,7 @@ public class LinkProperties implements Parcelable {
dest.writeByteArray(d.getAddress());
}
dest.writeString(mDomains);
-
+ dest.writeInt(mMtu);
dest.writeInt(mRoutes.size());
for(RouteInfo route : mRoutes) {
dest.writeParcelable(route, flags);
@@ -654,6 +690,7 @@ public class LinkProperties implements Parcelable {
} catch (UnknownHostException e) { }
}
netProp.setDomains(in.readString());
+ netProp.setMtu(in.readInt());
addressCount = in.readInt();
for (int i=0; i<addressCount; i++) {
netProp.addRoute((RouteInfo)in.readParcelable(null));
diff --git a/core/java/android/net/LinkInfo.aidl b/core/java/android/net/LinkQualityInfo.aidl
index 716674b..5e072bf 100644
--- a/core/java/android/net/LinkInfo.aidl
+++ b/core/java/android/net/LinkQualityInfo.aidl
@@ -16,4 +16,4 @@
package android.net;
-parcelable LinkInfo;
+parcelable LinkQualityInfo;
diff --git a/core/java/android/net/LinkQualityInfo.java b/core/java/android/net/LinkQualityInfo.java
new file mode 100644
index 0000000..9c8e61d
--- /dev/null
+++ b/core/java/android/net/LinkQualityInfo.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2013 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.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Class that represents useful attributes of generic network links
+ * such as the upload/download throughput or packet error rate.
+ * Generally speaking, you should be dealing with instances of
+ * LinkQualityInfo subclasses, such as {@link android.net.#WifiLinkQualityInfo}
+ * or {@link android.net.#MobileLinkQualityInfo} which provide additional
+ * information.
+ * @hide
+ */
+public class LinkQualityInfo implements Parcelable {
+
+ /**
+ * Represents a value that you can use to test if an integer field is set to a good value
+ */
+ public static final int UNKNOWN_INT = Integer.MAX_VALUE;
+
+ /**
+ * Represents a value that you can use to test if a long field is set to a good value
+ */
+ public static final long UNKNOWN_LONG = Long.MAX_VALUE;
+
+ public static final int NORMALIZED_MIN_SIGNAL_STRENGTH = 0;
+
+ public static final int NORMALIZED_MAX_SIGNAL_STRENGTH = 99;
+
+ public static final int NORMALIZED_SIGNAL_STRENGTH_RANGE =
+ NORMALIZED_MAX_SIGNAL_STRENGTH - NORMALIZED_MIN_SIGNAL_STRENGTH + 1;
+
+ /* Network type as defined by ConnectivityManager */
+ private int mNetworkType = ConnectivityManager.TYPE_NONE;
+
+ private int mNormalizedSignalStrength = UNKNOWN_INT;
+
+ private long mPacketCount = UNKNOWN_LONG;
+ private long mPacketErrorCount = UNKNOWN_LONG;
+ private int mTheoreticalTxBandwidth = UNKNOWN_INT;
+ private int mTheoreticalRxBandwidth = UNKNOWN_INT;
+ private int mTheoreticalLatency = UNKNOWN_INT;
+
+ /* Timestamp when last sample was made available */
+ private long mLastDataSampleTime = UNKNOWN_LONG;
+
+ /* Sample duration in millisecond */
+ private int mDataSampleDuration = UNKNOWN_INT;
+
+ public LinkQualityInfo() {
+
+ }
+
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ */
+
+ protected static final int OBJECT_TYPE_LINK_QUALITY_INFO = 1;
+ protected static final int OBJECT_TYPE_WIFI_LINK_QUALITY_INFO = 2;
+ protected static final int OBJECT_TYPE_MOBILE_LINK_QUALITY_INFO = 3;
+
+ /**
+ * @hide
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ writeToParcel(dest, flags, OBJECT_TYPE_LINK_QUALITY_INFO);
+ }
+
+ /**
+ * @hide
+ */
+ public void writeToParcel(Parcel dest, int flags, int objectType) {
+ dest.writeInt(objectType);
+ dest.writeInt(mNetworkType);
+ dest.writeInt(mNormalizedSignalStrength);
+ dest.writeLong(mPacketCount);
+ dest.writeLong(mPacketErrorCount);
+ dest.writeInt(mTheoreticalTxBandwidth);
+ dest.writeInt(mTheoreticalRxBandwidth);
+ dest.writeInt(mTheoreticalLatency);
+ dest.writeLong(mLastDataSampleTime);
+ dest.writeInt(mDataSampleDuration);
+ }
+
+ /**
+ * @hide
+ */
+ public static final Creator<LinkQualityInfo> CREATOR =
+ new Creator<LinkQualityInfo>() {
+ public LinkQualityInfo createFromParcel(Parcel in) {
+ int objectType = in.readInt();
+ if (objectType == OBJECT_TYPE_LINK_QUALITY_INFO) {
+ LinkQualityInfo li = new LinkQualityInfo();
+ li.initializeFromParcel(in);
+ return li;
+ } else if (objectType == OBJECT_TYPE_WIFI_LINK_QUALITY_INFO) {
+ return WifiLinkQualityInfo.createFromParcelBody(in);
+ } else if (objectType == OBJECT_TYPE_MOBILE_LINK_QUALITY_INFO) {
+ return MobileLinkQualityInfo.createFromParcelBody(in);
+ } else {
+ return null;
+ }
+ }
+
+ public LinkQualityInfo[] newArray(int size) {
+ return new LinkQualityInfo[size];
+ }
+ };
+
+ /**
+ * @hide
+ */
+ protected void initializeFromParcel(Parcel in) {
+ mNetworkType = in.readInt();
+ mNormalizedSignalStrength = in.readInt();
+ mPacketCount = in.readLong();
+ mPacketErrorCount = in.readLong();
+ mTheoreticalTxBandwidth = in.readInt();
+ mTheoreticalRxBandwidth = in.readInt();
+ mTheoreticalLatency = in.readInt();
+ mLastDataSampleTime = in.readLong();
+ mDataSampleDuration = in.readInt();
+ }
+
+ /**
+ * returns the type of network this link is connected to
+ * @return network type as defined by {@link android.net.ConnectivityManager} or
+ * {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getNetworkType() {
+ return mNetworkType;
+ }
+
+ /**
+ * @hide
+ */
+ public void setNetworkType(int networkType) {
+ mNetworkType = networkType;
+ }
+
+ /**
+ * returns the signal strength normalized across multiple types of networks
+ * @return an integer value from 0 - 99 or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getNormalizedSignalStrength() {
+ return mNormalizedSignalStrength;
+ }
+
+ /**
+ * @hide
+ */
+ public void setNormalizedSignalStrength(int normalizedSignalStrength) {
+ mNormalizedSignalStrength = normalizedSignalStrength;
+ }
+
+ /**
+ * returns the total number of packets sent or received in sample duration
+ * @return number of packets or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+ */
+ public long getPacketCount() {
+ return mPacketCount;
+ }
+
+ /**
+ * @hide
+ */
+ public void setPacketCount(long packetCount) {
+ mPacketCount = packetCount;
+ }
+
+ /**
+ * returns the total number of packets errors encountered in sample duration
+ * @return number of errors or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+ */
+ public long getPacketErrorCount() {
+ return mPacketErrorCount;
+ }
+
+ /**
+ * @hide
+ */
+ public void setPacketErrorCount(long packetErrorCount) {
+ mPacketErrorCount = packetErrorCount;
+ }
+
+ /**
+ * returns the theoretical upload bandwidth of this network
+ * @return bandwidth in Kbps or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getTheoreticalTxBandwidth() {
+ return mTheoreticalTxBandwidth;
+ }
+
+ /**
+ * @hide
+ */
+ public void setTheoreticalTxBandwidth(int theoreticalTxBandwidth) {
+ mTheoreticalTxBandwidth = theoreticalTxBandwidth;
+ }
+
+ /**
+ * returns the theoretical download bandwidth of this network
+ * @return bandwidth in Kbps or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getTheoreticalRxBandwidth() {
+ return mTheoreticalRxBandwidth;
+ }
+
+ /**
+ * @hide
+ */
+ public void setTheoreticalRxBandwidth(int theoreticalRxBandwidth) {
+ mTheoreticalRxBandwidth = theoreticalRxBandwidth;
+ }
+
+ /**
+ * returns the theoretical latency of this network
+ * @return latency in milliseconds or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getTheoreticalLatency() {
+ return mTheoreticalLatency;
+ }
+
+ /**
+ * @hide
+ */
+ public void setTheoreticalLatency(int theoreticalLatency) {
+ mTheoreticalLatency = theoreticalLatency;
+ }
+
+ /**
+ * returns the time stamp of the last sample
+ * @return milliseconds elapsed since start and sample time or
+ * {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+ */
+ public long getLastDataSampleTime() {
+ return mLastDataSampleTime;
+ }
+
+ /**
+ * @hide
+ */
+ public void setLastDataSampleTime(long lastDataSampleTime) {
+ mLastDataSampleTime = lastDataSampleTime;
+ }
+
+ /**
+ * returns the sample duration used
+ * @return duration in milliseconds or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getDataSampleDuration() {
+ return mDataSampleDuration;
+ }
+
+ /**
+ * @hide
+ */
+ public void setDataSampleDuration(int dataSampleDuration) {
+ mDataSampleDuration = dataSampleDuration;
+ }
+}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 125d5c1..b914940 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -84,6 +84,8 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
+ private static final int UNKNOWN = LinkQualityInfo.UNKNOWN_INT;
+
/**
* Create a new MobileDataStateTracker
* @param netType the ConnectivityManager network type
@@ -196,6 +198,8 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
loge("CONNECTED event did not supply link properties.");
mLinkProperties = new LinkProperties();
}
+ mLinkProperties.setMtu(mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_mobile_mtu));
mLinkCapabilities = intent.getParcelableExtra(
PhoneConstants.DATA_LINK_CAPABILITIES_KEY);
if (mLinkCapabilities == null) {
@@ -207,6 +211,8 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
private class MobileDataStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ // Assume this isn't a provisioning network.
+ mNetworkInfo.setIsConnectedToProvisioningNetwork(false);
if (intent.getAction().equals(TelephonyIntents.
ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) {
String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
@@ -222,7 +228,11 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
// Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING
mMobileDataState = PhoneConstants.DataState.CONNECTING;
updateLinkProperitesAndCapatilities(intent);
- setDetailedState(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, "", apnName);
+ mNetworkInfo.setIsConnectedToProvisioningNetwork(true);
+
+ // Change state to SUSPENDED so setDetailedState
+ // sends EVENT_STATE_CHANGED to connectivityService
+ setDetailedState(DetailedState.SUSPENDED, "", apnName);
} else if (intent.getAction().equals(TelephonyIntents.
ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY);
@@ -756,59 +766,59 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
}
@Override
- public LinkInfo getLinkInfo() {
+ public LinkQualityInfo getLinkQualityInfo() {
if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) {
// no data available yet; just return
return null;
}
- MobileLinkInfo li = new MobileLinkInfo();
+ MobileLinkQualityInfo li = new MobileLinkQualityInfo();
- li.mNetworkType = mNetworkInfo.getType();
+ li.setNetworkType(mNetworkInfo.getType());
- mSamplingDataTracker.setCommonLinkInfoFields(li);
+ mSamplingDataTracker.setCommonLinkQualityInfoFields(li);
if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
- li.mMobileNetworkType = mNetworkInfo.getSubtype();
+ li.setMobileNetworkType(mNetworkInfo.getSubtype());
NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype());
if (entry != null) {
- li.mTheoreticalRxBandwidth = entry.downloadBandwidth;
- li.mTheoreticalRxBandwidth = entry.uploadBandwidth;
- li.mTheoreticalLatency = entry.latency;
+ li.setTheoreticalRxBandwidth(entry.downloadBandwidth);
+ li.setTheoreticalRxBandwidth(entry.uploadBandwidth);
+ li.setTheoreticalLatency(entry.latency);
}
if (mSignalStrength != null) {
- li.mNormalizedSignalStrength = getNormalizedSignalStrength(
- li.mMobileNetworkType, mSignalStrength);
+ li.setNormalizedSignalStrength(getNormalizedSignalStrength(
+ li.getMobileNetworkType(), mSignalStrength));
}
}
SignalStrength ss = mSignalStrength;
if (ss != null) {
- li.mRssi = ss.getGsmSignalStrength();
- li.mGsmErrorRate = ss.getGsmBitErrorRate();
- li.mCdmaDbm = ss.getCdmaDbm();
- li.mCdmaEcio = ss.getCdmaEcio();
- li.mEvdoDbm = ss.getEvdoDbm();
- li.mEvdoEcio = ss.getEvdoEcio();
- li.mEvdoSnr = ss.getEvdoSnr();
- li.mLteSignalStrength = ss.getLteSignalStrength();
- li.mLteRsrp = ss.getLteRsrp();
- li.mLteRsrq = ss.getLteRsrq();
- li.mLteRssnr = ss.getLteRssnr();
- li.mLteCqi = ss.getLteCqi();
+ li.setRssi(ss.getGsmSignalStrength());
+ li.setGsmErrorRate(ss.getGsmBitErrorRate());
+ li.setCdmaDbm(ss.getCdmaDbm());
+ li.setCdmaEcio(ss.getCdmaEcio());
+ li.setEvdoDbm(ss.getEvdoDbm());
+ li.setEvdoEcio(ss.getEvdoEcio());
+ li.setEvdoSnr(ss.getEvdoSnr());
+ li.setLteSignalStrength(ss.getLteSignalStrength());
+ li.setLteRsrp(ss.getLteRsrp());
+ li.setLteRsrq(ss.getLteRsrq());
+ li.setLteRssnr(ss.getLteRssnr());
+ li.setLteCqi(ss.getLteCqi());
}
if (VDBG) {
- Slog.d(TAG, "Returning LinkInfo with"
- + " MobileNetworkType = " + String.valueOf(li.mMobileNetworkType)
- + " Theoretical Rx BW = " + String.valueOf(li.mTheoreticalRxBandwidth)
- + " gsm Signal Strength = " + String.valueOf(li.mRssi)
- + " cdma Signal Strength = " + String.valueOf(li.mCdmaDbm)
- + " evdo Signal Strength = " + String.valueOf(li.mEvdoDbm)
- + " Lte Signal Strength = " + String.valueOf(li.mLteSignalStrength));
+ Slog.d(TAG, "Returning LinkQualityInfo with"
+ + " MobileNetworkType = " + String.valueOf(li.getMobileNetworkType())
+ + " Theoretical Rx BW = " + String.valueOf(li.getTheoreticalRxBandwidth())
+ + " gsm Signal Strength = " + String.valueOf(li.getRssi())
+ + " cdma Signal Strength = " + String.valueOf(li.getCdmaDbm())
+ + " evdo Signal Strength = " + String.valueOf(li.getEvdoDbm())
+ + " Lte Signal Strength = " + String.valueOf(li.getLteSignalStrength()));
}
return li;
@@ -829,21 +839,21 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
}
private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] {
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE, 237, 118, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS, 48, 40, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS, 384, 64, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA, 14400, -1, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA, 14400, 5760, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA, 14400, 5760, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP, 21000, 5760, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA, -1, -1, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, -1, -1, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0, 2468, 153, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A, 3072, 1800, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B, 14700, 1800, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN, -1, -1, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE, 100000, 50000, -1),
- new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, -1, -1, -1),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE, 237, 118, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS, 48, 40, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS, 384, 64, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA, 14400, UNKNOWN, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA, 14400, 5760, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA, 14400, 5760, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP, 21000, 5760, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA, UNKNOWN, UNKNOWN, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, UNKNOWN, UNKNOWN, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0, 2468, 153, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A, 3072, 1800, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B, 14700, 1800, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN, UNKNOWN, UNKNOWN, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE, 100000, 50000, UNKNOWN),
+ new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, UNKNOWN, UNKNOWN, UNKNOWN),
};
private static NetworkDataEntry getNetworkDataEntry(int networkType) {
@@ -886,10 +896,10 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker {
case TelephonyManager.NETWORK_TYPE_IDEN:
case TelephonyManager.NETWORK_TYPE_EHRPD:
default:
- return LinkInfo.UNKNOWN;
+ return UNKNOWN;
}
- return (level * LinkInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) /
+ return (level * LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) /
SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
}
diff --git a/core/java/android/net/MobileLinkInfo.java b/core/java/android/net/MobileLinkInfo.java
deleted file mode 100644
index 2d18275..0000000
--- a/core/java/android/net/MobileLinkInfo.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2013 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.os.Parcel;
-import android.net.LinkInfo;
-
-/**
- * Class that represents useful attributes of mobile network links
- * such as the upload/download throughput or error rate etc.
- * @hide
- */
-public final class MobileLinkInfo extends LinkInfo
-{
- // Represents TelephonyManager.NetworkType
- public int mMobileNetworkType = UNKNOWN;
- public int mRssi = UNKNOWN;
- public int mGsmErrorRate = UNKNOWN;
- public int mCdmaDbm = UNKNOWN;
- public int mCdmaEcio = UNKNOWN;
- public int mEvdoDbm = UNKNOWN;
- public int mEvdoEcio = UNKNOWN;
- public int mEvdoSnr = UNKNOWN;
- public int mLteSignalStrength = UNKNOWN;
- public int mLteRsrp = UNKNOWN;
- public int mLteRsrq = UNKNOWN;
- public int mLteRssnr = UNKNOWN;
- public int mLteCqi = UNKNOWN;
-
- /**
- * Implement the Parcelable interface.
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags, OBJECT_TYPE_MOBILE_LINKINFO);
-
- dest.writeInt(mMobileNetworkType);
- dest.writeInt(mRssi);
- dest.writeInt(mGsmErrorRate);
- dest.writeInt(mCdmaDbm);
- dest.writeInt(mCdmaEcio);
- dest.writeInt(mEvdoDbm);
- dest.writeInt(mEvdoEcio);
- dest.writeInt(mEvdoSnr);
- dest.writeInt(mLteSignalStrength);
- dest.writeInt(mLteRsrp);
- dest.writeInt(mLteRsrq);
- dest.writeInt(mLteRssnr);
- dest.writeInt(mLteCqi);
- }
-
- /* Un-parceling helper */
- public static MobileLinkInfo createFromParcelBody(Parcel in) {
-
- MobileLinkInfo li = new MobileLinkInfo();
-
- li.initializeFromParcel(in);
-
- li.mMobileNetworkType = in.readInt();
- li.mRssi = in.readInt();
- li.mGsmErrorRate = in.readInt();
- li.mCdmaDbm = in.readInt();
- li.mCdmaEcio = in.readInt();
- li.mEvdoDbm = in.readInt();
- li.mEvdoEcio = in.readInt();
- li.mEvdoSnr = in.readInt();
- li.mLteSignalStrength = in.readInt();
- li.mLteRsrp = in.readInt();
- li.mLteRsrq = in.readInt();
- li.mLteRssnr = in.readInt();
- li.mLteCqi = in.readInt();
-
- return li;
- }
-}
diff --git a/core/java/android/net/MobileLinkQualityInfo.java b/core/java/android/net/MobileLinkQualityInfo.java
new file mode 100644
index 0000000..a01fc80
--- /dev/null
+++ b/core/java/android/net/MobileLinkQualityInfo.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2013 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.os.Parcel;
+
+/**
+ * Class that represents useful attributes of mobile network links
+ * such as the upload/download throughput or error rate etc.
+ * @hide
+ */
+public class MobileLinkQualityInfo extends LinkQualityInfo {
+ // Represents TelephonyManager.NetworkType
+ private int mMobileNetworkType = UNKNOWN_INT;
+ private int mRssi = UNKNOWN_INT;
+ private int mGsmErrorRate = UNKNOWN_INT;
+ private int mCdmaDbm = UNKNOWN_INT;
+ private int mCdmaEcio = UNKNOWN_INT;
+ private int mEvdoDbm = UNKNOWN_INT;
+ private int mEvdoEcio = UNKNOWN_INT;
+ private int mEvdoSnr = UNKNOWN_INT;
+ private int mLteSignalStrength = UNKNOWN_INT;
+ private int mLteRsrp = UNKNOWN_INT;
+ private int mLteRsrq = UNKNOWN_INT;
+ private int mLteRssnr = UNKNOWN_INT;
+ private int mLteCqi = UNKNOWN_INT;
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags, OBJECT_TYPE_MOBILE_LINK_QUALITY_INFO);
+
+ dest.writeInt(mMobileNetworkType);
+ dest.writeInt(mRssi);
+ dest.writeInt(mGsmErrorRate);
+ dest.writeInt(mCdmaDbm);
+ dest.writeInt(mCdmaEcio);
+ dest.writeInt(mEvdoDbm);
+ dest.writeInt(mEvdoEcio);
+ dest.writeInt(mEvdoSnr);
+ dest.writeInt(mLteSignalStrength);
+ dest.writeInt(mLteRsrp);
+ dest.writeInt(mLteRsrq);
+ dest.writeInt(mLteRssnr);
+ dest.writeInt(mLteCqi);
+ }
+
+ /* Un-parceling helper */
+ /**
+ * @hide
+ */
+ public static MobileLinkQualityInfo createFromParcelBody(Parcel in) {
+
+ MobileLinkQualityInfo li = new MobileLinkQualityInfo();
+
+ li.initializeFromParcel(in);
+
+ li.mMobileNetworkType = in.readInt();
+ li.mRssi = in.readInt();
+ li.mGsmErrorRate = in.readInt();
+ li.mCdmaDbm = in.readInt();
+ li.mCdmaEcio = in.readInt();
+ li.mEvdoDbm = in.readInt();
+ li.mEvdoEcio = in.readInt();
+ li.mEvdoSnr = in.readInt();
+ li.mLteSignalStrength = in.readInt();
+ li.mLteRsrp = in.readInt();
+ li.mLteRsrq = in.readInt();
+ li.mLteRssnr = in.readInt();
+ li.mLteCqi = in.readInt();
+
+ return li;
+ }
+
+ /**
+ * returns mobile network type as defined by {@link android.telephony.TelephonyManager}
+ * @return network type or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getMobileNetworkType() {
+ return mMobileNetworkType;
+ }
+
+ /**
+ * @hide
+ */
+ public void setMobileNetworkType(int mobileNetworkType) {
+ mMobileNetworkType = mobileNetworkType;
+ }
+
+ /**
+ * returns signal strength for GSM networks
+ * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getRssi() {
+ return mRssi;
+ }
+
+ /**
+ * @hide
+ */
+ public void setRssi(int Rssi) {
+ mRssi = Rssi;
+ }
+
+ /**
+ * returns error rates for GSM networks
+ * @return error rate or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getGsmErrorRate() {
+ return mGsmErrorRate;
+ }
+
+ /**
+ * @hide
+ */
+ public void setGsmErrorRate(int gsmErrorRate) {
+ mGsmErrorRate = gsmErrorRate;
+ }
+
+ /**
+ * returns signal strength for CDMA networks
+ * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getCdmaDbm() {
+ return mCdmaDbm;
+ }
+
+ /**
+ * @hide
+ */
+ public void setCdmaDbm(int cdmaDbm) {
+ mCdmaDbm = cdmaDbm;
+ }
+
+ /**
+ * returns signal to noise ratio for CDMA networks
+ * @return signal to noise ratio in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getCdmaEcio() {
+ return mCdmaEcio;
+ }
+
+ /**
+ * @hide
+ */
+ public void setCdmaEcio(int cdmaEcio) {
+ mCdmaEcio = cdmaEcio;
+ }
+
+ /**
+ * returns signal strength for EVDO networks
+ * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getEvdoDbm() {
+ return mEvdoDbm;
+ }
+
+ /**
+ * @hide
+ */
+ public void setEvdoDbm(int evdoDbm) {
+ mEvdoDbm = evdoDbm;
+ }
+
+ /**
+ * returns signal to noise ratio for EVDO spectrum
+ * @return signal to noise ration in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getEvdoEcio() {
+ return mEvdoEcio;
+ }
+
+ /**
+ * @hide
+ */
+ public void setEvdoEcio(int evdoEcio) {
+ mEvdoEcio = evdoEcio;
+ }
+
+ /**
+ * returns end-to-end signal to noise ratio for EVDO networks
+ * @return signal to noise ration in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getEvdoSnr() {
+ return mEvdoSnr;
+ }
+
+ /**
+ * @hide
+ */
+ public void setEvdoSnr(int evdoSnr) {
+ mEvdoSnr = evdoSnr;
+ }
+
+ /**
+ * returns signal strength for LTE network
+ * @return signal strength in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getLteSignalStrength() {
+ return mLteSignalStrength;
+ }
+
+ /**
+ * @hide
+ */
+ public void setLteSignalStrength(int lteSignalStrength) {
+ mLteSignalStrength = lteSignalStrength;
+ }
+
+ /**
+ * returns RSRP (Reference Signal Received Power) for LTE network
+ * @return RSRP in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getLteRsrp() {
+ return mLteRsrp;
+ }
+
+ /**
+ * @hide
+ */
+ public void setLteRsrp(int lteRsrp) {
+ mLteRsrp = lteRsrp;
+ }
+
+ /**
+ * returns RSRQ (Reference Signal Received Quality) for LTE network
+ * @return RSRQ ??? or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getLteRsrq() {
+ return mLteRsrq;
+ }
+
+ /**
+ * @hide
+ */
+ public void setLteRsrq(int lteRsrq) {
+ mLteRsrq = lteRsrq;
+ }
+
+ /**
+ * returns signal to noise ratio for LTE networks
+ * @return signal to noise ration in db or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getLteRssnr() {
+ return mLteRssnr;
+ }
+
+ /**
+ * @hide
+ */
+ public void setLteRssnr(int lteRssnr) {
+ mLteRssnr = lteRssnr;
+ }
+
+ /**
+ * returns channel quality indicator for LTE networks
+ * @return CQI or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getLteCqi() {
+ return mLteCqi;
+ }
+
+ /**
+ * @hide
+ */
+ public void setLteCqi(int lteCqi) {
+ mLteCqi = lteCqi;
+ }
+}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index dabc73a..4d2a70d 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -83,13 +83,7 @@ public class NetworkInfo implements Parcelable {
/** Link has poor connectivity. */
VERIFYING_POOR_LINK,
/** Checking if network is a captive portal */
- CAPTIVE_PORTAL_CHECK,
- /**
- * Network is connected to provisioning network
- * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK
- * @hide
- */
- CONNECTED_TO_PROVISIONING_NETWORK
+ CAPTIVE_PORTAL_CHECK
}
/**
@@ -114,7 +108,6 @@ public class NetworkInfo implements Parcelable {
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
- stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED);
}
private int mNetworkType;
@@ -127,6 +120,8 @@ public class NetworkInfo implements Parcelable {
private String mExtraInfo;
private boolean mIsFailover;
private boolean mIsRoaming;
+ private boolean mIsConnectedToProvisioningNetwork;
+
/**
* Indicates whether network connectivity is possible:
*/
@@ -155,6 +150,7 @@ public class NetworkInfo implements Parcelable {
mState = State.UNKNOWN;
mIsAvailable = false; // until we're told otherwise, assume unavailable
mIsRoaming = false;
+ mIsConnectedToProvisioningNetwork = false;
}
/** {@hide} */
@@ -171,6 +167,7 @@ public class NetworkInfo implements Parcelable {
mIsFailover = source.mIsFailover;
mIsRoaming = source.mIsRoaming;
mIsAvailable = source.mIsAvailable;
+ mIsConnectedToProvisioningNetwork = source.mIsConnectedToProvisioningNetwork;
}
}
@@ -329,6 +326,22 @@ public class NetworkInfo implements Parcelable {
}
}
+ /** {@hide} */
+ @VisibleForTesting
+ public boolean isConnectedToProvisioningNetwork() {
+ synchronized (this) {
+ return mIsConnectedToProvisioningNetwork;
+ }
+ }
+
+ /** {@hide} */
+ @VisibleForTesting
+ public void setIsConnectedToProvisioningNetwork(boolean val) {
+ synchronized (this) {
+ mIsConnectedToProvisioningNetwork = val;
+ }
+ }
+
/**
* Reports the current coarse-grained state of the network.
* @return the coarse-grained state
@@ -412,7 +425,9 @@ public class NetworkInfo implements Parcelable {
append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
append(", roaming: ").append(mIsRoaming).
append(", failover: ").append(mIsFailover).
- append(", isAvailable: ").append(mIsAvailable);
+ append(", isAvailable: ").append(mIsAvailable).
+ append(", isConnectedToProvisioningNetwork: ").
+ append(mIsConnectedToProvisioningNetwork);
return builder.toString();
}
}
@@ -440,6 +455,7 @@ public class NetworkInfo implements Parcelable {
dest.writeInt(mIsFailover ? 1 : 0);
dest.writeInt(mIsAvailable ? 1 : 0);
dest.writeInt(mIsRoaming ? 1 : 0);
+ dest.writeInt(mIsConnectedToProvisioningNetwork ? 1 : 0);
dest.writeString(mReason);
dest.writeString(mExtraInfo);
}
@@ -462,6 +478,7 @@ public class NetworkInfo implements Parcelable {
netInfo.mIsFailover = in.readInt() != 0;
netInfo.mIsAvailable = in.readInt() != 0;
netInfo.mIsRoaming = in.readInt() != 0;
+ netInfo.mIsConnectedToProvisioningNetwork = in.readInt() != 0;
netInfo.mReason = in.readString();
netInfo.mExtraInfo = in.readString();
return netInfo;
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index a3d7b14..1ca9255 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -122,7 +122,7 @@ public interface NetworkStateTracker {
* Get interesting information about this network link
* @return a copy of link information, null if not available
*/
- public LinkInfo getLinkInfo();
+ public LinkQualityInfo getLinkQualityInfo();
/**
* Return the system properties name associated with the tcp buffer sizes
diff --git a/core/java/android/net/SamplingDataTracker.java b/core/java/android/net/SamplingDataTracker.java
index ac24930..acd56f2 100644
--- a/core/java/android/net/SamplingDataTracker.java
+++ b/core/java/android/net/SamplingDataTracker.java
@@ -189,7 +189,7 @@ public class SamplingDataTracker
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mTxByteCount - mBeginningSample.mTxByteCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
}
@@ -199,7 +199,7 @@ public class SamplingDataTracker
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mTxPacketCount - mBeginningSample.mTxPacketCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
}
@@ -209,7 +209,7 @@ public class SamplingDataTracker
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mTxPacketErrorCount - mBeginningSample.mTxPacketErrorCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
}
@@ -219,7 +219,7 @@ public class SamplingDataTracker
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mRxByteCount - mBeginningSample.mRxByteCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
}
@@ -229,7 +229,7 @@ public class SamplingDataTracker
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mRxPacketCount - mBeginningSample.mRxPacketCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
}
@@ -244,7 +244,7 @@ public class SamplingDataTracker
long txPacketCount = end.mTxPacketCount - begin.mTxPacketCount;
return rxPacketCount + txPacketCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
@@ -254,7 +254,7 @@ public class SamplingDataTracker
long txPacketErrorCount = getSampledTxPacketErrorCount();
return rxPacketErrorCount + txPacketErrorCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
@@ -263,7 +263,7 @@ public class SamplingDataTracker
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mRxPacketErrorCount - mBeginningSample.mRxPacketErrorCount;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
}
@@ -273,7 +273,7 @@ public class SamplingDataTracker
if (mEndingSample != null) {
return mEndingSample.mTimestamp;
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_LONG;
}
}
}
@@ -283,17 +283,17 @@ public class SamplingDataTracker
if (mBeginningSample != null && mEndingSample != null) {
return (int) (mEndingSample.mTimestamp - mBeginningSample.mTimestamp);
} else {
- return LinkInfo.UNKNOWN;
+ return LinkQualityInfo.UNKNOWN_INT;
}
}
}
- public void setCommonLinkInfoFields(LinkInfo li) {
+ public void setCommonLinkQualityInfoFields(LinkQualityInfo li) {
synchronized(mSamplingDataLock) {
- li.mLastDataSampleTime = getSampleTimestamp();
- li.mDataSampleDuration = getSampleDuration();
- li.mPacketCount = getSampledPacketCount();
- li.mPacketErrorCount = getSampledPacketErrorCount();
+ li.setLastDataSampleTime(getSampleTimestamp());
+ li.setDataSampleDuration(getSampleDuration());
+ li.setPacketCount(getSampledPacketCount());
+ li.setPacketErrorCount(getSampledPacketErrorCount());
}
}
}
diff --git a/core/java/android/net/WifiLinkInfo.java b/core/java/android/net/WifiLinkInfo.java
deleted file mode 100644
index a21f1fe..0000000
--- a/core/java/android/net/WifiLinkInfo.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2013 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.os.Parcel;
-import android.net.LinkInfo;
-
-/**
- * Class that represents useful attributes of wifi network links
- * such as the upload/download throughput or error rate etc.
- * @hide
- */
-public final class WifiLinkInfo extends LinkInfo
-{
- /**
- * Type enumerations for Wifi Network
- */
-
- /* Indicates Wifi network type such as b/g etc*/
- public int mType = UNKNOWN;
-
- public String mBssid;
-
- /* Rssi found by scans */
- public int mRssi = UNKNOWN;
-
- /* packet statistics */
- public long mTxGood = UNKNOWN;
- public long mTxBad = UNKNOWN;
-
- /**
- * Implement the Parcelable interface.
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags, OBJECT_TYPE_WIFI_LINKINFO);
-
- dest.writeInt(mType);
- dest.writeInt(mRssi);
- dest.writeLong(mTxGood);
- dest.writeLong(mTxBad);
-
- dest.writeString(mBssid);
- }
-
- /* Un-parceling helper */
- public static WifiLinkInfo createFromParcelBody(Parcel in) {
- WifiLinkInfo li = new WifiLinkInfo();
-
- li.initializeFromParcel(in);
-
- li.mType = in.readInt();
- li.mRssi = in.readInt();
- li.mTxGood = in.readLong();
- li.mTxBad = in.readLong();
-
- li.mBssid = in.readString();
-
- return li;
- }
-}
diff --git a/core/java/android/net/WifiLinkQualityInfo.java b/core/java/android/net/WifiLinkQualityInfo.java
new file mode 100644
index 0000000..20ec9a7
--- /dev/null
+++ b/core/java/android/net/WifiLinkQualityInfo.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013 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.os.Parcel;
+
+/**
+ * Class that represents useful attributes of wifi network links
+ * such as the upload/download throughput or error rate etc.
+ * @hide
+ */
+public class WifiLinkQualityInfo extends LinkQualityInfo {
+
+ /* Indicates Wifi network type such as b/g etc*/
+ private int mType = UNKNOWN_INT;
+
+ private String mBssid;
+
+ /* Rssi found by scans */
+ private int mRssi = UNKNOWN_INT;
+
+ /* packet statistics */
+ private long mTxGood = UNKNOWN_LONG;
+ private long mTxBad = UNKNOWN_LONG;
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags, OBJECT_TYPE_WIFI_LINK_QUALITY_INFO);
+
+ dest.writeInt(mType);
+ dest.writeInt(mRssi);
+ dest.writeLong(mTxGood);
+ dest.writeLong(mTxBad);
+
+ dest.writeString(mBssid);
+ }
+
+ /* Un-parceling helper */
+ /**
+ * @hide
+ */
+ public static WifiLinkQualityInfo createFromParcelBody(Parcel in) {
+ WifiLinkQualityInfo li = new WifiLinkQualityInfo();
+
+ li.initializeFromParcel(in);
+
+ li.mType = in.readInt();
+ li.mRssi = in.readInt();
+ li.mTxGood = in.readLong();
+ li.mTxBad = in.readLong();
+
+ li.mBssid = in.readString();
+
+ return li;
+ }
+
+ /**
+ * returns Wifi network type
+ * @return network type or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * @hide
+ */
+ public void setType(int type) {
+ mType = type;
+ }
+
+ /**
+ * returns BSSID of the access point
+ * @return the BSSID, in the form of a six-byte MAC address: {@code XX:XX:XX:XX:XX:XX} or null
+ */
+ public String getBssid() {
+ return mBssid;
+ }
+
+ /**
+ * @hide
+ */
+ public void setBssid(String bssid) {
+ mBssid = bssid;
+ }
+
+ /**
+ * returns RSSI of the network in raw form
+ * @return un-normalized RSSI or {@link android.net.LinkQualityInfo#UNKNOWN_INT}
+ */
+ public int getRssi() {
+ return mRssi;
+ }
+
+ /**
+ * @hide
+ */
+ public void setRssi(int rssi) {
+ mRssi = rssi;
+ }
+
+ /**
+ * returns number of packets transmitted without error
+ * @return number of packets or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+ */
+ public long getTxGood() {
+ return mTxGood;
+ }
+
+ /**
+ * @hide
+ */
+ public void setTxGood(long txGood) {
+ mTxGood = txGood;
+ }
+
+ /**
+ * returns number of transmitted packets that encountered errors
+ * @return number of packets or {@link android.net.LinkQualityInfo#UNKNOWN_LONG}
+ */
+ public long getTxBad() {
+ return mTxBad;
+ }
+
+ /**
+ * @hide
+ */
+ public void setTxBad(long txBad) {
+ mTxBad = txBad;
+ }
+}
diff --git a/core/java/android/nfc/INdefPushCallback.aidl b/core/java/android/nfc/IAppCallback.aidl
index 16771dc..9599308 100644
--- a/core/java/android/nfc/INdefPushCallback.aidl
+++ b/core/java/android/nfc/IAppCallback.aidl
@@ -17,12 +17,14 @@
package android.nfc;
import android.nfc.BeamShareData;
+import android.nfc.Tag;
/**
* @hide
*/
-interface INdefPushCallback
+interface IAppCallback
{
BeamShareData createBeamShareData();
void onNdefPushComplete();
+ void onTagDiscovered(in Tag tag);
}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 15d0475..8414738 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -21,10 +21,11 @@ import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.Tag;
import android.nfc.TechListParcel;
-import android.nfc.INdefPushCallback;
+import android.nfc.IAppCallback;
import android.nfc.INfcAdapterExtras;
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
+import android.os.Bundle;
/**
* @hide
@@ -44,10 +45,10 @@ interface INfcAdapter
void setForegroundDispatch(in PendingIntent intent,
in IntentFilter[] filters, in TechListParcel techLists);
- void setNdefPushCallback(in INdefPushCallback callback);
+ void setAppCallback(in IAppCallback callback);
void dispatch(in Tag tag);
- void setReaderMode (IBinder b, int flags);
+ void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
void setP2pModes(int initatorModes, int targetModes);
}
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index d0d943c..77c0234 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -19,6 +19,7 @@ package android.nfc;
import android.app.Activity;
import android.app.Application;
import android.net.Uri;
+import android.nfc.NfcAdapter.ReaderCallback;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
@@ -36,7 +37,7 @@ import java.util.List;
*
* @hide
*/
-public final class NfcActivityManager extends INdefPushCallback.Stub
+public final class NfcActivityManager extends IAppCallback.Stub
implements Application.ActivityLifecycleCallbacks {
static final String TAG = NfcAdapter.TAG;
static final Boolean DBG = false;
@@ -113,6 +114,8 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
Uri[] uris = null;
int flags = 0;
int readerModeFlags = 0;
+ NfcAdapter.ReaderCallback readerCallback = null;
+ Bundle readerModeExtras = null;
Binder token;
public NfcActivityState(Activity activity) {
@@ -197,17 +200,20 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
mDefaultEvent = new NfcEvent(mAdapter);
}
- public void enableReaderMode(Activity activity, int flags) {
+ public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
+ Bundle extras) {
boolean isResumed;
Binder token;
synchronized (NfcActivityManager.this) {
NfcActivityState state = getActivityState(activity);
+ state.readerCallback = callback;
state.readerModeFlags = flags;
+ state.readerModeExtras = extras;
token = state.token;
isResumed = state.resumed;
}
if (isResumed) {
- setReaderMode(token, flags);
+ setReaderMode(token, flags, extras);
}
}
@@ -216,20 +222,22 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
Binder token;
synchronized (NfcActivityManager.this) {
NfcActivityState state = getActivityState(activity);
+ state.readerCallback = null;
state.readerModeFlags = 0;
+ state.readerModeExtras = null;
token = state.token;
isResumed = state.resumed;
}
if (isResumed) {
- setReaderMode(token, 0);
+ setReaderMode(token, 0, null);
}
}
- public void setReaderMode(Binder token, int flags) {
+ public void setReaderMode(Binder token, int flags, Bundle extras) {
if (DBG) Log.d(TAG, "Setting reader mode");
try {
- NfcAdapter.sService.setReaderMode(token, flags);
+ NfcAdapter.sService.setReaderMode(token, this, flags, extras);
} catch (RemoteException e) {
mAdapter.attemptDeadServiceRecovery(e);
}
@@ -302,12 +310,12 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
}
/**
- * Request or unrequest NFC service callbacks for NDEF push.
+ * Request or unrequest NFC service callbacks.
* Makes IPC call - do not hold lock.
*/
void requestNfcServiceCallback() {
try {
- NfcAdapter.sService.setNdefPushCallback(this);
+ NfcAdapter.sService.setAppCallback(this);
} catch (RemoteException e) {
mAdapter.attemptDeadServiceRecovery(e);
}
@@ -375,6 +383,22 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
}
}
+ @Override
+ public void onTagDiscovered(Tag tag) throws RemoteException {
+ NfcAdapter.ReaderCallback callback;
+ synchronized (NfcActivityManager.this) {
+ NfcActivityState state = findResumedActivityState();
+ if (state == null) return;
+
+ callback = state.readerCallback;
+ }
+
+ // Make callback without lock
+ if (callback != null) {
+ callback.onTagDiscovered(tag);
+ }
+
+ }
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { /* NO-OP */ }
@@ -387,6 +411,7 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
@Override
public void onActivityResumed(Activity activity) {
int readerModeFlags = 0;
+ Bundle readerModeExtras = null;
Binder token;
synchronized (NfcActivityManager.this) {
NfcActivityState state = findActivityState(activity);
@@ -395,9 +420,10 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
state.resumed = true;
token = state.token;
readerModeFlags = state.readerModeFlags;
+ readerModeExtras = state.readerModeExtras;
}
if (readerModeFlags != 0) {
- setReaderMode(token, readerModeFlags);
+ setReaderMode(token, readerModeFlags, readerModeExtras);
}
requestNfcServiceCallback();
}
@@ -417,7 +443,7 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
}
if (readerModeFlagsSet) {
// Restore default p2p modes
- setReaderMode(token, 0);
+ setReaderMode(token, 0, null);
}
}
@@ -441,4 +467,5 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
}
}
}
+
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index fa0c1f6..2a18900 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -33,6 +33,7 @@ import android.nfc.tech.MifareClassic;
import android.nfc.tech.Ndef;
import android.nfc.tech.NfcA;
import android.nfc.tech.NfcF;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -196,42 +197,42 @@ public final class NfcAdapter {
public static final int STATE_TURNING_OFF = 4;
/**
- * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag enables polling for Nfc-A technology.
*/
public static final int FLAG_READER_NFC_A = 0x1;
/**
- * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag enables polling for Nfc-B technology.
*/
public static final int FLAG_READER_NFC_B = 0x2;
/**
- * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag enables polling for Nfc-F technology.
*/
public static final int FLAG_READER_NFC_F = 0x4;
/**
- * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag enables polling for Nfc-V (ISO15693) technology.
*/
public static final int FLAG_READER_NFC_V = 0x8;
/**
- * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag enables polling for Kovio technology.
*/
public static final int FLAG_READER_KOVIO = 0x10;
/**
- * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
* <p>
* Setting this flag allows the caller to prevent the
* platform from performing an NDEF check on the tags it
@@ -239,6 +240,23 @@ public final class NfcAdapter {
*/
public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
+ /**
+ * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+ * <p>
+ * Setting this flag allows the caller to prevent the
+ * platform from playing sounds when it discovers a tag.
+ */
+ public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100;
+
+ /**
+ * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
+ * <p>
+ * Setting this integer extra allows the calling application to specify
+ * the delay that the platform will use for performing presence checks
+ * on any discovered tag.
+ */
+ public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
+
/** @hide */
public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
@@ -291,6 +309,14 @@ public final class NfcAdapter {
final Context mContext;
/**
+ * A callback to be invoked when the system has found a tag in
+ * reader mode.
+ */
+ public interface ReaderCallback {
+ public void onTagDiscovered(Tag tag);
+ }
+
+ /**
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
* to another device.
* @see #setOnNdefPushCompleteCallback
@@ -1167,19 +1193,18 @@ public final class NfcAdapter {
* {@link Ndef} tag technology from being enumerated on the tag, and that
* NDEF-based tag dispatch will not be functional.
*
- * <p>It is recommended to combine this method with
- * {@link #enableForegroundDispatch(Activity, PendingIntent, IntentFilter[], String[][])
- * to ensure that tags are delivered to this activity.
- *
* <p>For interacting with tags that are emulated on another Android device
* using Android's host-based card-emulation, the recommended flags are
* {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}.
*
* @param activity the Activity that requests the adapter to be in reader mode
+ * @param callback the callback to be called when a tag is discovered
* @param flags Flags indicating poll technologies and other optional parameters
+ * @param extras Additional extras for configuring reader mode.
*/
- public void enableReaderMode(Activity activity, int flags) {
- mNfcActivityManager.enableReaderMode(activity, flags);
+ public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
+ Bundle extras) {
+ mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
}
/**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 38ffb96..dbaa325 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2380,22 +2380,25 @@ public abstract class BatteryStats implements Parcelable {
@SuppressWarnings("unused")
public void dumpCheckinLocked(
- PrintWriter pw, List<ApplicationInfo> apps, boolean isUnpluggedOnly) {
+ PrintWriter pw, List<ApplicationInfo> apps, boolean isUnpluggedOnly,
+ boolean includeHistory) {
prepareForDumpLocked();
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
- final HistoryItem rec = new HistoryItem();
- if (startIteratingHistoryLocked()) {
- HistoryPrinter hprinter = new HistoryPrinter();
- while (getNextHistoryLocked(rec)) {
- pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
- pw.print(0); pw.print(',');
- pw.print(HISTORY_DATA); pw.print(',');
- hprinter.printNextItemCheckin(pw, rec, now);
- pw.println();
+ if (includeHistory) {
+ final HistoryItem rec = new HistoryItem();
+ if (startIteratingHistoryLocked()) {
+ HistoryPrinter hprinter = new HistoryPrinter();
+ while (getNextHistoryLocked(rec)) {
+ pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+ pw.print(0); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
+ hprinter.printNextItemCheckin(pw, rec, now);
+ pw.println();
+ }
+ finishIteratingHistoryLocked();
}
- finishIteratingHistoryLocked();
}
if (apps != null) {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 4627c88..26fc769 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -399,17 +399,27 @@ public class Binder implements IBinder {
// but all that does is rewind it, and we just got these from an IPC,
// so we'll just call it directly.
boolean res;
+ // Log any exceptions as warnings, don't silently suppress them.
+ // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
try {
res = onTransact(code, data, reply, flags);
} catch (RemoteException e) {
+ if ((flags & FLAG_ONEWAY) != 0) {
+ Log.w(TAG, "Binder call failed.", e);
+ }
reply.setDataPosition(0);
reply.writeException(e);
res = true;
} catch (RuntimeException e) {
+ if ((flags & FLAG_ONEWAY) != 0) {
+ Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
+ }
reply.setDataPosition(0);
reply.writeException(e);
res = true;
} catch (OutOfMemoryError e) {
+ // Unconditionally log this, since this is generally unrecoverable.
+ Log.e(TAG, "Caught an OutOfMemoryError from the binder stub implementation.", e);
RuntimeException re = new RuntimeException("Out of memory", e);
reply.setDataPosition(0);
reply.writeException(re);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index dd40e35..88eb280 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -438,7 +438,7 @@ public class Build {
public static final int JELLY_BEAN_MR2 = 18;
/**
- * Android X.X: Key Lime Pie, another tasty treat.
+ * Android X.X: KitKat, another tasty treat.
*
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
@@ -448,7 +448,7 @@ public class Build {
* {@link android.content.Context#bindService}.
* </ul>
*/
- public static final int KEY_LIME_PIE = CUR_DEVELOPMENT;
+ public static final int KITKAT = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 60ce132..8f68fc1 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -158,7 +158,7 @@ public final class Debug
public int otherSharedClean;
/** @hide */
- public static final int NUM_OTHER_STATS = 13;
+ public static final int NUM_OTHER_STATS = 14;
/** @hide */
public static final int NUM_DVK_STATS = 5;
@@ -285,11 +285,12 @@ public final class Debug
case 10: return "code mmap";
case 11: return "image mmap";
case 12: return "Other mmap";
- case 13: return ".Heap";
- case 14: return ".LOS";
- case 15: return ".LinearAlloc";
- case 16: return ".GC";
- case 17: return ".JITCache";
+ case 13: return "GPU";
+ case 14: return ".Heap";
+ case 15: return ".LOS";
+ case 16: return ".LinearAlloc";
+ case 17: return ".GC";
+ case 18: return ".JITCache";
default: return "????";
}
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 3b9456f..c6e8c3e 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
-import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -324,7 +323,7 @@ public class Environment {
* {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
* which is automatically granted if you hold the write permission.
* <p>
- * Starting in {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, if your
+ * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
* application only needs to store internal data, consider using
* {@link Context#getExternalFilesDir(String)} or
* {@link Context#getExternalCacheDir()}, which require no permissions to
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index ed9620f..61e5a4b 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -118,6 +118,11 @@ interface INetworkManagementService
void removeSecondaryRoute(String iface, in RouteInfo route);
/**
+ * Set the specified MTU size
+ */
+ void setMtu(String iface, int mtu);
+
+ /**
* Shuts down the service
*/
void shutdown();
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index bd2d9ac..3c9d0d9 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -46,8 +46,8 @@ interface IUserManager {
int userHandle);
Bundle getApplicationRestrictions(in String packageName);
Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle);
- boolean changeRestrictionsPin(in String newPin);
- int checkRestrictionsPin(in String pin);
- boolean hasRestrictionsPin();
+ boolean setRestrictionsChallenge(in String newPin);
+ int checkRestrictionsChallenge(in String pin);
+ boolean hasRestrictionsChallenge();
void removeRestrictions();
}
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 1e8983e..d1b8213 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -39,7 +39,7 @@ public final class MessageQueue {
Message mMessages;
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private IdleHandler[] mPendingIdleHandlers;
- private boolean mQuiting;
+ private boolean mQuitting;
// Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
private boolean mBlocked;
@@ -115,6 +115,8 @@ public final class MessageQueue {
}
}
+ // Disposes of the underlying message queue.
+ // Must only be called on the looper thread or the finalizer.
private void dispose() {
if (mPtr != 0) {
nativeDestroy(mPtr);
@@ -125,11 +127,13 @@ public final class MessageQueue {
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
-
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
+
+ // We can assume mPtr != 0 because the loop is obviously still running.
+ // The looper will not call this method after the loop quits.
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
@@ -167,7 +171,7 @@ public final class MessageQueue {
}
// Process the quit message now that all pending messages have been handled.
- if (mQuiting) {
+ if (mQuitting) {
dispose();
return null;
}
@@ -226,18 +230,20 @@ public final class MessageQueue {
}
synchronized (this) {
- if (mQuiting) {
+ if (mQuitting) {
return;
}
- mQuiting = true;
+ mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
+
+ // We can assume mPtr != 0 because mQuitting was previously false.
+ nativeWake(mPtr);
}
- nativeWake(mPtr);
}
int enqueueSyncBarrier(long when) {
@@ -270,7 +276,6 @@ public final class MessageQueue {
void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
- final boolean needWake;
synchronized (this) {
Message prev = null;
Message p = mMessages;
@@ -282,6 +287,7 @@ public final class MessageQueue {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
+ final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
@@ -290,9 +296,12 @@ public final class MessageQueue {
needWake = mMessages == null || mMessages.target != null;
}
p.recycle();
- }
- if (needWake) {
- nativeWake(mPtr);
+
+ // If the loop is quitting then it is already awake.
+ // We can assume mPtr != 0 when mQuitting is false.
+ if (needWake && !mQuitting) {
+ nativeWake(mPtr);
+ }
}
}
@@ -304,9 +313,8 @@ public final class MessageQueue {
throw new AndroidRuntimeException("Message must have a target.");
}
- boolean needWake;
synchronized (this) {
- if (mQuiting) {
+ if (mQuitting) {
RuntimeException e = new RuntimeException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
@@ -315,6 +323,7 @@ public final class MessageQueue {
msg.when = when;
Message p = mMessages;
+ boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
@@ -339,9 +348,11 @@ public final class MessageQueue {
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
- }
- if (needWake) {
- nativeWake(mPtr);
+
+ // We can assume mPtr != 0 because mQuitting is false.
+ if (needWake) {
+ nativeWake(mPtr);
+ }
}
return true;
}
@@ -381,7 +392,11 @@ public final class MessageQueue {
}
boolean isIdling() {
- return nativeIsIdling(mPtr);
+ synchronized (this) {
+ // If the loop is quitting then it must not be idling.
+ // We can assume mPtr != 0 when mQuitting is false.
+ return !mQuitting && nativeIsIdling(mPtr);
+ }
}
void removeMessages(Handler h, int what, Object object) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 83426ae..a3752a1 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -140,16 +140,6 @@ public class UserManager {
*/
public static final String DISALLOW_REMOVE_USER = "no_remove_user";
- /**
- * Key for user restrictions. Specifies if a user is disallowed from setting app restrictions
- * via a restrictions PIN. The default is <code>false</code>. If app restrictions have already
- * been set up, then this user restriction cannot be set to true.
- * <p/>
- * Type: Boolean
- * @see #hasRestrictionsPin()
- */
- public static final String DISALLOW_APP_RESTRICTIONS = "no_app_restrictions";
-
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
@@ -357,7 +347,18 @@ public class UserManager {
* @param restrictionKey the string key representing the restriction
*/
public boolean hasUserRestriction(String restrictionKey) {
- return getUserRestrictions().getBoolean(restrictionKey, false);
+ return hasUserRestriction(restrictionKey, Process.myUserHandle());
+ }
+
+ /**
+ * @hide
+ * Returns whether the given user has been disallowed from performing certain actions
+ * or setting certain settings.
+ * @param restrictionKey the string key representing the restriction
+ * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
+ */
+ public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
+ return getUserRestrictions(userHandle).getBoolean(restrictionKey, false);
}
/**
@@ -639,15 +640,14 @@ public class UserManager {
}
/**
- * @hide
- * Sets a new restrictions PIN. This should only be called after verifying that there
- * currently isn't a PIN set, or after the user successfully enters the current PIN.
- * @param newPin
- * @return Returns true if the PIN was changed successfully.
+ * Sets a new challenge PIN for restrictions. This is only for use by pre-installed
+ * apps and requires the MANAGE_USERS permission.
+ * @param newPin the PIN to use for challenge dialogs.
+ * @return Returns true if the challenge PIN was set successfully.
*/
- public boolean changeRestrictionsPin(String newPin) {
+ public boolean setRestrictionsChallenge(String newPin) {
try {
- return mService.changeRestrictionsPin(newPin);
+ return mService.setRestrictionsChallenge(newPin);
} catch (RemoteException re) {
Log.w(TAG, "Could not change restrictions pin");
}
@@ -663,9 +663,9 @@ public class UserManager {
* Returns {@link #PIN_VERIFICATION_SUCCESS} if the input matches the saved PIN. Returns
* {@link #PIN_VERIFICATION_FAILED_NOT_SET} if there is no PIN set.
*/
- public int checkRestrictionsPin(String pin) {
+ public int checkRestrictionsChallenge(String pin) {
try {
- return mService.checkRestrictionsPin(pin);
+ return mService.checkRestrictionsChallenge(pin);
} catch (RemoteException re) {
Log.w(TAG, "Could not check restrictions pin");
}
@@ -673,16 +673,17 @@ public class UserManager {
}
/**
+ * @hide
* Checks whether the user has restrictions that are PIN-protected. An application that
* participates in restrictions can check if the owner has requested a PIN challenge for
* any restricted operations. If there is a PIN in effect, the application should launch
- * the PIN challenge activity {@link android.content.Intent#ACTION_RESTRICTIONS_PIN_CHALLENGE}.
- * @see android.content.Intent#ACTION_RESTRICTIONS_PIN_CHALLENGE
+ * the PIN challenge activity {@link android.content.Intent#ACTION_RESTRICTIONS_CHALLENGE}.
+ * @see android.content.Intent#ACTION_RESTRICTIONS_CHALLENGE
* @return whether a restrictions PIN is in effect.
*/
- public boolean hasRestrictionsPin() {
+ public boolean hasRestrictionsChallenge() {
try {
- return mService.hasRestrictionsPin();
+ return mService.hasRestrictionsChallenge();
} catch (RemoteException re) {
Log.w(TAG, "Could not change restrictions pin");
}
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 0f765fa..a99705b 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -893,15 +893,12 @@ public abstract class PreferenceActivity extends ListActivity implements
* @return true if the fragment class name is valid for this Activity and false otherwise.
*/
protected boolean isValidFragment(String fragmentName) {
- if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.KEY_LIME_PIE) {
- Log.w(TAG, "Subclasses of PreferenceActivity must override isValidFragment(String)"
+ if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.KITKAT) {
+ throw new RuntimeException(
+ "Subclasses of PreferenceActivity must override isValidFragment(String)"
+ " to verify that the Fragment class is valid! " + this.getClass().getName()
+ " has not checked if fragment " + fragmentName + " is valid.");
- // Return true for now, but will eventually return false when all bundled apps
- // have been modified. TODO: change to return false
- return true;
} else {
- Log.i(TAG, "PreferenceActivity built on pre-KLP launching fragment: " + fragmentName);
return true;
}
}
diff --git a/core/java/android/preference/PreferenceGroup.java b/core/java/android/preference/PreferenceGroup.java
index a5e05ba..5f8c78d 100644
--- a/core/java/android/preference/PreferenceGroup.java
+++ b/core/java/android/preference/PreferenceGroup.java
@@ -210,10 +210,7 @@ public abstract class PreferenceGroup extends Preference implements GenericInfla
* @return Whether to allow adding the preference (true), or not (false).
*/
protected boolean onPrepareAddPreference(Preference preference) {
- if (!super.isEnabled()) {
- preference.setEnabled(false);
- }
-
+ preference.onParentChanged(this, shouldDisableDependents());
return true;
}
diff --git a/core/java/android/print/IPrinterDiscoveryObserver.aidl b/core/java/android/print/IPrinterDiscoveryObserver.aidl
index 625f383..b558011 100644
--- a/core/java/android/print/IPrinterDiscoveryObserver.aidl
+++ b/core/java/android/print/IPrinterDiscoveryObserver.aidl
@@ -16,7 +16,6 @@
package android.print;
-import android.print.IPrintClient;
import android.print.PrinterId;
import android.print.PrinterInfo;
@@ -28,5 +27,4 @@ import android.print.PrinterInfo;
oneway interface IPrinterDiscoveryObserver {
void onPrintersAdded(in List<PrinterInfo> printers);
void onPrintersRemoved(in List<PrinterId> printerIds);
- void onPrintersUpdated(in List<PrinterInfo> printerIds);
}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index caa10ae..b1e427e 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -18,10 +18,11 @@ package android.print;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.R;
@@ -29,60 +30,20 @@ import com.android.internal.R;
* This class represents the attributes of a print job.
*/
public final class PrintAttributes implements Parcelable {
- /** Duplex mode: No duplexing */
- public static final int DUPLEX_MODE_NONE = 1 << 0;
- /** Duplex mode: Turn a page along its long edge, e.g. like a book */
- public static final int DUPLEX_MODE_LONG_EDGE = 1 << 1;
- /** Duplex mode: Turn a page along its short edge, e.g. like a notepad */
- public static final int DUPLEX_MODE_SHORT_EDGE = 1 << 2;
-
-
- /** Orientation: Portrait page orientation. */
- public static final int ORIENTATION_PORTRAIT = 1 << 0;
- /** Orientation: Landscape page orientation. */
- public static final int ORIENTATION_LANDSCAPE = 1 << 1;
-
/** Color mode: Monochrome color scheme, e.g. one color is used. */
public static final int COLOR_MODE_MONOCHROME = 1 << 0;
/** Color mode: Color color scheme, e.g. many colors are used. */
public static final int COLOR_MODE_COLOR = 1 << 1;
-
- /** Fitting mode: No fitting. */
- public static final int FITTING_MODE_NONE = 1 << 0;
- /** Fitting mode: Scale the content to fit in the page
- * without cropping it in any dimension. */
- public static final int FITTING_MODE_SCALE_TO_FIT = 1 << 1;
- /**
- * Fitting mode: Uniformly scale the content to fill the entire page
- * potentially cropping the content if it overflows in one dimension.
- */
- public static final int FITTING_MODE_SCALE_TO_FILL = 1 << 2;
-
-
- private static final int VALID_DUPLEX_MODES =
- DUPLEX_MODE_NONE | DUPLEX_MODE_LONG_EDGE | DUPLEX_MODE_SHORT_EDGE;
-
private static final int VALID_COLOR_MODES =
COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
- private static final int VALID_FITTING_MODES =
- FITTING_MODE_NONE | FITTING_MODE_SCALE_TO_FIT | FITTING_MODE_SCALE_TO_FILL;
-
- private static final int VALID_ORIENTATIONS =
- ORIENTATION_PORTRAIT | ORIENTATION_LANDSCAPE;
-
private MediaSize mMediaSize;
private Resolution mResolution;
private Margins mMargins;
- private Tray mInputTray;
- private Tray mOutputTray;
- private int mDuplexMode;
private int mColorMode;
- private int mFittingMode;
- private int mOrientation;
PrintAttributes() {
/* hide constructor */
@@ -92,12 +53,7 @@ public final class PrintAttributes implements Parcelable {
mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
mMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
- mInputTray = (parcel.readInt() == 1) ? Tray.createFromParcel(parcel) : null;
- mOutputTray = (parcel.readInt() == 1) ? Tray.createFromParcel(parcel) : null;
- mDuplexMode = parcel.readInt();
mColorMode = parcel.readInt();
- mFittingMode = parcel.readInt();
- mOrientation = parcel.readInt();
}
/**
@@ -161,71 +117,6 @@ public final class PrintAttributes implements Parcelable {
}
/**
- * Sets the input tray.
- *
- * @return The input tray or <code>null</code> if not set.
- */
- public Tray getInputTray() {
- return mInputTray;
- }
-
- /**
- * Gets the input tray.
- *
- * @param The input tray.
- *
- * @hide
- */
- public void setInputTray(Tray inputTray) {
- mInputTray = inputTray;
- }
-
- /**
- * Gets the output tray.
- *
- * @return The output tray or <code>null</code> if not set.
- */
- public Tray getOutputTray() {
- return mOutputTray;
- }
-
- /**
- * Sets the output tray.
- *
- * @param The output tray.
- *
- * @hide
- */
- public void setOutputTray(Tray outputTray) {
- mOutputTray = outputTray;
- }
-
- /**
- * Gets the duplex mode.
- *
- * @return The duplex mode or zero if not set.
- *
- * @see #DUPLEX_MODE_NONE
- * @see #DUPLEX_MODE_SHORT_EDGE
- * @see #DUPLEX_MODE_LONG_EDGE
- */
- public int getDuplexMode() {
- return mDuplexMode;
- }
-
- /**
- * Sets the duplex mode.
- *
- * @param The duplex mode.
- *
- * @hide
- */
- public void setDuplexMode(int duplexMode) {
- enforceValidDuplexMode(duplexMode);
- mDuplexMode = duplexMode;
- }
-
- /**
* Gets the color mode.
*
* @return The color mode or zero if not set.
@@ -252,62 +143,6 @@ public final class PrintAttributes implements Parcelable {
mColorMode = colorMode;
}
- /**
- * Gets the fitting mode.
- *
- * @return The fitting mode or zero if not set.
- *
- * @see #FITTING_MODE_NONE
- * @see #FITTING_MODE_SCALE_TO_FILL
- * @see #FITTING_MODE_SCALE_TO_FIT
- */
- public int getFittingMode() {
- return mFittingMode;
- }
-
- /**
- * Sets the fitting mode.
- *
- * @param The fitting mode.
- *
- * @see #FITTING_MODE_NONE
- * @see #FITTING_MODE_SCALE_TO_FILL
- * @see #FITTING_MODE_SCALE_TO_FIT
- *
- * @hide
- */
- public void setFittingMode(int fittingMode) {
- enforceValidFittingMode(fittingMode);
- mFittingMode = fittingMode;
- }
-
- /**
- * Gets the orientation.
- *
- * @return The orientation or zero if not set.
- *
- * @see #ORIENTATION_PORTRAIT
- * @see #ORIENTATION_LANDSCAPE
- */
- public int getOrientation() {
- return mOrientation;
- }
-
- /**
- * Sets the orientation.
- *
- * @param The orientation.
- *
- * @see #ORIENTATION_PORTRAIT
- * @see #ORIENTATION_LANDSCAPE
- *
- * @hide
- */
- public void setOrientation(int orientation) {
- enforceValidOrientation(orientation);
- mOrientation = orientation;
- }
-
@Override
public void writeToParcel(Parcel parcel, int flags) {
if (mMediaSize != null) {
@@ -328,22 +163,7 @@ public final class PrintAttributes implements Parcelable {
} else {
parcel.writeInt(0);
}
- if (mInputTray != null) {
- parcel.writeInt(1);
- mInputTray.writeToParcel(parcel);
- } else {
- parcel.writeInt(0);
- }
- if (mOutputTray != null) {
- parcel.writeInt(1);
- mOutputTray.writeToParcel(parcel);
- } else {
- parcel.writeInt(0);
- }
- parcel.writeInt(mDuplexMode);
parcel.writeInt(mColorMode);
- parcel.writeInt(mFittingMode);
- parcel.writeInt(mOrientation);
}
@Override
@@ -356,13 +176,8 @@ public final class PrintAttributes implements Parcelable {
final int prime = 31;
int result = 1;
result = prime * result + mColorMode;
- result = prime * result + mDuplexMode;
- result = prime * result + mFittingMode;
- result = prime * result + mOrientation;
- result = prime * result + ((mInputTray == null) ? 0 : mInputTray.hashCode());
result = prime * result + ((mMargins == null) ? 0 : mMargins.hashCode());
result = prime * result + ((mMediaSize == null) ? 0 : mMediaSize.hashCode());
- result = prime * result + ((mOutputTray == null) ? 0 : mOutputTray.hashCode());
result = prime * result + ((mResolution == null) ? 0 : mResolution.hashCode());
return result;
}
@@ -382,29 +197,6 @@ public final class PrintAttributes implements Parcelable {
if (mColorMode != other.mColorMode) {
return false;
}
- if (mDuplexMode != other.mDuplexMode) {
- return false;
- }
- if (mFittingMode != other.mFittingMode) {
- return false;
- }
- if (mOrientation != other.mOrientation) {
- return false;
- }
- if (mInputTray == null) {
- if (other.mInputTray != null) {
- return false;
- }
- } else if (!mInputTray.equals(other.mInputTray)) {
- return false;
- }
- if (mOutputTray == null) {
- if (other.mOutputTray != null) {
- return false;
- }
- } else if (!mOutputTray.equals(other.mOutputTray)) {
- return false;
- }
if (mMargins == null) {
if (other.mMargins != null) {
return false;
@@ -436,12 +228,7 @@ public final class PrintAttributes implements Parcelable {
builder.append("mediaSize: ").append(mMediaSize);
builder.append(", resolution: ").append(mResolution);
builder.append(", margins: ").append(mMargins);
- builder.append(", inputTray: ").append(mInputTray);
- builder.append(", outputTray: ").append(mOutputTray);
builder.append(", colorMode: ").append(colorModeToString(mColorMode));
- builder.append(", duplexMode: ").append(duplexModeToString(mDuplexMode));
- builder.append(", fittingMode: ").append(fittingModeToString(mFittingMode));
- builder.append(", orientation: ").append(orientationToString(mOrientation));
builder.append("}");
return builder.toString();
}
@@ -451,12 +238,7 @@ public final class PrintAttributes implements Parcelable {
mMediaSize = null;
mResolution = null;
mMargins = null;
- mInputTray = null;
- mOutputTray = null;
- mDuplexMode = 0;
mColorMode = 0;
- mFittingMode = 0;
- mOrientation = 0;
}
/**
@@ -466,483 +248,200 @@ public final class PrintAttributes implements Parcelable {
mMediaSize = other.mMediaSize;
mResolution = other.mResolution;
mMargins = other.mMargins;
- mInputTray = other.mInputTray;
- mOutputTray = other.mOutputTray;
- mDuplexMode = other.mDuplexMode;
mColorMode = other.mColorMode;
- mFittingMode = other.mFittingMode;
- mOrientation = other.mOrientation;
}
/**
* This class specifies a supported media size.
*/
public static final class MediaSize {
+ private static final String LOG_TAG = "MediaSize";
// TODO: Verify media sizes and add more standard ones.
// ISO sizes
- /**
- * ISO A0 media size: 841mm x 1189mm (33.11" x 46.81")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A0 = 1;
-
- /**
- * ISO A1 media size: 594mm x 841mm (23.39" x 33.11")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A1 = 2;
-
- /**
- *
- *ISO A2 media size: 420mm x 594mm (16.54" x 23.39")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A2 = 3;
-
- /**
- * ISO A3 media size: 297mm x 420mm (11.69" x 16.54")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A3 = 4;
-
- /**
- * ISO A4 media size: 210mm x 297mm (8.27" x 11.69")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A4 = 5;
-
- /**
- * ISO A5 media size: 148mm x 210mm (5.83" x 8.27")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A5 = 6;
-
- /**
- * ISO A6 media size: 105mm x 148mm (4.13" x 5.83")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A6 = 7;
-
- /**
- * ISO A7 media size: 74mm x 105mm (2.91" x 4.13")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A7 = 8;
-
- /**
- * ISO A8 media size: 52mm x 74mm (2.05" x 2.91")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A8 = 9;
-
- /**
- * ISO A9 media size: 37mm x 52mm (1.46" x 2.05")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A9 = 10;
-
- /**
- * ISO A10 media size: 26mm x 37mm (1.02" x 1.46")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_A10 = 11;
-
-
- /**
- * ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B0 = 100;
-
- /**
- * ISO B1 media size: 707mm x 1000mm (27.83" x 39.37")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B1 = 101;
-
- /**
- * ISO B2 media size: 500mm x 707mm (19.69" x 27.83")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B2 = 102;
-
- /**
- * ISO B3 media size: 353mm x 500mm (13.90" x 19.69")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B3 = 103;
-
- /**
- * ISO B4 media size: 250mm x 353mm (9.84" x 13.90")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B4 = 104;
-
- /**
- * ISO B5 media size: 176mm x 250mm (6.93" x 9.84")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B5 = 105;
-
- /**
- * ISO B6 media size: 125mm x 176mm (4.92" x 6.93")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B6 = 106;
-
- /**
- * ISO B7 media size: 88mm x 125mm (3.46" x 4.92")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B7 = 107;
-
- /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B8 = 108;
-
- /**
- * ISO B9 media size: 44mm x 62mm (1.73" x 2.44")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B9 = 109;
-
- /**
- * ISO B10 media size: 31mm x 44mm (1.22" x 1.73")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_B10 = 110;
-
-
- /**
- * ISO C0 media size: 917mm x 1297mm (36.10" x 51.06")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C0 = 200;
-
- /**
- * ISO C1 media size: 648mm x 917mm (25.51" x 36.10")
- *
- * @see #createMediaSize(PackageManager, int)
- */
-
- public static final int ISO_C1 = 201;
- /**
- * ISO C2 media size: 458mm x 648mm (18.03" x 25.51")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C2 = 202;
-
- /**
- * ISO C3 media size: 324mm x 458mm (12.76" x 18.03")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C3 = 203;
-
- /**
- * ISO C4 media size: 229mm x 324mm (9.02" x 12.76")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C4 = 204;
-
- /**
- * ISO C5 media size: 162mm x 229mm (6.38" x 9.02")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C5 = 205;
-
- /**
- * ISO C6 media size: 114mm x 162mm (4.49" x 6.38")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C6 = 206;
-
- /**
- * ISO C7 media size: 81mm x 114mm (3.19" x 4.49")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C7 = 207;
-
- /**
- * ISO C8 media size: 57mm x 81mm (2.24" x 3.19")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C8 = 208;
-
- /**
- * ISO C9 media size: 40mm x 57mm (1.57" x 2.24")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C9 = 209;
-
- /**
- * ISO C10 media size: 28mm x 40mm (1.10" x 1.57")
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int ISO_C10 = 210;
-
+ /** ISO A0 media size: 841mm x 1189mm (33.11" x 46.81") */
+ public static final MediaSize ISO_A0 =
+ new MediaSize("ISO_A0", "android", R.string.mediaSize_iso_a0, 33110, 46810);
+ /** ISO A1 media size: 594mm x 841mm (23.39" x 33.11") */
+ public static final MediaSize ISO_A1 =
+ new MediaSize("ISO_A1", "android", R.string.mediaSize_iso_a1, 23390, 33110);
+ /** ISO A2 media size: 420mm x 594mm (16.54" x 23.39") */
+ public static final MediaSize ISO_A2 =
+ new MediaSize("ISO_A2", "android", R.string.mediaSize_iso_a2, 16540, 23390);
+ /** ISO A3 media size: 297mm x 420mm (11.69" x 16.54") */
+ public static final MediaSize ISO_A3 =
+ new MediaSize("ISO_A3", "android", R.string.mediaSize_iso_a3, 11690, 16540);
+ /** ISO A4 media size: 210mm x 297mm (8.27" x 11.69") */
+ public static final MediaSize ISO_A4 =
+ new MediaSize("ISO_A4", "android", R.string.mediaSize_iso_a4, 8270, 11690);
+ /** ISO A5 media size: 148mm x 210mm (5.83" x 8.27") */
+ public static final MediaSize ISO_A5 =
+ new MediaSize("ISO_A5", "android", R.string.mediaSize_iso_a5, 5830, 8270);
+ /** ISO A6 media size: 105mm x 148mm (4.13" x 5.83") */
+ public static final MediaSize ISO_A6 =
+ new MediaSize("ISO_A6", "android", R.string.mediaSize_iso_a6, 4130, 5830);
+ /** ISO A7 media size: 74mm x 105mm (2.91" x 4.13") */
+ public static final MediaSize ISO_A7 =
+ new MediaSize("ISO_A7", "android", R.string.mediaSize_iso_a7, 2910, 4130);
+ /** ISO A8 media size: 52mm x 74mm (2.05" x 2.91") */
+ public static final MediaSize ISO_A8 =
+ new MediaSize("ISO_A8", "android", R.string.mediaSize_iso_a8, 2050, 2910);
+ /** ISO A9 media size: 37mm x 52mm (1.46" x 2.05") */
+ public static final MediaSize ISO_A9 =
+ new MediaSize("ISO_A9", "android", R.string.mediaSize_iso_a9, 1460, 2050);
+ /** ISO A10 media size: 26mm x 37mm (1.02" x 1.46") */
+ public static final MediaSize ISO_A10 =
+ new MediaSize("ISO_A10", "android", R.string.mediaSize_iso_a10, 1020, 1460);
+
+ /** ISO B0 media size: 1000mm x 1414mm (39.37" x 55.67") */
+ public static final MediaSize ISO_B0 =
+ new MediaSize("ISO_B0", "android", R.string.mediaSize_iso_b0, 39370, 55670);
+ /** ISO B1 media size: 707mm x 1000mm (27.83" x 39.37") */
+ public static final MediaSize ISO_B1 =
+ new MediaSize("ISO_B1", "android", R.string.mediaSize_iso_b1, 27830, 39370);
+ /** ISO B2 media size: 500mm x 707mm (19.69" x 27.83") */
+ public static final MediaSize ISO_B2 =
+ new MediaSize("ISO_B2", "android", R.string.mediaSize_iso_b2, 19690, 27830);
+ /** ISO B3 media size: 353mm x 500mm (13.90" x 19.69") */
+ public static final MediaSize ISO_B3 =
+ new MediaSize("ISO_B3", "android", R.string.mediaSize_iso_b3, 13900, 19690);
+ /** ISO B4 media size: 250mm x 353mm (9.84" x 13.90") */
+ public static final MediaSize ISO_B4 =
+ new MediaSize("ISO_B4", "android", R.string.mediaSize_iso_b4, 9840, 13900);
+ /** ISO B5 media size: 176mm x 250mm (6.93" x 9.84") */
+ public static final MediaSize ISO_B5 =
+ new MediaSize("ISO_B5", "android", R.string.mediaSize_iso_b5, 6930, 9840);
+ /** ISO B6 media size: 125mm x 176mm (4.92" x 6.93") */
+ public static final MediaSize ISO_B6 =
+ new MediaSize("ISO_B6", "android", R.string.mediaSize_iso_b6, 4920, 6930);
+ /** ISO B7 media size: 88mm x 125mm (3.46" x 4.92") */
+ public static final MediaSize ISO_B7 =
+ new MediaSize("ISO_B7", "android", R.string.mediaSize_iso_b7, 3460, 4920);
+ /** ISO B8 media size: 62mm x 88mm (2.44" x 3.46") */
+ public static final MediaSize ISO_B8 =
+ new MediaSize("ISO_B8", "android", R.string.mediaSize_iso_b8, 2440, 3460);
+ /** ISO B9 media size: 44mm x 62mm (1.73" x 2.44") */
+ public static final MediaSize ISO_B9 =
+ new MediaSize("ISO_B9", "android", R.string.mediaSize_iso_b9, 1730, 2440);
+ /** ISO B10 media size: 31mm x 44mm (1.22" x 1.73") */
+ public static final MediaSize ISO_B10 =
+ new MediaSize("ISO_B10", "android", R.string.mediaSize_iso_b10, 1220, 1730);
+
+ /** ISO C0 media size: 917mm x 1297mm (36.10" x 51.06") */
+ public static final MediaSize ISO_C0 =
+ new MediaSize("ISO_C0", "android", R.string.mediaSize_iso_c0, 36100, 51060);
+ /** ISO C1 media size: 648mm x 917mm (25.51" x 36.10") */
+ public static final MediaSize ISO_C1 =
+ new MediaSize("ISO_C1", "android", R.string.mediaSize_iso_c1, 25510, 36100);
+ /** ISO C2 media size: 458mm x 648mm (18.03" x 25.51") */
+ public static final MediaSize ISO_C2 =
+ new MediaSize("ISO_C2", "android", R.string.mediaSize_iso_c2, 18030, 25510);
+ /** ISO C3 media size: 324mm x 458mm (12.76" x 18.03") */
+ public static final MediaSize ISO_C3 =
+ new MediaSize("ISO_C3", "android", R.string.mediaSize_iso_c3, 12760, 18030);
+ /** ISO C4 media size: 229mm x 324mm (9.02" x 12.76") */
+ public static final MediaSize ISO_C4 =
+ new MediaSize("ISO_C4", "android", R.string.mediaSize_iso_c4, 9020, 12760);
+ /** ISO C5 media size: 162mm x 229mm (6.38" x 9.02") */
+ public static final MediaSize ISO_C5 =
+ new MediaSize("ISO_C5", "android", R.string.mediaSize_iso_c5, 6380, 9020);
+ /** ISO C6 media size: 114mm x 162mm (4.49" x 6.38") */
+ public static final MediaSize ISO_C6 =
+ new MediaSize("ISO_C6", "android", R.string.mediaSize_iso_c6, 4490, 6380);
+ /** ISO C7 media size: 81mm x 114mm (3.19" x 4.49") */
+ public static final MediaSize ISO_C7 =
+ new MediaSize("ISO_C7", "android", R.string.mediaSize_iso_c7, 3190, 4490);
+ /** ISO C8 media size: 57mm x 81mm (2.24" x 3.19") */
+ public static final MediaSize ISO_C8 =
+ new MediaSize("ISO_C8", "android", R.string.mediaSize_iso_c8, 2240, 3190);
+ /** ISO C9 media size: 40mm x 57mm (1.57" x 2.24") */
+ public static final MediaSize ISO_C9 =
+ new MediaSize("ISO_C9", "android", R.string.mediaSize_iso_c9, 1570, 2240);
+ /** ISO C10 media size: 28mm x 40mm (1.10" x 1.57") */
+ public static final MediaSize ISO_C10 =
+ new MediaSize("ISO_C10", "android", R.string.mediaSize_iso_c10, 1100, 1570);
// North America
- /**
- * North America Letter media size: 8.5" x 11"
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int NA_LETTER = 300;
-
- /**
- * North America Government-Letter media size: 8.0" x 10.5"
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int NA_GOVT_LETTER = 301;
-
- /**
- * North America Legal media size: 8.5" x 14"
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int NA_LEGAL = 302;
+ /** North America Letter media size: 8.5" x 11" */
+ public static final MediaSize NA_LETTER =
+ new MediaSize("NA_LETTER", "android", R.string.mediaSize_na_letter, 8500, 11000);
+ /** North America Government-Letter media size: 8.0" x 10.5" */
+ public static final MediaSize NA_GOVT_LETTER =
+ new MediaSize("NA_GOVT_LETTER", "android",
+ R.string.mediaSize_na_gvrnmt_letter, 8000, 10500);
+ /** North America Legal media size: 8.5" x 14" */
+ public static final MediaSize NA_LEGAL =
+ new MediaSize("NA_LEGAL", "android", R.string.mediaSize_na_legal, 8500, 14000);
+ /** North America Junior Legal media size: 8.0" x 5.0" */
+ public static final MediaSize NA_JUNIOR_LEGAL =
+ new MediaSize("NA_JUNIOR_LEGAL", "android",
+ R.string.mediaSize_na_junior_legal, 8000, 5000);
+ /** North America Ledger media size: 17" x 11" */
+ public static final MediaSize NA_LEDGER =
+ new MediaSize("NA_LEDGER", "android", R.string.mediaSize_na_ledger, 17000, 11000);
+ /** North America Tabloid media size: 11" x 17" */
+ public static final MediaSize NA_TBLOID =
+ new MediaSize("NA_TABLOID", "android",
+ R.string.mediaSize_na_tabloid, 11000, 17000);
- /**
- * North America Junior Legal media size: 8.0" x 5.0"
- *
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int NA_JUNIOR_LEGAL = 303;
+ private final String mId;
+ /**@hide */
+ public final String mLabel;
+ /**@hide */
+ public final String mPackageName;
+ /**@hide */
+ public final int mLabelResId;
+ private final int mWidthMils;
+ private final int mHeightMils;
/**
- * North America Ledger media size: 17" x 11"
+ * Creates a new instance. This is the preferred constructor since
+ * it enables the media size label to be shown in a localized fashion
+ * on a locale change.
*
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int NA_LEDGER = 304;
-
- /**
- * North America Tabloid media size: 11" x 17"
+ * @param id The unique media size id.
+ * @param packageName The name of the creating package.
+ * @param labelResId The resource if of a human readable label.
+ * @param widthMils The width in mils (thousands of an inch).
+ * @param heightMils The height in mils (thousands of an inch).
*
- * @see #createMediaSize(PackageManager, int)
- */
- public static final int NA_TBLOID = 305;
-
- /**
- * Creates a standard media size with a localized label.
+ * @throws IllegalArgumentException If the id is empty.
+ * @throws IllegalArgumentException If the label is empty.
+ * @throws IllegalArgumentException If the widthMils is less than or equal to zero.
+ * @throws IllegalArgumentException If the heightMils is less than or equal to zero.
*
- * @param pm Package manager used to load the label.
- * @param mediaSize Media size constant.
- * @return A {@link MediaSize} instance with a localized label.
+ * @hide
*/
- public static MediaSize createMediaSize(PackageManager pm, int mediaSize) {
- final Resources resources;
- try {
- resources = pm.getResourcesForApplication("android");
- } catch (NameNotFoundException nnfe) {
- return null;
+ public MediaSize(String id, String packageName, int labelResId,
+ int widthMils, int heightMils) {
+ if (TextUtils.isEmpty(id)) {
+ throw new IllegalArgumentException("id cannot be empty.");
}
- switch (mediaSize) {
- case ISO_A0: {
- return new MediaSize("ISO_A0", resources
- .getString(R.string.mediaSize_iso_a0), 33110, 46810);
- }
- case ISO_A1: {
- return new MediaSize("ISO_A1", resources
- .getString(R.string.mediaSize_iso_a1), 23390, 33110);
- }
- case ISO_A2: {
- return new MediaSize("ISO_A2", resources
- .getString(R.string.mediaSize_iso_a2), 16540, 23390);
- }
- case ISO_A3: {
- return new MediaSize("ISO_A3", resources
- .getString(R.string.mediaSize_iso_a3), 11690, 16540);
- }
- case ISO_A4: {
- return new MediaSize("ISO_A4", resources
- .getString(R.string.mediaSize_iso_a4), 8270, 11690);
- }
- case ISO_A5: {
- return new MediaSize("ISO_A5", resources
- .getString(R.string.mediaSize_iso_a5), 5830, 8270);
- }
- case ISO_A6: {
- return new MediaSize("ISO_A6", resources
- .getString(R.string.mediaSize_iso_a6), 4130, 5830);
- }
- case ISO_A7: {
- return new MediaSize("ISO_A7", resources
- .getString(R.string.mediaSize_iso_a7), 2910, 4130);
- }
- case ISO_A8: {
- return new MediaSize("ISO_A8", resources
- .getString(R.string.mediaSize_iso_a8), 2050, 2910);
- }
- case ISO_A9: {
- return new MediaSize("ISO_A9", resources
- .getString(R.string.mediaSize_iso_a9), 1460, 2050);
- }
- case ISO_A10: {
- return new MediaSize("ISO_A10", resources
- .getString(R.string.mediaSize_iso_a10), 1020, 1460);
- }
- case ISO_B0: {
- return new MediaSize("ISO_B0", resources
- .getString(R.string.mediaSize_iso_b0), 39370, 55670);
- }
- case ISO_B1: {
- return new MediaSize("ISO_B1", resources
- .getString(R.string.mediaSize_iso_b1), 27830, 39370);
- }
- case ISO_B2: {
- return new MediaSize("ISO_B2", resources
- .getString(R.string.mediaSize_iso_b2), 19690, 27830);
- }
- case ISO_B3: {
- return new MediaSize("ISO_B3", resources
- .getString(R.string.mediaSize_iso_b3), 13900, 19690);
- }
- case ISO_B4: {
- return new MediaSize("ISO_B4", resources
- .getString(R.string.mediaSize_iso_b4), 9840, 13900);
- }
- case ISO_B5: {
- return new MediaSize("ISO_B5", resources
- .getString(R.string.mediaSize_iso_b5), 6930, 9840);
- }
- case ISO_B6: {
- return new MediaSize("ISO_B6", resources
- .getString(R.string.mediaSize_iso_b6), 4920, 6930);
- }
- case ISO_B7: {
- return new MediaSize("ISO_B7", resources
- .getString(R.string.mediaSize_iso_b7), 3460, 4920);
- }
- case ISO_B8: {
- return new MediaSize("ISO_B8", resources
- .getString(R.string.mediaSize_iso_b8), 2440, 3460);
- }
- case ISO_B9: {
- return new MediaSize("ISO_B9", resources
- .getString(R.string.mediaSize_iso_b9), 1730, 2440);
- }
- case ISO_B10: {
- return new MediaSize("ISO_B10", resources
- .getString(R.string.mediaSize_iso_b10), 1220, 1730);
- }
- case ISO_C0: {
- return new MediaSize("ISO_C0", resources
- .getString(R.string.mediaSize_iso_c0), 36100, 51060);
- }
- case ISO_C1: {
- return new MediaSize("ISO_C1", resources
- .getString(R.string.mediaSize_iso_c1), 25510, 36100);
- }
- case ISO_C2: {
- return new MediaSize("ISO_C2", resources
- .getString(R.string.mediaSize_iso_c2), 18030, 25510);
- }
- case ISO_C3: {
- return new MediaSize("ISO_C3", resources
- .getString(R.string.mediaSize_iso_c3), 12760, 18030);
- }
- case ISO_C4: {
- return new MediaSize("ISO_C4", resources
- .getString(R.string.mediaSize_iso_c4), 9020, 12760);
- }
- case ISO_C5: {
- return new MediaSize("ISO_C5", resources
- .getString(R.string.mediaSize_iso_c5), 6380, 9020);
- }
- case ISO_C6: {
- return new MediaSize("ISO_C6", resources
- .getString(R.string.mediaSize_iso_c6), 4490, 6380);
- }
- case ISO_C7: {
- return new MediaSize("ISO_C7", resources
- .getString(R.string.mediaSize_iso_c7), 3190, 4490);
- }
- case ISO_C8: {
- return new MediaSize("ISO_C8", resources
- .getString(R.string.mediaSize_iso_c8), 2240, 3190);
- }
- case ISO_C9: {
- return new MediaSize("ISO_C9", resources
- .getString(R.string.mediaSize_iso_c9), 1570, 2240);
- }
- case ISO_C10: {
- return new MediaSize("ISO_C10", resources
- .getString(R.string.mediaSize_iso_c10), 1100, 1570);
- }
- case NA_LETTER: {
- return new MediaSize("NA_LETTER", resources
- .getString(R.string.mediaSize_na_letter), 8500, 11000);
- }
- case NA_GOVT_LETTER: {
- return new MediaSize("NA_GOVT_LETTER", resources
- .getString(R.string.mediaSize_na_gvrnmt_letter), 8000, 10500);
- }
- case NA_LEGAL: {
- return new MediaSize("NA_LEGAL", resources
- .getString(R.string.mediaSize_na_legal), 8500, 14000);
- }
- case NA_JUNIOR_LEGAL: {
- return new MediaSize("NA_JUNIOR_LEGAL", resources
- .getString(R.string.mediaSize_na_junior_legal), 8000, 5000);
- }
- case NA_LEDGER: {
- return new MediaSize("NA_LEDGER", resources
- .getString(R.string.mediaSize_na_ledger), 17000, 11000);
- }
- case NA_TBLOID: {
- return new MediaSize("NA_TABLOID", resources
- .getString(R.string.mediaSize_na_tabloid), 11000, 17000);
- }
- default: {
- throw new IllegalArgumentException("Unknown media size.");
- }
+ if (TextUtils.isEmpty(packageName)) {
+ throw new IllegalArgumentException("packageName cannot be empty.");
+ }
+ if (labelResId <= 0) {
+ throw new IllegalArgumentException("labelResId must be greater than zero.");
+ }
+ if (widthMils <= 0) {
+ throw new IllegalArgumentException("widthMils "
+ + "cannot be less than or equal to zero.");
}
+ if (heightMils <= 0) {
+ throw new IllegalArgumentException("heightMils "
+ + "cannot be less than or euqual to zero.");
+ }
+ mPackageName = packageName;
+ mId = id;
+ mLabelResId = labelResId;
+ mWidthMils = widthMils;
+ mHeightMils = heightMils;
+ mLabel = null;
}
- private final String mId;
- private final String mLabel;
- private final int mWidthMils;
- private final int mHeightMils;
-
/**
* Creates a new instance.
*
@@ -975,6 +474,19 @@ public final class PrintAttributes implements Parcelable {
mLabel = label;
mWidthMils = widthMils;
mHeightMils = heightMils;
+ mLabelResId = 0;
+ mPackageName = null;
+ }
+
+ /** @hide */
+ public MediaSize(String id, String label, String packageName,
+ int widthMils, int heightMils, int labelResId) {
+ mPackageName = packageName;
+ mId = id;
+ mLabelResId = labelResId;
+ mWidthMils = widthMils;
+ mHeightMils = heightMils;
+ mLabel = label;
}
/**
@@ -989,9 +501,22 @@ public final class PrintAttributes implements Parcelable {
/**
* Gets the human readable media size label.
*
+ * @param packageManager The package manager for loading the label.
* @return The human readable label.
*/
- public String getLabel() {
+ public String getLabel(PackageManager packageManager) {
+ if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
+ try {
+ return packageManager.getResourcesForApplication(
+ mPackageName).getString(mLabelResId);
+ } catch (NotFoundException nfe) {
+ Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+ + " from package " + mPackageName);
+ } catch (NameNotFoundException nnfee) {
+ Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+ + " from package " + mPackageName);
+ }
+ }
return mLabel;
}
@@ -1013,17 +538,58 @@ public final class PrintAttributes implements Parcelable {
return mHeightMils;
}
+ /**
+ * Gets whether this media size is in portrait which is the
+ * height is greater or equal to the width.
+ *
+ * @return True if the media size is in portrait, false if
+ * it is in landscape.
+ */
+ public boolean isPortrait() {
+ return mHeightMils >= mWidthMils;
+ }
+
+ /**
+ * Returns a new media size in a portrait orientation
+ * which is the height is the greater dimension.
+ *
+ * @return New instance in landscape orientation.
+ */
+ public MediaSize asPortrait() {
+ return new MediaSize(mId, mLabel, mPackageName,
+ Math.min(mWidthMils, mHeightMils),
+ Math.max(mWidthMils, mHeightMils),
+ mLabelResId);
+ }
+
+ /**
+ * Returns a new media size in a landscape orientation
+ * which is the height is the lesser dimension.
+ *
+ * @return New instance in landscape orientation.
+ */
+ public MediaSize asLandscape() {
+ return new MediaSize(mId, mLabel, mPackageName,
+ Math.max(mWidthMils, mHeightMils),
+ Math.min(mWidthMils, mHeightMils),
+ mLabelResId);
+ }
+
void writeToParcel(Parcel parcel) {
parcel.writeString(mId);
parcel.writeString(mLabel);
+ parcel.writeString(mPackageName);
parcel.writeInt(mWidthMils);
parcel.writeInt(mHeightMils);
+ parcel.writeInt(mLabelResId);
}
static MediaSize createFromParcel(Parcel parcel) {
return new MediaSize(
parcel.readString(),
parcel.readString(),
+ parcel.readString(),
+ parcel.readInt(),
parcel.readInt(),
parcel.readInt());
}
@@ -1032,8 +598,6 @@ public final class PrintAttributes implements Parcelable {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((mId == null) ? 0 : mId.hashCode());
- result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode());
result = prime * result + mWidthMils;
result = prime * result + mHeightMils;
return result;
@@ -1051,12 +615,6 @@ public final class PrintAttributes implements Parcelable {
return false;
}
MediaSize other = (MediaSize) obj;
- if (!TextUtils.equals(mId, other.mId)) {
- return false;
- }
- if (!TextUtils.equals(mLabel, other.mLabel)) {
- return false;
- }
if (mWidthMils != other.mWidthMils) {
return false;
}
@@ -1072,8 +630,10 @@ public final class PrintAttributes implements Parcelable {
builder.append("MediaSize{");
builder.append("id: ").append(mId);
builder.append(", label: ").append(mLabel);
+ builder.append(", packageName: ").append(mPackageName);
builder.append(", heightMils: ").append(mHeightMils);
builder.append(", widthMils: ").append(mWidthMils);
+ builder.append(", labelResId: ").append(mLabelResId);
builder.append("}");
return builder.toString();
}
@@ -1083,12 +643,64 @@ public final class PrintAttributes implements Parcelable {
* This class specifies a supported resolution in dpi (dots per inch).
*/
public static final class Resolution {
+ private static final String LOG_TAG = "Resolution";
+
private final String mId;
- private final String mLabel;
+ /**@hide */
+ public final String mLabel;
+ /**@hide */
+ public final String mPackageName;
+ /**@hide */
+ public final int mLabelResId;
private final int mHorizontalDpi;
private final int mVerticalDpi;
/**
+ * Creates a new instance. This is the preferred constructor since
+ * it enables the resolution label to be shown in a localized fashion
+ * on a locale change.
+ *
+ * @param id The unique resolution id.
+ * @param packageName The name of the creating package.
+ * @param labelResId The resource id of a human readable label.
+ * @param horizontalDpi The horizontal resolution in dpi.
+ * @param verticalDpi The vertical resolution in dpi.
+ *
+ * @throws IllegalArgumentException If the id is empty.
+ * @throws IllegalArgumentException If the label is empty.
+ * @throws IllegalArgumentException If the horizontalDpi is less than or equal to zero.
+ * @throws IllegalArgumentException If the verticalDpi is less than or equal to zero.
+ *
+ * @hide
+ */
+ public Resolution(String id, String packageName, int labelResId,
+ int horizontalDpi, int verticalDpi) {
+ if (TextUtils.isEmpty(id)) {
+ throw new IllegalArgumentException("id cannot be empty.");
+ }
+ if (TextUtils.isEmpty(packageName)) {
+ throw new IllegalArgumentException("packageName cannot be empty.");
+ }
+ if (labelResId <= 0) {
+ throw new IllegalArgumentException("labelResId must be greater than zero.");
+ }
+ if (horizontalDpi <= 0) {
+ throw new IllegalArgumentException("horizontalDpi "
+ + "cannot be less than or equal to zero.");
+ }
+ if (verticalDpi <= 0) {
+ throw new IllegalArgumentException("verticalDpi"
+ + " cannot be less than or equal to zero.");
+ }
+ mId = id;
+ mPackageName = packageName;
+ mLabelResId = labelResId;
+ mHorizontalDpi = horizontalDpi;
+ mVerticalDpi = verticalDpi;
+ mLabel = null;
+ }
+
+ /**
* Creates a new instance.
*
* @param id The unique resolution id.
@@ -1120,6 +732,19 @@ public final class PrintAttributes implements Parcelable {
mLabel = label;
mHorizontalDpi = horizontalDpi;
mVerticalDpi = verticalDpi;
+ mPackageName = null;
+ mLabelResId = 0;
+ }
+
+ /** @hide */
+ public Resolution(String id, String label, String packageName,
+ int horizontalDpi, int verticalDpi, int labelResId) {
+ mId = id;
+ mPackageName = packageName;
+ mLabelResId = labelResId;
+ mHorizontalDpi = horizontalDpi;
+ mVerticalDpi = verticalDpi;
+ mLabel = label;
}
/**
@@ -1134,14 +759,27 @@ public final class PrintAttributes implements Parcelable {
/**
* Gets the resolution human readable label.
*
+ * @param packageManager The package manager for loading the label.
* @return The human readable label.
*/
- public String getLabel() {
+ public String getLabel(PackageManager packageManager) {
+ if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
+ try {
+ return packageManager.getResourcesForApplication(
+ mPackageName).getString(mLabelResId);
+ } catch (NotFoundException nfe) {
+ Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+ + " from package " + mPackageName);
+ } catch (NameNotFoundException nnfee) {
+ Log.w(LOG_TAG, "Could not load resouce" + mLabelResId
+ + " from package " + mPackageName);
+ }
+ }
return mLabel;
}
/**
- * Gets the horizontal resolution in dpi.
+ * Gets the vertical resolution in dpi.
*
* @return The horizontal resolution.
*/
@@ -1161,14 +799,18 @@ public final class PrintAttributes implements Parcelable {
void writeToParcel(Parcel parcel) {
parcel.writeString(mId);
parcel.writeString(mLabel);
+ parcel.writeString(mPackageName);
parcel.writeInt(mHorizontalDpi);
parcel.writeInt(mVerticalDpi);
+ parcel.writeInt(mLabelResId);
}
static Resolution createFromParcel(Parcel parcel) {
return new Resolution(
parcel.readString(),
parcel.readString(),
+ parcel.readString(),
+ parcel.readInt(),
parcel.readInt(),
parcel.readInt());
}
@@ -1177,8 +819,6 @@ public final class PrintAttributes implements Parcelable {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((mId == null) ? 0 : mId.hashCode());
- result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode());
result = prime * result + mHorizontalDpi;
result = prime * result + mVerticalDpi;
return result;
@@ -1196,12 +836,6 @@ public final class PrintAttributes implements Parcelable {
return false;
}
Resolution other = (Resolution) obj;
- if (!TextUtils.equals(mId, other.mId)) {
- return false;
- }
- if (!TextUtils.equals(mLabel, other.mLabel)) {
- return false;
- }
if (mHorizontalDpi != other.mHorizontalDpi) {
return false;
}
@@ -1217,8 +851,10 @@ public final class PrintAttributes implements Parcelable {
builder.append("Resolution{");
builder.append("id: ").append(mId);
builder.append(", label: ").append(mLabel);
+ builder.append(", packageName: ").append(mPackageName);
builder.append(", horizontalDpi: ").append(mHorizontalDpi);
builder.append(", verticalDpi: ").append(mVerticalDpi);
+ builder.append(", labelResId: ").append(mLabelResId);
builder.append("}");
return builder.toString();
}
@@ -1358,120 +994,6 @@ public final class PrintAttributes implements Parcelable {
}
}
- /**
- * Represents a printer tray.
- */
- public static final class Tray {
- private final String mId;
- private final String mLabel;
-
- /**
- * Creates a new instance.
- *
- * @param id The unique tray id.
- * @param label The <strong>internationalized</strong> human readable label.
- *
- * @throws IllegalArgumentException If the id is empty.
- * @throws IllegalArgumentException If the label is empty.
- */
- public Tray(String id, String label) {
- if (TextUtils.isEmpty(id)) {
- throw new IllegalArgumentException("id cannot be empty.");
- }
- if (TextUtils.isEmpty(label)) {
- throw new IllegalArgumentException("label cannot be empty.");
- }
- mId = id;
- mLabel = label;
- }
-
- /**
- * Gets the unique tray id.
- *
- * @return The unique tray id.
- */
- public String getId() {
- return mId;
- }
-
- /**
- * Gets the tray human readable label.
- *
- * @return The human readable label.
- */
- public String getLabel() {
- return mLabel;
- }
-
- void writeToParcel(Parcel parcel) {
- parcel.writeString(mId);
- parcel.writeString(mLabel);
- }
-
- static Tray createFromParcel(Parcel parcel) {
- return new Tray(
- parcel.readString(),
- parcel.readString());
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mId == null) ? 0 : mId.hashCode());
- result = prime * result + ((mLabel == null) ? 0 : mLabel.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- Tray other = (Tray) obj;
- if (!TextUtils.equals(mId, other.mId)) {
- return false;
- }
- if (!TextUtils.equals(mLabel, other.mLabel)) {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("Tray{");
- builder.append("id: ").append(mId);
- builder.append("id: ").append(mId);
- builder.append(", label: ").append(mLabel);
- builder.append("}");
- return builder.toString();
- }
- }
-
- static String duplexModeToString(int duplexMode) {
- switch (duplexMode) {
- case DUPLEX_MODE_NONE: {
- return "DUPLEX_MODE_NONE";
- }
- case DUPLEX_MODE_LONG_EDGE: {
- return "DUPLEX_MODE_LONG_EDGE";
- }
- case DUPLEX_MODE_SHORT_EDGE: {
- return "DUPLEX_MODE_SHORT_EDGE";
- }
- default:
- return "DUPLEX_MODE_UNKNOWN";
- }
- }
-
static String colorModeToString(int colorMode) {
switch (colorMode) {
case COLOR_MODE_MONOCHROME: {
@@ -1485,59 +1007,12 @@ public final class PrintAttributes implements Parcelable {
}
}
- static String orientationToString(int orientation) {
- switch (orientation) {
- case ORIENTATION_PORTRAIT: {
- return "ORIENTATION_PORTRAIT";
- }
- case ORIENTATION_LANDSCAPE: {
- return "ORIENTATION_LANDSCAPE";
- }
- default:
- return "ORIENTATION_UNKNOWN";
- }
- }
-
- static String fittingModeToString(int fittingMode) {
- switch (fittingMode) {
- case FITTING_MODE_NONE: {
- return "FITTING_MODE_NONE";
- }
- case FITTING_MODE_SCALE_TO_FIT: {
- return "FITTING_MODE_SCALE_TO_FIT";
- }
- case FITTING_MODE_SCALE_TO_FILL: {
- return "FITTING_MODE_SCALE_TO_FILL";
- }
- default:
- return "FITTING_MODE_UNKNOWN";
- }
- }
-
- static void enforceValidDuplexMode(int duplexMode) {
- if ((duplexMode & VALID_DUPLEX_MODES) == 0 && Integer.bitCount(duplexMode) == 1) {
- throw new IllegalArgumentException("invalid duplex mode: " + duplexMode);
- }
- }
-
static void enforceValidColorMode(int colorMode) {
if ((colorMode & VALID_COLOR_MODES) == 0 && Integer.bitCount(colorMode) == 1) {
throw new IllegalArgumentException("invalid color mode: " + colorMode);
}
}
- static void enforceValidFittingMode(int fittingMode) {
- if ((fittingMode & VALID_FITTING_MODES) == 0 && Integer.bitCount(fittingMode) == 1) {
- throw new IllegalArgumentException("invalid fitting mode: " + fittingMode);
- }
- }
-
- static void enforceValidOrientation(int orientation) {
- if ((orientation & VALID_ORIENTATIONS) == 0 && Integer.bitCount(orientation) == 1) {
- throw new IllegalArgumentException("invalid orientation: " + orientation);
- }
- }
-
/**
* Builder for creating {@link PrintAttributes}.
*/
@@ -1578,46 +1053,6 @@ public final class PrintAttributes implements Parcelable {
}
/**
- * Sets the input tray.
- *
- * @param inputTray The tray.
- * @return This builder.
- */
- public Builder setInputTray(Tray inputTray) {
- mAttributes.setInputTray(inputTray);
- return this;
- }
-
- /**
- * Sets the output tray.
- *
- * @param outputTray The tray.
- * @return This builder.
- */
- public Builder setOutputTray(Tray outputTray) {
- mAttributes.setOutputTray(outputTray);
- return this;
- }
-
- /**
- * Sets the duplex mode.
- *
- * @param duplexMode A valid duplex mode or zero.
- * @return This builder.
- *
- * @see PrintAttributes#DUPLEX_MODE_NONE
- * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
- * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
- */
- public Builder setDuplexMode(int duplexMode) {
- if (Integer.bitCount(duplexMode) > 1) {
- throw new IllegalArgumentException("can specify at most one duplexMode bit.");
- }
- mAttributes.setDuplexMode(duplexMode);
- return this;
- }
-
- /**
* Sets the color mode.
*
* @param colorMode A valid color mode or zero.
@@ -1635,40 +1070,6 @@ public final class PrintAttributes implements Parcelable {
}
/**
- * Sets the fitting mode.
- *
- * @param fittingMode A valid fitting mode or zero.
- * @return This builder.
- *
- * @see PrintAttributes#FITTING_MODE_NONE
- * @see PrintAttributes#FITTING_MODE_FIT_TO_PAGE
- */
- public Builder setFittingMode(int fittingMode) {
- if (Integer.bitCount(fittingMode) > 1) {
- throw new IllegalArgumentException("can specify at most one fittingMode bit.");
- }
- mAttributes.setFittingMode(fittingMode);
- return this;
- }
-
- /**
- * Sets the orientation.
- *
- * @param orientation A valid orientation or zero.
- * @return This builder.
- *
- * @see PrintAttributes#ORIENTATION_PORTRAIT
- * @see PrintAttributes#ORIENTATION_LANDSCAPE
- */
- public Builder setOrientation(int orientation) {
- if (Integer.bitCount(orientation) > 1) {
- throw new IllegalArgumentException("can specify at most one orientation bit.");
- }
- mAttributes.setOrientation(orientation);
- return this;
- }
-
- /**
* Creates a new {@link PrintAttributes} instance.
*
* @return The new instance.
diff --git a/core/java/android/print/PrintDocumentAdapter.java b/core/java/android/print/PrintDocumentAdapter.java
index 33b4aad..c81ca95 100644
--- a/core/java/android/print/PrintDocumentAdapter.java
+++ b/core/java/android/print/PrintDocumentAdapter.java
@@ -55,7 +55,7 @@ import java.util.List;
* The APIs defined in this class are designed to enable doing part or all
* of the work on an arbitrary thread. For example, if the printed content
* does not depend on the UI state, i.e. on what is shown on the screen, then
- * you can off load the entire work on a dedicated thread, thus making your
+ * you can offload the entire work on a dedicated thread, thus making your
* application interactive while the print work is being performed.
* </p>
* <p>
@@ -99,28 +99,7 @@ public abstract class PrintDocumentAdapter {
* the last argument <code>true</code> or <code>false</code> depending on
* whether the layout changed the content or not, respectively; and {@link
* LayoutResultCallback#onLayoutFailed(CharSequence)}, if an error occurred.
- * </p>
- * <p>
- * When doing a layout you may satisfy some of the constraints in the print
- * attributes such as applying the appropriate fitting, emitting content in the
- * requested orientation, using the specified margins, generating content with
- * the desired color mode, producing output with the given media size. Ideally,
- * you will satisfy all of these constraints. It is important that if you
- * satisfy a given constraint, you update the {@link PrintDocumentInfo} that
- * is returned in the given {@link LayoutResultCallback}. This way the printer
- * will have more accurate information about the content, thus producing a
- * better output. For example, assume that your application is printing
- * an image and the print attributes request landscape and fitting mode scale
- * to fill. The result of this operation should be the entire media is filled
- * and the content is rotated ninety degrees. In this case it is beneficial
- * you do the rotation and select a higher resolution image to utilize
- * the wider media (the height is now the width), rather to use a lower
- * resolution image that is later stretched by the printer. If you applied
- * the rotation you have to update the returned print document info to
- * reflect that the content is already in landscape by calling
- * {@link PrintDocumentInfo.Builder#setOrientation(int)} with {@link
- * PrintAttributes#ORIENTATION_LANDSCAPE}. In this case the printer does not
- * have to rotate the content.
+ * Note that you must call one of the methods of the given callback.
* </p>
* <p>
* <strong>Note:</strong> If the content is large and a layout will be
@@ -147,13 +126,14 @@ public abstract class PrintDocumentAdapter {
/**
* Called when specific pages of the content should be written in the
- * from of a PDF file to the given file descriptor. This method is invoked
+ * form of a PDF file to the given file descriptor. This method is invoked
* on the main thread.
*<p>
* After you are done writing, you should close the file descriptor and
- * invoke {@link WriteResultCallback #onWriteFinished(List)}, if writing
+ * invoke {@link WriteResultCallback #onWriteFinished(PageRange[]), if writing
* completed successfully; or {@link WriteResultCallback#onWriteFailed(
- * CharSequence)}, if an error occurred.
+ * CharSequence)}, if an error occurred. Note that you must call one of
+ * the methods of the given callback.
* </p>
* <p>
* <strong>Note:</strong> If the printed content is large, it is a good
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index f2b91ae..7a96e69 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -18,8 +18,6 @@ package android.print;
import android.os.Parcel;
import android.os.Parcelable;
-import android.print.PrintAttributes.Margins;
-import android.print.PrintAttributes.MediaSize;
import android.text.TextUtils;
/**
@@ -28,11 +26,6 @@ import android.text.TextUtils;
public final class PrintDocumentInfo implements Parcelable {
/**
- * Constant for an unknown media size.
- */
- public static final MediaSize MEDIA_SIZE_UNKNOWN = new MediaSize("Unknown", "Unknown", 1, 1);
-
- /**
* Constant for unknown page count..
*/
public static final int PAGE_COUNT_UNKNOWN = -1;
@@ -55,11 +48,6 @@ public final class PrintDocumentInfo implements Parcelable {
private String mName;
private int mPageCount;
private int mContentType;
- private int mOrientation;
- private int mFittingMode;
- private int mColorMode;
- private Margins mMargins;
- private MediaSize mMediaSize;
private long mDataSize;
/**
@@ -78,11 +66,6 @@ public final class PrintDocumentInfo implements Parcelable {
mName = prototype.mName;
mPageCount = prototype.mPageCount;
mContentType = prototype.mContentType;
- mOrientation = prototype.mOrientation;
- mFittingMode = prototype.mFittingMode;
- mColorMode = prototype.mColorMode;
- mMargins = prototype.mMargins;
- mMediaSize = prototype.mMediaSize;
mDataSize = prototype.mDataSize;
}
@@ -95,11 +78,6 @@ public final class PrintDocumentInfo implements Parcelable {
mName = parcel.readString();
mPageCount = parcel.readInt();
mContentType = parcel.readInt();
- mOrientation = parcel.readInt();
- mFittingMode = parcel.readInt();
- mColorMode = parcel.readInt();
- mMargins = Margins.createFromParcel(parcel);
- mMediaSize = MediaSize.createFromParcel(parcel);
mDataSize = parcel.readLong();
}
@@ -137,61 +115,6 @@ public final class PrintDocumentInfo implements Parcelable {
}
/**
- * Gets the document orientation.
- *
- * @return The orientation.
- *
- * @see PrintAttributes#ORIENTATION_PORTRAIT PrintAttributes.ORIENTATION_PORTRAIT
- * @see PrintAttributes#ORIENTATION_LANDSCAPE PrintAttributes.ORIENTATION_LANDSCAPE
- */
- public int getOrientation() {
- return mOrientation;
- }
-
- /**
- * Gets the document fitting mode.
- *
- * @return The fitting mode.
- *
- * @see PrintAttributes#FITTING_MODE_NONE PrintAttributes.FITTING_MODE_NONE
- * @see PrintAttributes#FITTING_MODE_SCALE_TO_FILL PrintAttributes.FITTING_MODE_SCALE_TO_FILL
- * @see PrintAttributes#FITTING_MODE_SCALE_TO_FIT PrintAttributes.FITTING_MODE_SCALE_TO_FIT
- */
- public int getFittingMode() {
- return mFittingMode;
- }
-
- /**
- * Gets document color mode.
- *
- * @return The color mode.
- *
- * @see PrintAttributes#COLOR_MODE_COLOR PrintAttributes.COLOR_MODE_COLOR
- * @see PrintAttributes#COLOR_MODE_MONOCHROME PrintAttributes.COLOR_MODE_MONOCHROME
- */
- public int getColorMode() {
- return mColorMode;
- }
-
- /**
- * Gets the document margins.
- *
- * @return The margins.
- */
- public Margins getMargins() {
- return mMargins;
- }
-
- /**
- * Gets the media size.
- *
- * @return The media size.
- */
- public MediaSize getMediaSize() {
- return mMediaSize;
- }
-
- /**
* Gets the document data size in bytes.
*
* @return The data size.
@@ -221,11 +144,6 @@ public final class PrintDocumentInfo implements Parcelable {
parcel.writeString(mName);
parcel.writeInt(mPageCount);
parcel.writeInt(mContentType);
- parcel.writeInt(mOrientation);
- parcel.writeInt(mFittingMode);
- parcel.writeInt(mColorMode);
- mMargins.writeToParcel(parcel);
- mMediaSize.writeToParcel(parcel);
parcel.writeLong(mDataSize);
}
@@ -236,11 +154,6 @@ public final class PrintDocumentInfo implements Parcelable {
result = prime * result + ((mName != null) ? mName.hashCode() : 0);
result = prime * result + mContentType;
result = prime * result + mPageCount;
- result = prime * result + mOrientation;
- result = prime * result + mFittingMode;
- result = prime * result + mColorMode;
- result = prime * result + (mMargins != null ? mMargins.hashCode() : 0);
- result = prime * result + (mMediaSize != null ? mMediaSize.hashCode() : 0);
result = prime * result + (int) mDataSize;
result = prime * result + (int) mDataSize >> 32;
return result;
@@ -267,29 +180,6 @@ public final class PrintDocumentInfo implements Parcelable {
if (mPageCount != other.mPageCount) {
return false;
}
- if (mOrientation != other.mOrientation) {
- return false;
- }
- if (mFittingMode != other.mFittingMode) {
- return false;
- }
- if (mColorMode != other.mColorMode) {
- return false;
- }
- if (mMargins == null) {
- if (other.mMargins != null) {
- return false;
- }
- } else if (!mMargins.equals(other.mMargins)) {
- return false;
- }
- if (mMediaSize == null) {
- if (other.mMediaSize != null) {
- return false;
- }
- } else if (!mMediaSize.equals(other.mMediaSize)) {
- return false;
- }
if (mDataSize != other.mDataSize) {
return false;
}
@@ -303,11 +193,6 @@ public final class PrintDocumentInfo implements Parcelable {
builder.append("name=").append(mName);
builder.append(", pageCount=").append(mPageCount);
builder.append(", contentType=").append(contentTyepToString(mContentType));
- builder.append(", orientation=").append(PrintAttributes.orientationToString(mOrientation));
- builder.append(", fittingMode=").append(PrintAttributes.fittingModeToString(mFittingMode));
- builder.append(", colorMode=").append(PrintAttributes.colorModeToString(mColorMode));
- builder.append(", margins=").append(mMargins);
- builder.append(", mediaSize=").append(mMediaSize);
builder.append(", size=").append(mDataSize);
builder.append("}");
return builder.toString();
@@ -336,36 +221,6 @@ public final class PrintDocumentInfo implements Parcelable {
/**
* Constructor.
* <p>
- * The values of the relevant properties are initialized from the
- * provided print attributes. For example, the orientation is set
- * to be the same as the orientation returned by calling {@link
- * PrintAttributes#getOrientation() PrintAttributes.getOrientation()}.
- * </p>
- *
- * @param name The document name. Cannot be empty.
- * @param attributes Print attributes. Cannot be null.
- *
- * @throws IllegalArgumentException If the name is empty.
- */
- public Builder(String name, PrintAttributes attributes) {
- if (TextUtils.isEmpty(name)) {
- throw new IllegalArgumentException("name cannot be empty");
- }
- if (attributes == null) {
- throw new IllegalArgumentException("attributes cannot be null");
- }
- mPrototype = new PrintDocumentInfo();
- mPrototype.mName = name;
- mPrototype.mOrientation = attributes.getOrientation();
- mPrototype.mFittingMode = attributes.getFittingMode();
- mPrototype.mColorMode = attributes.getColorMode();
- mPrototype.mMargins = attributes.getMargins();
- mPrototype.mMediaSize = attributes.getMediaSize();
- }
-
- /**
- * Constructor.
- * <p>
* The values of the relevant properties are initialized with default
* values. Please refer to the documentation of the individual setters
* for information about the default values.
@@ -379,11 +234,6 @@ public final class PrintDocumentInfo implements Parcelable {
}
mPrototype = new PrintDocumentInfo();
mPrototype.mName = name;
- mPrototype.mOrientation = PrintAttributes.ORIENTATION_PORTRAIT;
- mPrototype.mFittingMode = PrintAttributes.FITTING_MODE_NONE;
- mPrototype.mColorMode = PrintAttributes.COLOR_MODE_COLOR;
- mPrototype.mMargins = Margins.NO_MARGINS;
- mPrototype.mMediaSize = MEDIA_SIZE_UNKNOWN;
}
/**
@@ -423,95 +273,6 @@ public final class PrintDocumentInfo implements Parcelable {
}
/**
- * Sets the orientation.
- * <p>
- * <strong>Default: </strong> {@link PrintAttributes#ORIENTATION_PORTRAIT
- * PrintAttributes.ORIENTATION_PORTRAIT}
- * </p>
- *
- * @param orientation The orientation.
- *
- * @see PrintAttributes#ORIENTATION_PORTRAIT PrintAttributes.ORIENTATION_PORTRAIT
- * @see PrintAttributes#ORIENTATION_LANDSCAPE PrintAttributes.ORIENTATION_LANDSCAPE
- */
- public Builder setOrientation(int orientation) {
- PrintAttributes.enforceValidOrientation(orientation);
- mPrototype.mOrientation = orientation;
- return this;
- }
-
- /**
- * Sets the content fitting mode.
- * <p>
- * <strong>Default: </strong> {@link PrintAttributes#FITTING_MODE_NONE
- * PrintAttributes.FITTING_MODE_NONE}
- * </p>
- *
- * @param fittingMode The fitting mode.
- *
- * @see PrintAttributes#FITTING_MODE_NONE PrintAttributes.FITTING_MODE_NONE
- * @see PrintAttributes#FITTING_MODE_SCALE_TO_FILL PrintAttributes.FITTING_MODE_SCALE_TO_FILL
- * @see PrintAttributes#FITTING_MODE_SCALE_TO_FIT PrintAttributes.FITTING_MODE_SCALE_TO_FIT
- */
- public Builder setFittingMode(int fittingMode) {
- PrintAttributes.enforceValidFittingMode(fittingMode);
- mPrototype.mFittingMode = fittingMode;
- return this;
- }
-
- /**
- * Sets the content color mode.
- * <p>
- * <strong>Default: </strong> {@link PrintAttributes#COLOR_MODE_COLOR
- * PrintAttributes.COLOR_MODE_COLOR}
- * </p>
- *
- * @param colorMode The color mode.
- *
- * @see PrintAttributes#COLOR_MODE_COLOR PrintAttributes.COLOR_MODE_COLOR
- * @see PrintAttributes#COLOR_MODE_MONOCHROME PrintAttributes.COLOR_MODE_MONOCHROME
- */
- public Builder setColorMode(int colorMode) {
- PrintAttributes.enforceValidColorMode(colorMode);
- mPrototype.mColorMode = colorMode;
- return this;
- }
-
- /**
- * Sets the document margins.
- * <p>
- * <strong>Default: </strong> {@link PrintAttributes.Margins#NO_MARGINS Margins.NO_MARGINS}
- * </p>
- *
- * @param margins The margins. Cannot be null.
- */
- public Builder setMargins(Margins margins) {
- if (margins == null) {
- throw new IllegalArgumentException("margins cannot be null");
- }
- mPrototype.mMargins = margins;
- return this;
- }
-
- /**
- * Sets the document media size.
- * <p>
- * <strong>Default: </strong>#MEDIA_SIZE_UNKNOWN
- * </p>
- *
- * @param mediaSize The media size. Cannot be null.
- *
- * @see #MEDIA_SIZE_UNKNOWN
- */
- public Builder setMediaSize(MediaSize mediaSize) {
- if (mediaSize == null) {
- throw new IllegalArgumentException("media size cannot be null");
- }
- mPrototype.mMediaSize = mediaSize;
- return this;
- }
-
- /**
* Creates a new {@link PrintDocumentInfo} instance.
*
* @return The new instance.
diff --git a/core/java/android/print/PrintFileDocumentAdapter.java b/core/java/android/print/PrintFileDocumentAdapter.java
index b905396..c3a23a5 100644
--- a/core/java/android/print/PrintFileDocumentAdapter.java
+++ b/core/java/android/print/PrintFileDocumentAdapter.java
@@ -36,10 +36,11 @@ import java.io.InputStream;
import java.io.OutputStream;
/**
- * Adapter for printing files. This class could be useful if you
+ * Adapter for printing PDF files. This class could be useful if you
* want to print a file and intercept when the system is ready
- * spooling the data, so you can deleted the file if it is a
- * temporary one.
+ * spooling the data, so you can delete the file if it is a
+ * temporary one. To achieve this one must override {@link #onFinish()}
+ * and delete the file yourself.
*/
public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
@@ -57,7 +58,7 @@ public class PrintFileDocumentAdapter extends PrintDocumentAdapter {
* Constructor.
*
* @param context Context for accessing resources.
- * @param file The file to print.
+ * @param file The PDF file to print.
* @param documentInfo The information about the printed file.
*/
public PrintFileDocumentAdapter(Context context, File file,
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index 941e6e1..ea44c87 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -21,7 +21,6 @@ import android.os.Parcelable;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
-import android.print.PrintAttributes.Tray;
import java.util.ArrayList;
import java.util.Arrays;
@@ -40,26 +39,16 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
private static final int PROPERTY_MEDIA_SIZE = 0;
private static final int PROPERTY_RESOLUTION = 1;
- private static final int PROPERTY_INPUT_TRAY = 2;
- private static final int PROPERTY_OUTPUT_TRAY = 3;
- private static final int PROPERTY_DUPLEX_MODE = 4;
- private static final int PROPERTY_COLOR_MODE = 5;
- private static final int PROPERTY_FITTING_MODE = 6;
- private static final int PROPERTY_ORIENTATION = 7;
- private static final int PROPERTY_COUNT = 8;
+ private static final int PROPERTY_COLOR_MODE = 2;
+ private static final int PROPERTY_COUNT = 3;
private static final Margins DEFAULT_MARGINS = new Margins(0, 0, 0, 0);
private Margins mMinMargins = DEFAULT_MARGINS;
private List<MediaSize> mMediaSizes;
private List<Resolution> mResolutions;
- private List<Tray> mInputTrays;
- private List<Tray> mOutputTrays;
- private int mDuplexModes;
private int mColorModes;
- private int mFittingModes;
- private int mOrientations;
private final int[] mDefaults = new int[PROPERTY_COUNT];
private Margins mDefaultMargins = DEFAULT_MARGINS;
@@ -106,32 +95,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
mResolutions = null;
}
- if (other.mInputTrays != null) {
- if (mInputTrays != null) {
- mInputTrays.clear();
- mInputTrays.addAll(other.mInputTrays);
- } else {
- mInputTrays = new ArrayList<Tray>(other.mInputTrays);
- }
- } else {
- mInputTrays = null;
- }
-
- if (other.mOutputTrays != null) {
- if (mOutputTrays != null) {
- mOutputTrays.clear();
- mOutputTrays.addAll(other.mOutputTrays);
- } else {
- mOutputTrays = new ArrayList<Tray>(other.mOutputTrays);
- }
- } else {
- mOutputTrays = null;
- }
-
- mDuplexModes = other.mDuplexModes;
mColorModes = other.mColorModes;
- mFittingModes = other.mFittingModes;
- mOrientations = other.mOrientations;
final int defaultCount = other.mDefaults.length;
for (int i = 0; i < defaultCount; i++) {
@@ -169,37 +133,6 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Gets the available input trays.
- *
- * @return The input trays.
- */
- public List<Tray> getInputTrays() {
- return mInputTrays;
- }
-
- /**
- * Gets the available output trays.
- *
- * @return The output trays.
- */
- public List<Tray> getOutputTrays() {
- return mOutputTrays;
- }
-
- /**
- * Gets the supported duplex modes.
- *
- * @return The duplex modes.
- *
- * @see PrintAttributes#DUPLEX_MODE_NONE
- * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
- * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
- */
- public int getDuplexModes() {
- return mDuplexModes;
- }
-
- /**
* Gets the supported color modes.
*
* @return The color modes.
@@ -212,30 +145,6 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Gets the supported fitting modes.
- *
- * @return The fitting modes.
- *
- * @see PrintAttributes#FITTING_MODE_NONE
- * @see PrintAttributes#FITTING_MODE_FIT_TO_PAGE
- */
- public int getFittingModes() {
- return mFittingModes;
- }
-
- /**
- * Gets the supported orientations.
- *
- * @return The orientations.
- *
- * @see PrintAttributes#ORIENTATION_PORTRAIT
- * @see PrintAttributes#ORIENTATION_LANDSCAPE
- */
- public int getOrientations() {
- return mOrientations;
- }
-
- /**
* Gets the default print attributes.
*
* @param outAttributes The attributes to populated.
@@ -255,48 +164,18 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
outAttributes.setResolution(mResolutions.get(resolutionIndex));
}
- final int inputTrayIndex = mDefaults[PROPERTY_INPUT_TRAY];
- if (inputTrayIndex >= 0) {
- outAttributes.setInputTray(mInputTrays.get(inputTrayIndex));
- }
-
- final int outputTrayIndex = mDefaults[PROPERTY_OUTPUT_TRAY];
- if (outputTrayIndex >= 0) {
- outAttributes.setOutputTray(mOutputTrays.get(outputTrayIndex));
- }
-
- final int duplexMode = mDefaults[PROPERTY_DUPLEX_MODE];
- if (duplexMode > 0) {
- outAttributes.setDuplexMode(duplexMode);
- }
-
final int colorMode = mDefaults[PROPERTY_COLOR_MODE];
if (colorMode > 0) {
outAttributes.setColorMode(colorMode);
}
-
- final int fittingMode = mDefaults[PROPERTY_FITTING_MODE];
- if (fittingMode > 0) {
- outAttributes.setFittingMode(fittingMode);
- }
-
- final int orientation = mDefaults[PROPERTY_ORIENTATION];
- if (orientation > 0) {
- outAttributes.setOrientation(orientation);
- }
}
private PrinterCapabilitiesInfo(Parcel parcel) {
mMinMargins = readMargins(parcel);
readMediaSizes(parcel);
readResolutions(parcel);
- mInputTrays = readInputTrays(parcel);
- mOutputTrays = readOutputTrays(parcel);
mColorModes = parcel.readInt();
- mDuplexModes = parcel.readInt();
- mFittingModes = parcel.readInt();
- mOrientations = parcel.readInt();
readDefaults(parcel);
mDefaultMargins = readMargins(parcel);
@@ -312,13 +191,8 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
writeMargins(mMinMargins, parcel);
writeMediaSizes(parcel);
writeResolutions(parcel);
- writeInputTrays(parcel);
- writeOutputTrays(parcel);
parcel.writeInt(mColorModes);
- parcel.writeInt(mDuplexModes);
- parcel.writeInt(mFittingModes);
- parcel.writeInt(mOrientations);
writeDefaults(parcel);
writeMargins(mDefaultMargins, parcel);
@@ -331,12 +205,7 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
result = prime * result + ((mMinMargins == null) ? 0 : mMinMargins.hashCode());
result = prime * result + ((mMediaSizes == null) ? 0 : mMediaSizes.hashCode());
result = prime * result + ((mResolutions == null) ? 0 : mResolutions.hashCode());
- result = prime * result + ((mInputTrays == null) ? 0 : mInputTrays.hashCode());
- result = prime * result + ((mOutputTrays == null) ? 0 : mOutputTrays.hashCode());
result = prime * result + mColorModes;
- result = prime * result + mDuplexModes;
- result = prime * result + mFittingModes;
- result = prime * result + mOrientations;
result = prime * result + Arrays.hashCode(mDefaults);
result = prime * result + ((mDefaultMargins == null) ? 0 : mDefaultMargins.hashCode());
return result;
@@ -375,32 +244,9 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
} else if (!mResolutions.equals(other.mResolutions)) {
return false;
}
- if (mInputTrays == null) {
- if (other.mInputTrays != null) {
- return false;
- }
- } else if (!mInputTrays.equals(other.mInputTrays)) {
- return false;
- }
- if (mOutputTrays == null) {
- if (other.mOutputTrays != null) {
- return false;
- }
- } else if (!mOutputTrays.equals(other.mOutputTrays)) {
- return false;
- }
- if (mDuplexModes != other.mDuplexModes) {
- return false;
- }
if (mColorModes != other.mColorModes) {
return false;
}
- if (mFittingModes != other.mFittingModes) {
- return false;
- }
- if (mOrientations != other.mOrientations) {
- return false;
- }
if (!Arrays.equals(mDefaults, other.mDefaults)) {
return false;
}
@@ -421,32 +267,11 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
builder.append("minMargins=").append(mMinMargins);
builder.append(", mediaSizes=").append(mMediaSizes);
builder.append(", resolutions=").append(mResolutions);
- builder.append(", inputTrays=").append(mInputTrays);
- builder.append(", outputTrays=").append(mOutputTrays);
- builder.append(", duplexModes=").append(duplexModesToString());
builder.append(", colorModes=").append(colorModesToString());
- builder.append(", fittingModes=").append(fittingModesToString());
- builder.append(", orientations=").append(orientationsToString());
builder.append("\"}");
return builder.toString();
}
- private String duplexModesToString() {
- StringBuilder builder = new StringBuilder();
- builder.append('[');
- int duplexModes = mDuplexModes;
- while (duplexModes != 0) {
- final int duplexMode = 1 << Integer.numberOfTrailingZeros(duplexModes);
- duplexModes &= ~duplexMode;
- if (builder.length() > 0) {
- builder.append(", ");
- }
- builder.append(PrintAttributes.duplexModeToString(duplexMode));
- }
- builder.append(']');
- return builder.toString();
- }
-
private String colorModesToString() {
StringBuilder builder = new StringBuilder();
builder.append('[');
@@ -463,38 +288,6 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
return builder.toString();
}
- private String fittingModesToString() {
- StringBuilder builder = new StringBuilder();
- builder.append('[');
- int fittingModes = mFittingModes;
- while (fittingModes != 0) {
- final int fittingMode = 1 << Integer.numberOfTrailingZeros(fittingModes);
- fittingModes &= ~fittingMode;
- if (builder.length() > 0) {
- builder.append(", ");
- }
- builder.append(PrintAttributes.fittingModeToString(fittingMode));
- }
- builder.append(']');
- return builder.toString();
- }
-
- private String orientationsToString() {
- StringBuilder builder = new StringBuilder();
- builder.append('[');
- int orientations = mOrientations;
- while (orientations != 0) {
- final int orientation = 1 << Integer.numberOfTrailingZeros(orientations);
- orientations &= ~orientation;
- if (builder.length() > 0) {
- builder.append(", ");
- }
- builder.append(PrintAttributes.orientationToString(orientation));
- }
- builder.append(']');
- return builder.toString();
- }
-
private void writeMediaSizes(Parcel parcel) {
if (mMediaSizes == null) {
parcel.writeInt(0);
@@ -552,54 +345,6 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
return (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
}
- private void writeInputTrays(Parcel parcel) {
- if (mInputTrays == null) {
- parcel.writeInt(0);
- return;
- }
- final int inputTrayCount = mInputTrays.size();
- parcel.writeInt(inputTrayCount);
- for (int i = 0; i < inputTrayCount; i++) {
- mInputTrays.get(i).writeToParcel(parcel);
- }
- }
-
- private List<Tray> readInputTrays(Parcel parcel) {
- final int inputTrayCount = parcel.readInt();
- if (inputTrayCount <= 0) {
- return null;
- }
- List<Tray> inputTrays = new ArrayList<Tray>(inputTrayCount);
- for (int i = 0; i < inputTrayCount; i++) {
- inputTrays.add(Tray.createFromParcel(parcel));
- }
- return inputTrays;
- }
-
- private void writeOutputTrays(Parcel parcel) {
- if (mOutputTrays == null) {
- parcel.writeInt(0);
- return;
- }
- final int outputTrayCount = mOutputTrays.size();
- parcel.writeInt(outputTrayCount);
- for (int i = 0; i < outputTrayCount; i++) {
- mOutputTrays.get(i).writeToParcel(parcel);
- }
- }
-
- private List<Tray> readOutputTrays(Parcel parcel) {
- final int outputTrayCount = parcel.readInt();
- if (outputTrayCount <= 0) {
- return null;
- }
- List<Tray> outputTrays = new ArrayList<Tray>(outputTrayCount);
- for (int i = 0; i < outputTrayCount; i++) {
- outputTrays.add(Tray.createFromParcel(parcel));
- }
- return outputTrays;
- }
-
private void readDefaults(Parcel parcel) {
final int defaultCount = parcel.readInt();
for (int i = 0; i < defaultCount; i++) {
@@ -722,62 +467,6 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Adds an input tray.
- * <p>
- * <strong>Required:</strong> No
- * </p>
- *
- * @param inputTray A tray.
- * @param isDefault Whether this is the default.
- * @return This builder.
- *
- * @throws IllegalArgumentException If set as default and there
- * is already a default.
- *
- * @see PrintAttributes.Tray
- */
- public Builder addInputTray(Tray inputTray, boolean isDefault) {
- if (mPrototype.mInputTrays == null) {
- mPrototype.mInputTrays = new ArrayList<Tray>();
- }
- final int insertionIndex = mPrototype.mInputTrays.size();
- mPrototype.mInputTrays.add(inputTray);
- if (isDefault) {
- throwIfDefaultAlreadySpecified(PROPERTY_INPUT_TRAY);
- mPrototype.mDefaults[PROPERTY_INPUT_TRAY] = insertionIndex;
- }
- return this;
- }
-
- /**
- * Adds an output tray.
- * <p>
- * <strong>Required:</strong> No
- * </p>
- *
- * @param outputTray A tray.
- * @param isDefault Whether this is the default.
- * @return This builder.
- *
- * @throws IllegalArgumentException If set as default and there
- * is already a default.
- *
- * @see PrintAttributes.Tray
- */
- public Builder addOutputTray(Tray outputTray, boolean isDefault) {
- if (mPrototype.mOutputTrays == null) {
- mPrototype.mOutputTrays = new ArrayList<Tray>();
- }
- final int insertionIndex = mPrototype.mOutputTrays.size();
- mPrototype.mOutputTrays.add(outputTray);
- if (isDefault) {
- throwIfDefaultAlreadySpecified(PROPERTY_OUTPUT_TRAY);
- mPrototype.mDefaults[PROPERTY_OUTPUT_TRAY] = insertionIndex;
- }
- return this;
- }
-
- /**
* Sets the color modes.
* <p>
* <strong>Required:</strong> Yes
@@ -810,103 +499,6 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
}
/**
- * Set the duplex modes.
- * <p>
- * <strong>Required:</strong> No
- * </p>
- *
- * @param duplexModes The duplex mode bit mask.
- * @param defaultDuplexMode The default duplex mode.
- * @return This builder.
- *
- * @throws IllegalArgumentException If duplex modes contains an invalid
- * mode bit or if the default duplex mode is invalid.
- *
- * @see PrintAttributes#DUPLEX_MODE_NONE
- * @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
- * @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
- */
- public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) {
- int currentModes = duplexModes;
- while (currentModes > 0) {
- final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
- currentModes &= ~currentMode;
- PrintAttributes.enforceValidDuplexMode(currentMode);
- }
- if ((duplexModes & defaultDuplexMode) == 0) {
- throw new IllegalArgumentException("Default duplex mode not in duplex modes.");
- }
- PrintAttributes.enforceValidDuplexMode(defaultDuplexMode);
- mPrototype.mDuplexModes = duplexModes;
- mPrototype.mDefaults[PROPERTY_DUPLEX_MODE] = defaultDuplexMode;
- return this;
- }
-
- /**
- * Sets the fitting modes.
- * <p>
- * <strong>Required:</strong> No
- * </p>
- *
- * @param fittingModes The fitting mode bit mask.
- * @param defaultFittingMode The default fitting mode.
- * @return This builder.
- *
- * @throws IllegalArgumentException If fitting modes contains an invalid
- * mode bit or if the default fitting mode is invalid.
- *
- * @see PrintAttributes#FITTING_MODE_NONE
- * @see PrintAttributes#FITTING_MODE_FIT_TO_PAGE
- */
- public Builder setFittingModes(int fittingModes, int defaultFittingMode) {
- int currentModes = fittingModes;
- while (currentModes > 0) {
- final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
- currentModes &= ~currentMode;
- PrintAttributes.enforceValidFittingMode(currentMode);
- }
- if ((fittingModes & defaultFittingMode) == 0) {
- throw new IllegalArgumentException("Default fitting mode not in fiting modes.");
- }
- PrintAttributes.enforceValidFittingMode(defaultFittingMode);
- mPrototype.mFittingModes = fittingModes;
- mPrototype.mDefaults[PROPERTY_FITTING_MODE] = defaultFittingMode;
- return this;
- }
-
- /**
- * Sets the orientations.
- * <p>
- * <strong>Required:</strong> Yes
- * </p>
- *
- * @param orientations The orientation bit mask.
- * @param defaultOrientation The default orientation.
- * @return This builder.
- *
- * @throws IllegalArgumentException If orientations contains an invalid
- * mode bit or if the default orientation is invalid.
- *
- * @see PrintAttributes#ORIENTATION_PORTRAIT
- * @see PrintAttributes#ORIENTATION_LANDSCAPE
- */
- public Builder setOrientations(int orientations, int defaultOrientation) {
- int currentOrientaions = orientations;
- while (currentOrientaions > 0) {
- final int currentOrnt = (1 << Integer.numberOfTrailingZeros(currentOrientaions));
- currentOrientaions &= ~currentOrnt;
- PrintAttributes.enforceValidOrientation(currentOrnt);
- }
- if ((orientations & defaultOrientation) == 0) {
- throw new IllegalArgumentException("Default orientation not in orientations.");
- }
- PrintAttributes.enforceValidOrientation(defaultOrientation);
- mPrototype.mOrientations = orientations;
- mPrototype.mDefaults[PROPERTY_ORIENTATION] = defaultOrientation;
- return this;
- }
-
- /**
* Crates a new {@link PrinterCapabilitiesInfo} enforcing that all
* required properties have need specified. See individual methods
* in this class for reference about required attributes.
@@ -934,12 +526,6 @@ public final class PrinterCapabilitiesInfo implements Parcelable {
if (mPrototype.mDefaults[PROPERTY_COLOR_MODE] == DEFAULT_UNDEFINED) {
throw new IllegalStateException("No default color mode specified.");
}
- if (mPrototype.mOrientations == 0) {
- throw new IllegalStateException("No oprientation specified.");
- }
- if (mPrototype.mDefaults[PROPERTY_ORIENTATION] == DEFAULT_UNDEFINED) {
- throw new IllegalStateException("No default orientation specified.");
- }
if (mPrototype.mMinMargins == null) {
mPrototype.mMinMargins = new Margins(0, 0, 0, 0);
}
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index 46f0bef..64249b4 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -38,7 +38,6 @@ public final class PrinterDiscoverySession {
private static final int MSG_PRINTERS_ADDED = 1;
private static final int MSG_PRINTERS_REMOVED = 2;
- private static final int MSG_PRINTERS_UPDATED = 3;
private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
new ArrayMap<PrinterId, PrinterInfo>();
@@ -200,8 +199,8 @@ public final class PrinterDiscoverySession {
final int addedPrinterCount = printers.size();
for (int i = 0; i < addedPrinterCount; i++) {
PrinterInfo addedPrinter = printers.get(i);
- if (mPrinters.get(addedPrinter.getId()) == null) {
- mPrinters.put(addedPrinter.getId(), addedPrinter);
+ PrinterInfo oldPrinter = mPrinters.put(addedPrinter.getId(), addedPrinter);
+ if (oldPrinter == null || !oldPrinter.equals(addedPrinter)) {
printersChanged = true;
}
}
@@ -227,25 +226,6 @@ public final class PrinterDiscoverySession {
}
}
- private void handlePrintersUpdated(List<PrinterInfo> printers) {
- if (isDestroyed()) {
- return;
- }
- boolean printersChanged = false;
- final int updatedPrinterCount = printers.size();
- for (int i = 0; i < updatedPrinterCount; i++) {
- PrinterInfo updatedPrinter = printers.get(i);
- PrinterInfo oldPrinter = mPrinters.get(updatedPrinter.getId());
- if (oldPrinter != null && !oldPrinter.equals(updatedPrinter)) {
- mPrinters.put(updatedPrinter.getId(), updatedPrinter);
- printersChanged = true;
- }
- }
- if (printersChanged) {
- notifyOnPrintersChanged();
- }
- }
-
private void notifyOnPrintersChanged() {
if (mListener != null) {
mListener.onPrintersChanged();
@@ -277,11 +257,6 @@ public final class PrinterDiscoverySession {
List<PrinterId> printerIds = (List<PrinterId>) message.obj;
handlePrintersRemoved(printerIds);
} break;
-
- case MSG_PRINTERS_UPDATED: {
- List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
- handlePrintersUpdated(printers);
- } break;
}
}
}
@@ -311,14 +286,5 @@ public final class PrinterDiscoverySession {
printerIds).sendToTarget();
}
}
-
- @Override
- public void onPrintersUpdated(List<PrinterInfo> printers) {
- PrinterDiscoverySession session = mWeakSession.get();
- if (session != null) {
- session.mHandler.obtainMessage(MSG_PRINTERS_UPDATED,
- printers).sendToTarget();
- }
- }
}
}
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index 1e33fc0..ad3c04f 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -35,5 +35,4 @@ interface IPrintServiceClient {
void onPrintersAdded(in List<PrinterInfo> printers);
void onPrintersRemoved(in List<PrinterId> printerIds);
- void onPrintersUpdated(in List<PrinterInfo> printers);
}
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 8bae9d6..4ff7f0c 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -26,8 +26,8 @@ import android.util.Log;
* service. It provides APIs for observing the print job state and
* performing operations on the print job.
* <p>
- * <strong>Note: </strong> All methods of this class must be executed on the main
- * application thread.
+ * <strong>Note: </strong> All methods of this class must be invoked on
+ * the main application thread.
* </p>
*/
public final class PrintJob {
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 96552af..0ffc40a 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -20,6 +20,7 @@ import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -155,6 +156,8 @@ public abstract class PrintService extends Service {
private static final String LOG_TAG = "PrintService";
+ private static final boolean DEBUG = false;
+
/**
* The {@link Intent} action that must be declared as handled by a service
* in its manifest for the system to recognize it as a print service.
@@ -433,6 +436,9 @@ public abstract class PrintService extends Service {
case MSG_ON_PRINTJOB_QUEUED: {
PrintJobInfo printJobInfo = (PrintJobInfo) message.obj;
+ if (DEBUG) {
+ Log.i(LOG_TAG, "Queued: " + printJobInfo);
+ }
onPrintJobQueued(new PrintJob(printJobInfo, mClient));
} break;
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 128628d..8e9636c 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -239,10 +239,10 @@ public final class PrintServiceInfo implements Parcelable {
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PrintServiceInfo{");
- builder.append("id:").append(mId).append(", ");
- builder.append("resolveInfo:").append(mResolveInfo).append(", ");
- builder.append("settingsActivityName:").append(mSettingsActivityName);
- builder.append("addPrintersActivityName:").append(mAddPrintersActivityName);
+ builder.append("id=").append(mId);
+ builder.append(", resolveInfo=").append(mResolveInfo);
+ builder.append(", settingsActivityName=").append(mSettingsActivityName);
+ builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
builder.append("}");
return builder.toString();
}
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 6464cc1..b0bf3da 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -30,7 +30,7 @@ import java.util.List;
/**
* This class encapsulates the interaction between a print service and the
* system during printer discovery. During printer discovery you are responsible
- * for adding discovered printers, removing already added printers that
+ * for adding discovered printers, removing previously added printers that
* disappeared, and updating already added printers.
* <p>
* During the lifetime of this session you may be asked to start and stop
@@ -47,7 +47,7 @@ import java.util.List;
* PrinterDiscoverySession#addPrinters(List)}. Added printers that disappeared are
* removed by invoking {@link PrinterDiscoverySession#removePrinters(List)}. Added
* printers whose properties or capabilities changed are updated through a call to
- * {@link PrinterDiscoverySession#updatePrinters(List)}. The printers added in this
+ * {@link PrinterDiscoverySession#addPrinters(List)}. The printers added in this
* session can be acquired via {@link #getPrinters()} where the returned printers
* will be an up-to-date snapshot of the printers that you reported during the
* session. Printers are <strong>not</strong> persisted across sessions.
@@ -89,6 +89,9 @@ public abstract class PrinterDiscoverySession {
private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
new ArrayMap<PrinterId, PrinterInfo>();
+ private final List<PrinterId> mTrackedPrinters =
+ new ArrayList<PrinterId>();
+
private ArrayMap<PrinterId, PrinterInfo> mLastSentPrinters;
private IPrintServiceClient mObserver;
@@ -130,7 +133,6 @@ public abstract class PrinterDiscoverySession {
*
* @see #addPrinters(List)
* @see #removePrinters(List)
- * @see #updatePrinters(List)
* @see #isDestroyed()
*/
public final List<PrinterInfo> getPrinters() {
@@ -142,7 +144,7 @@ public abstract class PrinterDiscoverySession {
}
/**
- * Adds discovered printers. Adding an already added printer has no effect.
+ * Adds discovered printers. Adding an already added printer updates it.
* Removed printers can be added again. You can call this method multiple
* times during the life of this session. Duplicates will be ignored.
* <p>
@@ -153,7 +155,6 @@ public abstract class PrinterDiscoverySession {
* @param printers The printers to add.
*
* @see #removePrinters(List)
- * @see #updatePrinters(List)
* @see #getPrinters()
* @see #isDestroyed()
*/
@@ -168,18 +169,21 @@ public abstract class PrinterDiscoverySession {
if (mIsDiscoveryStarted) {
// If during discovery, add the new printers and send them.
- List<PrinterInfo> addedPrinters = new ArrayList<PrinterInfo>();
+ List<PrinterInfo> addedPrinters = null;
final int addedPrinterCount = printers.size();
for (int i = 0; i < addedPrinterCount; i++) {
PrinterInfo addedPrinter = printers.get(i);
- if (mPrinters.get(addedPrinter.getId()) == null) {
- mPrinters.put(addedPrinter.getId(), addedPrinter);
+ PrinterInfo oldPrinter = mPrinters.put(addedPrinter.getId(), addedPrinter);
+ if (oldPrinter == null || !oldPrinter.equals(addedPrinter)) {
+ if (addedPrinters == null) {
+ addedPrinters = new ArrayList<PrinterInfo>();
+ }
addedPrinters.add(addedPrinter);
}
}
// Send the added printers, if such.
- if (!addedPrinters.isEmpty()) {
+ if (addedPrinters != null) {
sendAddedPrinters(mObserver, addedPrinters);
}
} else {
@@ -232,7 +236,6 @@ public abstract class PrinterDiscoverySession {
* @param printerIds The ids of the removed printers.
*
* @see #addPrinters(List)
- * @see #updatePrinters(List)
* @see #getPrinters()
* @see #isDestroyed()
*/
@@ -295,86 +298,6 @@ public abstract class PrinterDiscoverySession {
}
}
- /**
- * Updates added printers. Updating a printer that was not added or that
- * was removed has no effect. You can call this method multiple times
- * during the lifetime of this session.
- * <p>
- * <strong>Note: </strong> Calls to this method after the session is
- * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
- * </p>
- *
- * @param printers The printers to update.
- *
- * @see #addPrinters(List)
- * @see #removePrinters(List)
- * @see #getPrinters()
- * @see #isDestroyed()
- */
- public final void updatePrinters(List<PrinterInfo> printers) {
- PrintService.throwIfNotCalledOnMainThread();
-
- // If the session is destroyed - nothing do to.
- if (mIsDestroyed) {
- Log.w(LOG_TAG, "Not updating printers - session destroyed.");
- return;
- }
-
- if (mIsDiscoveryStarted) {
- // If during discovery, update existing printers and send them.
- List<PrinterInfo> updatedPrinters = new ArrayList<PrinterInfo>();
- final int updatedPrinterCount = printers.size();
- for (int i = 0; i < updatedPrinterCount; i++) {
- PrinterInfo updatedPrinter = printers.get(i);
- PrinterInfo oldPrinter = mPrinters.get(updatedPrinter.getId());
- if (oldPrinter != null && !oldPrinter.equals(updatedPrinter)) {
- mPrinters.put(updatedPrinter.getId(), updatedPrinter);
- updatedPrinters.add(updatedPrinter);
- }
- }
-
- // Send the updated printers, if such.
- if (!updatedPrinters.isEmpty()) {
- sendUpdatedPrinters(mObserver, updatedPrinters);
- }
- } else {
- // Remember the last sent printers if needed.
- if (mLastSentPrinters == null) {
- mLastSentPrinters = new ArrayMap<PrinterId, PrinterInfo>(mPrinters);
- }
-
- // Update the printers.
- final int updatedPrinterCount = printers.size();
- for (int i = 0; i < updatedPrinterCount; i++) {
- PrinterInfo updatedPrinter = printers.get(i);
- PrinterInfo oldPrinter = mPrinters.get(updatedPrinter.getId());
- if (oldPrinter != null && !oldPrinter.equals(updatedPrinter)) {
- mPrinters.put(updatedPrinter.getId(), updatedPrinter);
- }
- }
- }
- }
-
- private static void sendUpdatedPrinters(IPrintServiceClient observer,
- List<PrinterInfo> printers) {
- try {
- final int printerCount = printers.size();
- if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
- observer.onPrintersUpdated(printers);
- } else {
- final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
- for (int i = 0; i < transactionCount; i++) {
- final int start = i * MAX_ITEMS_PER_CALLBACK;
- final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
- List<PrinterInfo> subPrinters = printers.subList(start, end);
- observer.onPrintersUpdated(subPrinters);
- }
- }
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending updated printers", re);
- }
- }
-
private void sendOutOfDiscoveryPeriodPrinterChanges() {
// Noting changed since the last discovery period - nothing to do.
if (mLastSentPrinters == null || mLastSentPrinters.isEmpty()) {
@@ -382,21 +305,11 @@ public abstract class PrinterDiscoverySession {
return;
}
+ // Determine the added printers.
List<PrinterInfo> addedPrinters = null;
- List<PrinterInfo> updatedPrinters = null;
- List<PrinterId> removedPrinterIds = null;
-
- // Determine the added and updated printers.
for (PrinterInfo printer : mPrinters.values()) {
PrinterInfo sentPrinter = mLastSentPrinters.get(printer.getId());
- if (sentPrinter != null) {
- if (!sentPrinter.equals(printer)) {
- if (updatedPrinters == null) {
- updatedPrinters = new ArrayList<PrinterInfo>();
- }
- updatedPrinters.add(printer);
- }
- } else {
+ if (sentPrinter == null || !sentPrinter.equals(printer)) {
if (addedPrinters == null) {
addedPrinters = new ArrayList<PrinterInfo>();
}
@@ -409,12 +322,8 @@ public abstract class PrinterDiscoverySession {
sendAddedPrinters(mObserver, addedPrinters);
}
- // Send the updated printers, if such.
- if (updatedPrinters != null) {
- sendUpdatedPrinters(mObserver, updatedPrinters);
- }
-
// Determine the removed printers.
+ List<PrinterId> removedPrinterIds = null;
for (PrinterInfo sentPrinter : mLastSentPrinters.values()) {
if (!mPrinters.containsKey(sentPrinter.getId())) {
if (removedPrinterIds == null) {
@@ -437,14 +346,15 @@ public abstract class PrinterDiscoverySession {
* added via calling {@link #addPrinters(List)}. Added printers that disappeared
* should be removed via calling {@link #removePrinters(List)}. Added printers
* whose properties or capabilities changed should be updated via calling {@link
- * #updatePrinters(List)}. You will receive a call to call to {@link
- * #onStopPrinterDiscovery()} when you should stop printer discovery.
+ * #addPrinters(List)}. You will receive a call to {@link #onStopPrinterDiscovery()}
+ * when you should stop printer discovery.
* <p>
* During the lifetime of this session all printers that are known to your print
* service have to be added. The system does not retain any printers across sessions.
* However, if you were asked to start and then stop performing printer discovery
* in this session, then a subsequent discovering should not re-discover already
- * discovered printers.
+ * discovered printers. You can get the printers reported during this session by
+ * calling {@link #getPrinters()}.
* </p>
* <p>
* <strong>Note: </strong>You are also given a list of printers whose availability
@@ -459,7 +369,6 @@ public abstract class PrinterDiscoverySession {
* @see #onStopPrinterDiscovery()
* @see #addPrinters(List)
* @see #removePrinters(List)
- * @see #updatePrinters(List)
* @see #isPrinterDiscoveryStarted()
*/
public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
@@ -476,7 +385,7 @@ public abstract class PrinterDiscoverySession {
* Callback asking you to validate that the given printers are valid, that
* is they exist. You are responsible for checking whether these printers
* exist and for the ones that do exist notify the system via calling
- * {@link #updatePrinters(List)}.
+ * {@link #addPrinters(List)}.
* <p>
* <strong>Note: </strong> You are <strong>not required</strong> to provide
* the printer capabilities when updating the printers that do exist.
@@ -484,7 +393,6 @@ public abstract class PrinterDiscoverySession {
*
* @param printerIds The printers to validate.
*
- * @see #updatePrinters(List)
* @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
*/
@@ -494,7 +402,7 @@ public abstract class PrinterDiscoverySession {
* Callback asking you to start tracking the state of a printer. Tracking
* the state means that you should do a best effort to observe the state
* of this printer and notify the system if that state changes via calling
- * {@link #updatePrinters(List)}.
+ * {@link #addPrinters(List)}.
* <p>
* <strong>Note: </strong> A printer can be initially added without its
* capabilities to avoid polling printers that the user will not select.
@@ -513,7 +421,6 @@ public abstract class PrinterDiscoverySession {
* @param printerId The printer to start tracking.
*
* @see #onStopPrinterStateTracking(PrinterId)
- * @see #updatePrinters(List)
* @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
*/
@@ -531,6 +438,32 @@ public abstract class PrinterDiscoverySession {
public abstract void onStopPrinterStateTracking(PrinterId printerId);
/**
+ * Gets the printers that should be tracked. These are printers that are
+ * important to the user and for which you received a call to {@link
+ * #onStartPrinterStateTracking(PrinterId)} asking you to observer their
+ * state and reporting it to the system via {@link #addPrinters(List)}.
+ * You will receive a call to {@link #onStopPrinterStateTracking(PrinterId)}
+ * if you should stop tracking a printer.
+ * <p>
+ * <strong>Note: </strong> Calls to this method after the session is
+ * destroyed, that is after the {@link #onDestroy()} callback, will be ignored.
+ * </p>
+ *
+ * @return The printers.
+ *
+ * @see #onStartPrinterStateTracking(PrinterId)
+ * @see #onStopPrinterStateTracking(PrinterId)
+ * @see #isDestroyed()
+ */
+ public final List<PrinterId> getTrackedPrinters() {
+ PrintService.throwIfNotCalledOnMainThread();
+ if (mIsDestroyed) {
+ return Collections.emptyList();
+ }
+ return new ArrayList<PrinterId>(mTrackedPrinters);
+ }
+
+ /**
* Notifies you that the session is destroyed. After this callback is invoked
* any calls to the methods of this class will be ignored, {@link #isDestroyed()}
* will return true and you will also no longer receive callbacks.
@@ -589,13 +522,16 @@ public abstract class PrinterDiscoverySession {
}
void startPrinterStateTracking(PrinterId printerId) {
- if (!mIsDestroyed && mObserver != null) {
+ if (!mIsDestroyed && mObserver != null
+ && !mTrackedPrinters.contains(printerId)) {
+ mTrackedPrinters.add(printerId);
onStartPrinterStateTracking(printerId);
}
}
void stopPrinterStateTracking(PrinterId printerId) {
- if (!mIsDestroyed && mObserver != null) {
+ if (!mIsDestroyed && mObserver != null
+ && mTrackedPrinters.remove(printerId)) {
onStopPrinterStateTracking(printerId);
}
}
diff --git a/core/java/android/printservice/package.html b/core/java/android/printservice/package.html
index 6b0327c..7410a49 100644
--- a/core/java/android/printservice/package.html
+++ b/core/java/android/printservice/package.html
@@ -9,8 +9,7 @@ implementation is factored out of the system and can by independently developed
<p>
A print service implementation should extend {@link android.printservice.PrintService}
and implement its abstract methods. Also the print service has to follow the contract for
-managing print {@link android.printservice.PrintJob}s to ensure correct interaction with
-the system and consistent user experience.
+managing print {@link android.printservice.PrintJob}s.
<p/>
<p>
The system is responsible for starting and stopping a print service depending on whether
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index f445fd5..91b3b48 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -72,7 +72,9 @@ public final class DocumentsContract {
public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";
/** {@hide} */
- public static final String ACTION_MANAGE_DOCUMENTS = "android.provider.action.MANAGE_DOCUMENTS";
+ public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT";
+ /** {@hide} */
+ public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT";
/**
* Constants related to a document, including {@link Cursor} columns names
@@ -249,6 +251,15 @@ public final class DocumentsContract {
* @see #COLUMN_FLAGS
*/
public static final int FLAG_DIR_PREFERS_GRID = 1 << 5;
+
+ /**
+ * Flag indicating that a directory prefers its contents be sorted by
+ * {@link #COLUMN_LAST_MODIFIED}. Only valid when
+ * {@link #COLUMN_MIME_TYPE} is {@link #MIME_TYPE_DIR}.
+ *
+ * @see #COLUMN_FLAGS
+ */
+ public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 6;
}
/**
@@ -290,9 +301,6 @@ public final class DocumentsContract {
* @see #FLAG_LOCAL_ONLY
* @see #FLAG_SUPPORTS_CREATE
* @see #FLAG_ADVANCED
- * @see #FLAG_PROVIDES_AUDIO
- * @see #FLAG_PROVIDES_IMAGES
- * @see #FLAG_PROVIDES_VIDEO
*/
public static final String COLUMN_FLAGS = "flags";
@@ -337,6 +345,19 @@ public final class DocumentsContract {
public static final String COLUMN_AVAILABLE_BYTES = "available_bytes";
/**
+ * MIME types supported by this root, or {@code null} if the root
+ * supports all MIME types. Multiple MIME types can be separated by a
+ * newline. For example, a root supporting audio might use
+ * "audio/*\napplication/x-flac".
+ * <p>
+ * Type: String
+ */
+ public static final String COLUMN_MIME_TYPES = "mime_types";
+
+ /** {@hide} */
+ public static final String MIME_TYPE_ITEM = "vnd.android.document/root";
+
+ /**
* Type of root that represents a storage service, such as a cloud-based
* service.
*
@@ -386,40 +407,13 @@ public final class DocumentsContract {
public static final int FLAG_ADVANCED = 1 << 2;
/**
- * Flag indicating that a root offers audio documents. When a user is
- * selecting audio, roots not providing audio may be excluded.
- *
- * @see #COLUMN_FLAGS
- * @see Intent#EXTRA_MIME_TYPES
- */
- public static final int FLAG_PROVIDES_AUDIO = 1 << 3;
-
- /**
- * Flag indicating that a root offers video documents. When a user is
- * selecting video, roots not providing video may be excluded.
- *
- * @see #COLUMN_FLAGS
- * @see Intent#EXTRA_MIME_TYPES
- */
- public static final int FLAG_PROVIDES_VIDEO = 1 << 4;
-
- /**
- * Flag indicating that a root offers image documents. When a user is
- * selecting images, roots not providing images may be excluded.
- *
- * @see #COLUMN_FLAGS
- * @see Intent#EXTRA_MIME_TYPES
- */
- public static final int FLAG_PROVIDES_IMAGES = 1 << 5;
-
- /**
* Flag indicating that this root can report recently modified
* documents.
*
* @see #COLUMN_FLAGS
* @see DocumentsContract#buildRecentDocumentsUri(String, String)
*/
- public static final int FLAG_SUPPORTS_RECENTS = 1 << 6;
+ public static final int FLAG_SUPPORTS_RECENTS = 1 << 3;
}
/**
@@ -479,6 +473,17 @@ public final class DocumentsContract {
}
/**
+ * Build Uri representing the given {@link Root#COLUMN_ROOT_ID} in a
+ * document provider.
+ *
+ * @see #getRootId(Uri)
+ */
+ public static Uri buildRootUri(String authority, String rootId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(authority).appendPath(PATH_ROOT).appendPath(rootId).build();
+ }
+
+ /**
* Build Uri representing the recently modified documents of a specific
* root. When queried, a provider will return zero or more rows with columns
* defined by {@link Document}.
@@ -689,6 +694,7 @@ public final class DocumentsContract {
* @param mimeType MIME type of new document
* @param displayName name of new document
* @return newly created document, or {@code null} if failed
+ * @hide
*/
public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri,
String mimeType, String displayName) {
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 09f4866..1b0fc4d 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -28,6 +28,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.UriMatcher;
+import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
@@ -71,11 +72,12 @@ import java.io.FileNotFoundException;
public abstract class DocumentsProvider extends ContentProvider {
private static final String TAG = "DocumentsProvider";
- private static final int MATCH_ROOT = 1;
- private static final int MATCH_RECENT = 2;
- private static final int MATCH_DOCUMENT = 3;
- private static final int MATCH_CHILDREN = 4;
- private static final int MATCH_SEARCH = 5;
+ private static final int MATCH_ROOTS = 1;
+ private static final int MATCH_ROOT = 2;
+ private static final int MATCH_RECENT = 3;
+ private static final int MATCH_DOCUMENT = 4;
+ private static final int MATCH_CHILDREN = 5;
+ private static final int MATCH_SEARCH = 6;
private String mAuthority;
@@ -89,7 +91,8 @@ public abstract class DocumentsProvider extends ContentProvider {
mAuthority = info.authority;
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- mMatcher.addURI(mAuthority, "root", MATCH_ROOT);
+ mMatcher.addURI(mAuthority, "root", MATCH_ROOTS);
+ mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT);
mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
@@ -252,7 +255,7 @@ public abstract class DocumentsProvider extends ContentProvider {
String[] selectionArgs, String sortOrder) {
try {
switch (mMatcher.match(uri)) {
- case MATCH_ROOT:
+ case MATCH_ROOTS:
return queryRoots(projection);
case MATCH_RECENT:
return queryRecentDocuments(getRootId(uri), projection);
@@ -281,6 +284,8 @@ public abstract class DocumentsProvider extends ContentProvider {
public final String getType(Uri uri) {
try {
switch (mMatcher.match(uri)) {
+ case MATCH_ROOT:
+ return DocumentsContract.Root.MIME_TYPE_ITEM;
case MATCH_DOCUMENT:
return getDocumentType(getDocumentId(uri));
default:
@@ -324,20 +329,35 @@ public abstract class DocumentsProvider extends ContentProvider {
throw new UnsupportedOperationException("Update not supported");
}
- /** {@hide} */
+ /**
+ * Implementation is provided by the parent class. Can be overridden to
+ * provide additional functionality, but subclasses <em>must</em> always
+ * call the superclass. If the superclass returns {@code null}, the subclass
+ * may implement custom behavior.
+ *
+ * @see #openDocument(String, String, CancellationSignal)
+ * @see #deleteDocument(String)
+ */
@Override
- public final Bundle callFromPackage(
- String callingPackage, String method, String arg, Bundle extras) {
+ public Bundle call(String method, String arg, Bundle extras) {
+ final Context context = getContext();
+
if (!method.startsWith("android:")) {
// Let non-platform methods pass through
- return super.callFromPackage(callingPackage, method, arg, extras);
+ return super.call(method, arg, extras);
}
- // Require that caller can manage given document
final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID);
final Uri documentUri = DocumentsContract.buildDocumentUri(mAuthority, documentId);
- getContext().enforceCallingOrSelfUriPermission(
- documentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, method);
+
+ // Require that caller can manage given document
+ final boolean callerHasManage =
+ context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS)
+ == PackageManager.PERMISSION_GRANTED;
+ if (!callerHasManage) {
+ getContext().enforceCallingOrSelfUriPermission(
+ documentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, method);
+ }
final Bundle out = new Bundle();
try {
@@ -345,14 +365,26 @@ public abstract class DocumentsProvider extends ContentProvider {
final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
- // TODO: issue Uri grant towards calling package
- // TODO: enforce that package belongs to caller
final String newDocumentId = createDocument(documentId, mimeType, displayName);
out.putString(Document.COLUMN_DOCUMENT_ID, newDocumentId);
+ // Extend permission grant towards caller if needed
+ if (!callerHasManage) {
+ final Uri newDocumentUri = DocumentsContract.buildDocumentUri(
+ mAuthority, newDocumentId);
+ context.grantUriPermission(getCallingPackage(), newDocumentUri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
+ }
+
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
- final String docId = extras.getString(Document.COLUMN_DOCUMENT_ID);
- deleteDocument(docId);
+ deleteDocument(documentId);
+
+ // Document no longer exists, clean up any grants
+ context.revokeUriPermission(documentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
} else {
throw new UnsupportedOperationException("Method not supported " + method);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 83e1544..1a80818 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -343,7 +343,7 @@ public final class Settings {
/**
* Activity Action: Show settings to manage the user input dictionary.
* <p>
- * Starting with {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE},
+ * Starting with {@link android.os.Build.VERSION_CODES#KITKAT},
* it is guaranteed there will always be an appropriate implementation for this Intent action.
* In prior releases of the platform this was optional, so ensure you safeguard against it.
* <p>
@@ -703,6 +703,20 @@ public final class Settings {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
+ /**
+ * Activity Action: Show the top level print settings.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_PRINT_SETTINGS =
+ "android.settings.ACTION_PRINT_SETTINGS";
+
// End of Intent actions for Settings
/**
@@ -5107,6 +5121,21 @@ public final class Settings {
"wifi_display_certification_on";
/**
+ * WPS Configuration method used by Wifi display, this setting only
+ * takes effect when WIFI_DISPLAY_CERTIFICATION_ON is 1 (enabled).
+ *
+ * Possible values are:
+ *
+ * WpsInfo.INVALID: use default WPS method chosen by framework
+ * WpsInfo.PBC : use Push button
+ * WpsInfo.KEYPAD : use Keypad
+ * WpsInfo.DISPLAY: use Display
+ * @hide
+ */
+ public static final String WIFI_DISPLAY_WPS_CONFIG =
+ "wifi_display_wps_config";
+
+ /**
* Whether to notify the user of open networks.
* <p>
* If not connected and the scan results have an open network, we will
@@ -5268,6 +5297,13 @@ public final class Settings {
"data_stall_alarm_aggressive_delay_in_ms";
/**
+ * The number of milliseconds to allow the provisioning apn to remain active
+ * @hide
+ */
+ public static final String PROVISIONING_APN_ALARM_DELAY_IN_MS =
+ "provisioning_apn_alarm_delay_in_ms";
+
+ /**
* The interval in milliseconds at which to check gprs registration
* after the first registration mismatch of gprs and voice service,
* to detect possible data network registration problems.
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index bf8d4e5..f8bf45b 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -444,12 +444,13 @@ public interface IKeystoreService extends IInterface {
}
@Override
- public int is_hardware_backed() throws RemoteException {
+ public int is_hardware_backed(String keyType) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(keyType);
mRemote.transact(Stub.TRANSACTION_is_hardware_backed, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
@@ -593,7 +594,7 @@ public interface IKeystoreService extends IInterface {
public int duplicate(String srcKey, int srcUid, String destKey, int destUid)
throws RemoteException;
- public int is_hardware_backed() throws RemoteException;
+ public int is_hardware_backed(String string) throws RemoteException;
public int clear_uid(long uid) throws RemoteException;
}
diff --git a/core/java/android/speech/hotword/HotwordRecognitionListener.java b/core/java/android/speech/hotword/HotwordRecognitionListener.java
index 8e62373..8a32654 100644
--- a/core/java/android/speech/hotword/HotwordRecognitionListener.java
+++ b/core/java/android/speech/hotword/HotwordRecognitionListener.java
@@ -16,7 +16,6 @@
package android.speech.hotword;
-import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
@@ -47,9 +46,10 @@ public interface HotwordRecognitionListener {
/**
* Called back when hotword is detected.
- * The action tells the client what action to take, post hotword-detection.
+ *
+ * @param intent for the activity to launch, post hotword detection.
*/
- void onHotwordRecognized(PendingIntent intent);
+ void onHotwordRecognized(Intent intent);
/**
* Called when the HotwordRecognitionService encounters an error.
diff --git a/core/java/android/speech/hotword/HotwordRecognitionService.java b/core/java/android/speech/hotword/HotwordRecognitionService.java
index 521d06d..1cba281 100644
--- a/core/java/android/speech/hotword/HotwordRecognitionService.java
+++ b/core/java/android/speech/hotword/HotwordRecognitionService.java
@@ -21,6 +21,7 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -31,7 +32,6 @@ import android.util.Log;
/**
* This class provides a base class for hotword detection service implementations.
* This class should be extended only if you wish to implement a new hotword recognizer.
- * {@hide}
*/
public abstract class HotwordRecognitionService extends Service {
/**
@@ -45,8 +45,39 @@ public abstract class HotwordRecognitionService extends Service {
private static final String TAG = "HotwordRecognitionService";
/** Debugging flag */
- // TODO: Turn off.
- private static final boolean DBG = true;
+ private static final boolean DBG = false;
+
+ /**
+ * Key used to retrieve a string to be displayed to the user.
+ */
+ public static final String KEY_PROMPT_TEXT = "prompt_text";
+
+ /**
+ * Event type used to indicate to the user that the prompt for
+ * hotword recognition has changed.
+ */
+ public static final int EVENT_TYPE_PROMPT_CHANGED = 1;
+
+ /** Audio recording error. */
+ public static final int ERROR_AUDIO = 1;
+
+ /** RecognitionService busy. */
+ public static final int ERROR_RECOGNIZER_BUSY = 2;
+
+ /** This indicates a permanent failure and the clients shouldn't retry on this */
+ public static final int ERROR_FAILED = 3;
+
+ /** Client-side errors */
+ public static final int ERROR_CLIENT = 4;
+
+ /** The service timed out */
+ public static final int ERROR_TIMEOUT = 5;
+
+ /** The service received concurrent start calls */
+ public static final int ERROR_SERVICE_ALREADY_STARTED = 6;
+
+ /** Hotword recognition is unavailable on the device */
+ public static final int ERROR_UNAVAILABLE = 7;
private static final int MSG_START_RECOGNITION = 1;
private static final int MSG_STOP_RECOGNITION = 2;
@@ -95,7 +126,7 @@ public abstract class HotwordRecognitionService extends Service {
HotwordRecognitionService.this.onStartHotwordRecognition(mCurrentCallback);
} else {
try {
- listener.onHotwordError(HotwordRecognizer.ERROR_RECOGNIZER_BUSY);
+ listener.onHotwordError(ERROR_RECOGNIZER_BUSY);
} catch (RemoteException e) {
if (DBG) Log.d(TAG, "onError call from startRecognition failed");
}
@@ -106,10 +137,10 @@ public abstract class HotwordRecognitionService extends Service {
private void dispatchStopRecognition(IHotwordRecognitionListener listener) {
try {
if (mCurrentCallback == null) {
- listener.onHotwordError(HotwordRecognizer.ERROR_CLIENT);
+ listener.onHotwordError(ERROR_CLIENT);
Log.w(TAG, "stopRecognition called with no preceding startRecognition - ignoring");
} else if (mCurrentCallback.mListener.asBinder() != listener.asBinder()) {
- listener.onHotwordError(HotwordRecognizer.ERROR_RECOGNIZER_BUSY);
+ listener.onHotwordError(ERROR_RECOGNIZER_BUSY);
Log.w(TAG, "stopRecognition called by a different caller - ignoring");
} else { // the correct state
mCurrentCallback.onHotwordRecognitionStopped();
@@ -160,7 +191,7 @@ public abstract class HotwordRecognitionService extends Service {
public void startHotwordRecognition(IHotwordRecognitionListener listener) {
if (DBG) Log.d(TAG, "startRecognition called by: " + listener.asBinder());
- if (mInternalService != null) {
+ if (mInternalService != null && mInternalService.checkPermissions(listener)) {
mInternalService.mHandler.sendMessage(
Message.obtain(mInternalService.mHandler, MSG_START_RECOGNITION, listener));
}
@@ -168,7 +199,7 @@ public abstract class HotwordRecognitionService extends Service {
public void stopHotwordRecognition(IHotwordRecognitionListener listener) {
if (DBG) Log.d(TAG, "stopRecognition called by: " + listener.asBinder());
- if (mInternalService != null) {
+ if (mInternalService != null && mInternalService.checkPermissions(listener)) {
mInternalService.mHandler.sendMessage(
Message.obtain(mInternalService.mHandler, MSG_STOP_RECOGNITION, listener));
}
@@ -180,6 +211,27 @@ public abstract class HotwordRecognitionService extends Service {
}
/**
+ * Checks whether the caller has sufficient permissions
+ *
+ * @param listener to send the error message to in case of error.
+ * @return {@code true} if the caller has enough permissions, {@code false} otherwise.
+ */
+ private boolean checkPermissions(IHotwordRecognitionListener listener) {
+ if (DBG) Log.d(TAG, "checkPermissions");
+ if (checkCallingOrSelfPermission(android.Manifest.permission.HOTWORD_RECOGNITION) ==
+ PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ try {
+ Log.e(TAG, "Recognition service called without HOTWORD_RECOGNITION permissions");
+ listener.onHotwordError(ERROR_FAILED);
+ } catch (RemoteException e) {
+ Log.e(TAG, "onHotwordError(ERROR_FAILED) message failed", e);
+ }
+ return false;
+ }
+
+ /**
* This class acts passes on the callbacks received from the Hotword service
* to the listener.
*/
@@ -207,7 +259,7 @@ public abstract class HotwordRecognitionService extends Service {
/**
* Called on an event of interest to the client.
*
- * @param eventType the event type. Event types are defined in {@link HotwordRecognizer}.
+ * @param eventType the event type.
* @param eventBundle a Bundle containing the hotword event(s).
*/
public void onHotwordEvent(int eventType, Bundle eventBundle) throws RemoteException {
@@ -216,17 +268,17 @@ public abstract class HotwordRecognitionService extends Service {
/**
* Called back when hotword is detected.
- * The action tells the client what action to take, post hotword-detection.
+ *
+ * @param activityIntent for the activity to launch, post hotword detection.
*/
- public void onHotwordRecognized(PendingIntent intent) throws RemoteException {
- mListener.onHotwordRecognized(intent);
+ public void onHotwordRecognized(Intent activityIntent) throws RemoteException {
+ mListener.onHotwordRecognized(activityIntent);
}
/**
* Called when the HotwordRecognitionService encounters an error.
*
* @param errorCode the error code describing the error that was encountered.
- * Error codes are defined in {@link HotwordRecognizer}.
*/
public void onError(int errorCode) throws RemoteException {
mListener.onHotwordError(errorCode);
diff --git a/core/java/android/speech/hotword/HotwordRecognizer.java b/core/java/android/speech/hotword/HotwordRecognizer.java
index 82cec10..9f05f31 100644
--- a/core/java/android/speech/hotword/HotwordRecognizer.java
+++ b/core/java/android/speech/hotword/HotwordRecognizer.java
@@ -45,42 +45,11 @@ import java.util.Queue;
*/
public class HotwordRecognizer {
/** DEBUG value to enable verbose debug prints */
- // TODO: Turn off.
- private final static boolean DBG = true;
+ private final static boolean DBG = false;
/** Log messages identifier */
private static final String TAG = "HotwordRecognizer";
- /**
- * Key used to retrieve a string to be displayed to the user passed to the
- * {@link android.speech.hotword.HotwordRecognitionListener#onHotwordEvent(int, Bundle)} method.
- */
- public static final String PROMPT_TEXT = "prompt_text";
-
- /**
- * Event type used to indicate to the user that the hotword service has changed
- * its state.
- */
- public static final int EVENT_TYPE_STATE_CHANGED = 1;
-
- /** Audio recording error. */
- public static final int ERROR_AUDIO = 1;
-
- /** RecognitionService busy. */
- public static final int ERROR_RECOGNIZER_BUSY = 2;
-
- /** This indicates a permanent failure and the clients shouldn't retry on this */
- public static final int ERROR_FAILED = 3;
-
- /** Client-side errors */
- public static final int ERROR_CLIENT = 4;
-
- /** The service timed out */
- public static final int ERROR_TIMEOUT = 5;
-
- /** The service received concurrent start calls */
- public static final int ERROR_SERVICE_ALREADY_STARTED = 6;
-
/** action codes */
private static final int MSG_START = 1;
private static final int MSG_STOP = 2;
@@ -207,7 +176,7 @@ public class HotwordRecognizer {
if (mServiceComponent == null) {
Log.e(TAG, "no selected voice recognition service");
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
return;
} else {
serviceIntent.setComponent(mServiceComponent);
@@ -217,12 +186,12 @@ public class HotwordRecognizer {
Log.e(TAG, "bind to recognition service failed");
mConnection = null;
mService = null;
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
return;
}
putMessage(Message.obtain(mHandler, MSG_START));
} else {
- mListener.onHotwordError(ERROR_SERVICE_ALREADY_STARTED);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_SERVICE_ALREADY_STARTED);
return;
}
}
@@ -250,7 +219,7 @@ public class HotwordRecognizer {
if (DBG) Log.d(TAG, "service startRecognition command succeeded");
} catch (final RemoteException e) {
Log.e(TAG, "startRecognition() failed", e);
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
}
}
@@ -266,7 +235,7 @@ public class HotwordRecognizer {
if (DBG) Log.d(TAG, "service stopRecognition command succeeded");
} catch (final RemoteException e) {
Log.e(TAG, "stopRecognition() failed", e);
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
} finally {
mPendingTasks.clear();
mService = null;
@@ -279,7 +248,7 @@ public class HotwordRecognizer {
if (mService != null) {
return true;
}
- mListener.onHotwordError(ERROR_CLIENT);
+ mListener.onHotwordError(HotwordRecognitionService.ERROR_CLIENT);
Log.e(TAG, "not connected to the recognition service");
return false;
}
@@ -354,7 +323,7 @@ public class HotwordRecognizer {
mInternalListener.onHotwordEvent(msg.arg1, (Bundle) msg.obj);
break;
case MSG_ON_RECOGNIZED:
- mInternalListener.onHotwordRecognized((PendingIntent) msg.obj);
+ mInternalListener.onHotwordRecognized((Intent) msg.obj);
break;
case MSG_ON_ERROR:
mInternalListener.onHotwordError((Integer) msg.obj);
@@ -380,8 +349,8 @@ public class HotwordRecognizer {
}
@Override
- public void onHotwordRecognized(PendingIntent intent) throws RemoteException {
- Message.obtain(mInternalHandler, MSG_ON_RECOGNIZED, intent)
+ public void onHotwordRecognized(Intent activityIntent) throws RemoteException {
+ Message.obtain(mInternalHandler, MSG_ON_RECOGNIZED, activityIntent)
.sendToTarget();
}
diff --git a/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl b/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
index 49c5233..4ea2e8e 100644
--- a/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
+++ b/core/java/android/speech/hotword/IHotwordRecognitionListener.aidl
@@ -16,7 +16,7 @@
package android.speech.hotword;
-import android.app.PendingIntent;
+import android.content.Intent;
import android.os.Bundle;
/**
@@ -47,9 +47,10 @@ oneway interface IHotwordRecognitionListener {
/**
* Called back when hotword is detected.
- * The action tells the client what action to take, post hotword-detection.
+ *
+ * @param intent for the activity to launch, post hotword detection.
*/
- void onHotwordRecognized(in PendingIntent intent);
+ void onHotwordRecognized(in Intent intent);
/**
* Called when the HotwordRecognitionService encounters an error.
diff --git a/core/java/android/view/transition/AutoTransition.java b/core/java/android/transition/AutoTransition.java
index 7ddac7e..6e46021 100644
--- a/core/java/android/view/transition/AutoTransition.java
+++ b/core/java/android/transition/AutoTransition.java
@@ -14,22 +14,28 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
/**
* Utility class for creating a default transition that automatically fades,
* moves, and resizes views during a scene change.
+ *
+ * <p>An AutoTransition can be described in a resource file by using the
+ * tag <code>autoTransition</code>, along with the other standard
+ * attributes of {@link android.R.styleable#Transition}.</p>
*/
-public class AutoTransition extends TransitionGroup {
+public class AutoTransition extends TransitionSet {
/**
- * Constructs an AutoTransition object, which is a TransitionGroup which
+ * Constructs an AutoTransition object, which is a TransitionSet which
* first fades out disappearing targets, then moves and resizes existing
* targets, and finally fades in appearing targets.
*
*/
public AutoTransition() {
- setOrdering(SEQUENTIALLY);
- addTransitions(new Fade(Fade.OUT), new Move(), new Fade(Fade.IN));
+ setOrdering(ORDERING_SEQUENTIAL);
+ addTransition(new Fade(Fade.OUT)).
+ addTransition(new ChangeBounds()).
+ addTransition(new Fade(Fade.IN));
}
}
diff --git a/core/java/android/view/transition/Move.java b/core/java/android/transition/ChangeBounds.java
index fda0cd2..8053bff 100644
--- a/core/java/android/view/transition/Move.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -33,13 +33,17 @@ import java.util.Map;
/**
* This transition captures the layout bounds of target views before and after
* the scene change and animates those changes during the transition.
+ *
+ * <p>A ChangeBounds transition can be described in a resource file by using the
+ * tag <code>changeBounds</code>, along with the other standard
+ * attributes of {@link android.R.styleable#Transition}.</p>
*/
-public class Move extends Transition {
+public class ChangeBounds extends Transition {
- private static final String PROPNAME_BOUNDS = "android:move:bounds";
- private static final String PROPNAME_PARENT = "android:move:parent";
- private static final String PROPNAME_WINDOW_X = "android:move:windowX";
- private static final String PROPNAME_WINDOW_Y = "android:move:windowY";
+ private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds";
+ private static final String PROPNAME_PARENT = "android:changeBounds:parent";
+ private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX";
+ private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY";
private static final String[] sTransitionProperties = {
PROPNAME_BOUNDS,
PROPNAME_PARENT,
@@ -50,7 +54,7 @@ public class Move extends Transition {
int[] tempLocation = new int[2];
boolean mResizeClip = false;
boolean mReparent = false;
- private static final String LOG_TAG = "Move";
+ private static final String LOG_TAG = "ChangeBounds";
private static RectEvaluator sRectEvaluator = new RectEvaluator();
@@ -64,7 +68,7 @@ public class Move extends Transition {
}
/**
- * Setting this flag tells Move to track the before/after parent
+ * Setting this flag tells ChangeBounds to track the before/after parent
* of every view using this transition. The flag is not enabled by
* default because it requires the parent instances to be the same
* in the two scenes or else all parents must use ids to allow
@@ -77,8 +81,7 @@ public class Move extends Transition {
mReparent = reparent;
}
- @Override
- protected void captureValues(TransitionValues values, boolean start) {
+ private void captureValues(TransitionValues values) {
View view = values.view;
values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(),
view.getRight(), view.getBottom()));
@@ -89,7 +92,17 @@ public class Move extends Transition {
}
@Override
- protected Animator play(final ViewGroup sceneRoot, TransitionValues startValues,
+ public void captureStartValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
@@ -105,7 +118,7 @@ public class Move extends Transition {
boolean parentsEqual = (startParent == endParent) ||
(startParent.getId() == endParent.getId());
// TODO: Might want reparenting to be separate/subclass transition, or at least
- // triggered by a property on Move. Otherwise, we're forcing the requirement that
+ // triggered by a property on ChangeBounds. Otherwise, we're forcing the requirement that
// all parents in layouts have IDs to avoid layout-inflation resulting in a side-effect
// of reparenting the views.
if (!mReparent || parentsEqual) {
diff --git a/core/java/android/view/transition/Crossfade.java b/core/java/android/transition/Crossfade.java
index 18bb57f..69ce872 100644
--- a/core/java/android/view/transition/Crossfade.java
+++ b/core/java/android/transition/Crossfade.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -24,10 +24,8 @@ import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.SurfaceView;
import android.view.TextureView;
@@ -43,6 +41,8 @@ import java.util.Map;
*
* <p>Note: This transition is not compatible with {@link TextureView}
* or {@link SurfaceView}.</p>
+ *
+ * @hide
*/
public class Crossfade extends Transition {
// TODO: Add a hook that lets a Transition call user code to query whether it should run on
@@ -121,12 +121,19 @@ public class Crossfade extends Transition {
* @param fadeBehavior The type of fading animation to use when this
* transition is run.
*/
- public void setFadeBehavior(int fadeBehavior) {
+ public Crossfade setFadeBehavior(int fadeBehavior) {
if (fadeBehavior >= FADE_BEHAVIOR_CROSSFADE && fadeBehavior <= FADE_BEHAVIOR_OUT_IN) {
mFadeBehavior = fadeBehavior;
}
+ return this;
}
+ /**
+ * Returns the fading behavior of the animation.
+ *
+ * @return This crossfade object.
+ * @see #setFadeBehavior(int)
+ */
public int getFadeBehavior() {
return mFadeBehavior;
}
@@ -139,18 +146,25 @@ public class Crossfade extends Transition {
* @param resizeBehavior The type of resizing behavior to use when this
* transition is run.
*/
- public void setResizeBehavior(int resizeBehavior) {
+ public Crossfade setResizeBehavior(int resizeBehavior) {
if (resizeBehavior >= RESIZE_BEHAVIOR_NONE && resizeBehavior <= RESIZE_BEHAVIOR_SCALE) {
mResizeBehavior = resizeBehavior;
}
+ return this;
}
+ /**
+ * Returns the resizing behavior of the animation.
+ *
+ * @return This crossfade object.
+ * @see #setResizeBehavior(int)
+ */
public int getResizeBehavior() {
return mResizeBehavior;
}
@Override
- protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
@@ -243,18 +257,16 @@ public class Crossfade extends Transition {
}
}
- @Override
- protected void captureValues(TransitionValues values, boolean start) {
- View view = values.view;
+ private void captureValues(TransitionValues transitionValues) {
+ View view = transitionValues.view;
Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
if (mFadeBehavior != FADE_BEHAVIOR_REVEAL) {
bounds.offset(view.getLeft(), view.getTop());
}
- values.values.put(PROPNAME_BOUNDS, bounds);
+ transitionValues.values.put(PROPNAME_BOUNDS, bounds);
if (Transition.DBG) {
- Log.d(LOG_TAG, "Captured bounds " + values.values.get(PROPNAME_BOUNDS) + ": start = " +
- start);
+ Log.d(LOG_TAG, "Captured bounds " + transitionValues.values.get(PROPNAME_BOUNDS));
}
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
Bitmap.Config.ARGB_8888);
@@ -264,12 +276,21 @@ public class Crossfade extends Transition {
Canvas c = new Canvas(bitmap);
view.draw(c);
}
- values.values.put(PROPNAME_BITMAP, bitmap);
+ transitionValues.values.put(PROPNAME_BITMAP, bitmap);
// TODO: I don't have resources, can't call the non-deprecated method?
BitmapDrawable drawable = new BitmapDrawable(bitmap);
// TODO: lrtb will be wrong if the view has transXY set
drawable.setBounds(bounds);
- values.values.put(PROPNAME_DRAWABLE, drawable);
+ transitionValues.values.put(PROPNAME_DRAWABLE, drawable);
}
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
}
diff --git a/core/java/android/view/transition/Fade.java b/core/java/android/transition/Fade.java
index 45c21d8..12e0d73 100644
--- a/core/java/android/view/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -14,12 +14,11 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -30,6 +29,12 @@ import android.view.ViewGroup;
* or non-visible. Visibility is determined by both the
* {@link View#setVisibility(int)} state of the view as well as whether it
* is parented in the current view hierarchy.
+ *
+ * <p>A Fade transition can be described in a resource file by using the
+ * tag <code>fade</code>, along with the standard
+ * attributes of {@link android.R.styleable#Fade} and
+ * {@link android.R.styleable#Transition}.</p>
+
*/
public class Fade extends Visibility {
@@ -93,21 +98,31 @@ public class Fade extends Visibility {
return anim;
}
- @Override
- protected void captureValues(TransitionValues values, boolean start) {
- super.captureValues(values, start);
- float alpha = values.view.getAlpha();
- values.values.put(PROPNAME_ALPHA, alpha);
+ private void captureValues(TransitionValues transitionValues) {
+ float alpha = transitionValues.view.getAlpha();
+ transitionValues.values.put(PROPNAME_ALPHA, alpha);
int[] loc = new int[2];
- values.view.getLocationOnScreen(loc);
- values.values.put(PROPNAME_SCREEN_X, loc[0]);
- values.values.put(PROPNAME_SCREEN_Y, loc[1]);
+ transitionValues.view.getLocationOnScreen(loc);
+ transitionValues.values.put(PROPNAME_SCREEN_X, loc[0]);
+ transitionValues.values.put(PROPNAME_SCREEN_Y, loc[1]);
+ }
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ super.captureStartValues(transitionValues);
+ captureValues(transitionValues);
+ }
+
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ super.captureEndValues(transitionValues);
}
@Override
- protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
- Animator animator = super.play(sceneRoot, startValues, endValues);
+ Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
if (animator == null && startValues != null && endValues != null) {
boolean endVisible = isVisible(endValues);
final View endView = endValues.view;
@@ -122,13 +137,18 @@ public class Fade extends Visibility {
}
@Override
- protected Animator appear(ViewGroup sceneRoot,
+ public Animator onAppear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
if ((mFadingMode & IN) != IN || endValues == null) {
return null;
}
final View endView = endValues.view;
+ if (DBG) {
+ View startView = (startValues != null) ? startValues.view : null;
+ Log.d(LOG_TAG, "Fade.onDisappear: startView, startVis, endView, endVis = " +
+ startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
+ }
// if alpha < 1, just fade it in from the current value
if (endView.getAlpha() == 1.0f) {
endView.setAlpha(0);
@@ -137,7 +157,7 @@ public class Fade extends Visibility {
}
@Override
- protected Animator disappear(ViewGroup sceneRoot,
+ public Animator onDisappear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
if ((mFadingMode & OUT) != OUT) {
@@ -147,7 +167,7 @@ public class Fade extends Visibility {
View startView = (startValues != null) ? startValues.view : null;
View endView = (endValues != null) ? endValues.view : null;
if (DBG) {
- Log.d(LOG_TAG, "Fade.predisappear: startView, startVis, endView, endVis = " +
+ Log.d(LOG_TAG, "Fade.onDisappear: startView, startVis, endView, endVis = " +
startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
}
View overlayView = null;
diff --git a/core/java/android/view/transition/Recolor.java b/core/java/android/transition/Recolor.java
index e4858c4..70111d1 100644
--- a/core/java/android/view/transition/Recolor.java
+++ b/core/java/android/transition/Recolor.java
@@ -14,20 +14,17 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.util.ArrayMap;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import java.util.Map;
-
/**
* This transition tracks changes during scene changes to the
* {@link View#setBackground(android.graphics.drawable.Drawable) background}
@@ -36,22 +33,34 @@ import java.util.Map;
* {@link TextView#setTextColor(android.content.res.ColorStateList)
* color} of the text for target TextViews. If the color changes between
* scenes, the color change is animated.
+ *
+ * @hide
*/
public class Recolor extends Transition {
private static final String PROPNAME_BACKGROUND = "android:recolor:background";
private static final String PROPNAME_TEXT_COLOR = "android:recolor:textColor";
- @Override
- protected void captureValues(TransitionValues values, boolean start) {
- values.values.put(PROPNAME_BACKGROUND, values.view.getBackground());
- if (values.view instanceof TextView) {
- values.values.put(PROPNAME_TEXT_COLOR, ((TextView)values.view).getCurrentTextColor());
+ private void captureValues(TransitionValues transitionValues) {
+ transitionValues.values.put(PROPNAME_BACKGROUND, transitionValues.view.getBackground());
+ if (transitionValues.view instanceof TextView) {
+ transitionValues.values.put(PROPNAME_TEXT_COLOR,
+ ((TextView)transitionValues.view).getCurrentTextColor());
}
}
@Override
- protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ public void captureStartValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
diff --git a/core/java/android/view/transition/Rotate.java b/core/java/android/transition/Rotate.java
index d35a6dc7..ad1720c 100644
--- a/core/java/android/view/transition/Rotate.java
+++ b/core/java/android/transition/Rotate.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -24,18 +24,25 @@ import android.view.ViewGroup;
/**
* This transition captures the rotation property of targets before and after
* the scene change and animates any changes.
+ *
+ * @hide
*/
public class Rotate extends Transition {
private static final String PROPNAME_ROTATION = "android:rotate:rotation";
@Override
- protected void captureValues(TransitionValues values, boolean start) {
- values.values.put(PROPNAME_ROTATION, values.view.getRotation());
+ public void captureStartValues(TransitionValues transitionValues) {
+ transitionValues.values.put(PROPNAME_ROTATION, transitionValues.view.getRotation());
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ transitionValues.values.put(PROPNAME_ROTATION, transitionValues.view.getRotation());
}
@Override
- protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
diff --git a/core/java/android/view/transition/Scene.java b/core/java/android/transition/Scene.java
index cf3eadb..f81eeef 100644
--- a/core/java/android/view/transition/Scene.java
+++ b/core/java/android/transition/Scene.java
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.content.Context;
+import android.util.SparseArray;
import android.view.LayoutInflater;
+import android.view.View;
import android.view.ViewGroup;
/**
@@ -34,6 +36,37 @@ public final class Scene {
private ViewGroup mSceneRoot;
private ViewGroup mLayout; // alternative to layoutId
Runnable mEnterAction, mExitAction;
+ private static ThreadLocal<SparseArray<Scene>> sScenes = new ThreadLocal<SparseArray<Scene>>();
+
+ /**
+ * Returns a Scene described by the resource file associated with the given
+ * <code>layoutId</code> parameter. If such a Scene has already been created,
+ * that same Scene will be returned. This caching of layoutId-based scenes enables
+ * sharing of common scenes between those created in code and those referenced
+ * by {@link TransitionManager} XML resource files.
+ *
+ * @param sceneRoot The root of the hierarchy in which scene changes
+ * and transitions will take place.
+ * @param layoutId The id of a standard layout resource file.
+ * @param context The context used in the process of inflating
+ * the layout resource.
+ * @return
+ */
+ public static Scene getSceneForLayout(ViewGroup sceneRoot, int layoutId, Context context) {
+ SparseArray<Scene> scenes = sScenes.get();
+ if (scenes == null) {
+ scenes = new SparseArray<Scene>();
+ sScenes.set(scenes);
+ }
+ Scene scene = scenes.get(layoutId);
+ if (scene != null) {
+ return scene;
+ } else {
+ scene = new Scene(sceneRoot, layoutId, context);
+ scenes.put(layoutId, scene);
+ return scene;
+ }
+ }
/**
* Constructs a Scene with no information about how values will change
@@ -54,6 +87,9 @@ public final class Scene {
* children from the sceneRoot container and will inflate and add
* the hierarchy specified by the layoutId resource file.
*
+ * <p>This method is hidden because layoutId-based scenes should be
+ * created by the caching factory method {@link Scene#getCurrentScene(View)}.</p>
+ *
* @param sceneRoot The root of the hierarchy in which scene changes
* and transitions will take place.
* @param layoutId The id of a resource file that defines the view
@@ -61,7 +97,7 @@ public final class Scene {
* @param context The context used in the process of inflating
* the layout resource.
*/
- public Scene(ViewGroup sceneRoot, int layoutId, Context context) {
+ private Scene(ViewGroup sceneRoot, int layoutId, Context context) {
mContext = context;
mSceneRoot = sceneRoot;
mLayoutId = layoutId;
@@ -74,7 +110,7 @@ public final class Scene {
*
* @param sceneRoot The root of the hierarchy in which scene changes
* and transitions will take place.
- * @param layout The view hiearrchy of this scene, added as a child
+ * @param layout The view hierarchy of this scene, added as a child
* of sceneRoot when this scene is entered.
*/
public Scene(ViewGroup sceneRoot, ViewGroup layout) {
@@ -94,19 +130,14 @@ public final class Scene {
}
/**
- * Exits this scene, if it is the {@link ViewGroup#getCurrentScene()
- * currentScene} on the scene's {@link #getSceneRoot() scene root}.
- * Exiting a scene involves removing the layout added if the scene
- * has either a layoutId or layout view group (set at construction
- * time) and running the {@link #setExitAction(Runnable) exit action}
+ * Exits this scene, if it is the current scene
+ * on the scene's {@link #getSceneRoot() scene root}. The current scene is
+ * set when {@link #enter() entering} a scene.
+ * Exiting a scene runs the {@link #setExitAction(Runnable) exit action}
* if there is one.
*/
public void exit() {
- if (mSceneRoot.getCurrentScene() == this) {
- if (mLayoutId >= 0 || mLayout != null) {
- // Undo layout change caused by entering this scene
- getSceneRoot().removeAllViews();
- }
+ if (getCurrentScene(mSceneRoot) == this) {
if (mExitAction != null) {
mExitAction.run();
}
@@ -127,8 +158,7 @@ public final class Scene {
// Apply layout change, if any
if (mLayoutId >= 0 || mLayout != null) {
- // redundant with exit() action of previous scene, but must
- // empty out that parent container before adding to it
+ // empty out parent container before adding to it
getSceneRoot().removeAllViews();
if (mLayoutId >= 0) {
@@ -143,7 +173,30 @@ public final class Scene {
mEnterAction.run();
}
- mSceneRoot.setCurrentScene(this );
+ setCurrentScene(mSceneRoot, this);
+ }
+
+ /**
+ * Set the scene that the given view is in. The current scene is set only
+ * on the root view of a scene, not for every view in that hierarchy. This
+ * information is used by Scene to determine whether there is a previous
+ * scene which should be exited before the new scene is entered.
+ *
+ * @param view The view on which the current scene is being set
+ */
+ static void setCurrentScene(View view, Scene scene) {
+ view.setTagInternal(com.android.internal.R.id.current_scene, scene);
+ }
+
+ /**
+ * Gets the current {@link Scene} set on the given view. A scene is set on a view
+ * only if that view is the scene root.
+ *
+ * @return The current Scene set on this view. A value of null indicates that
+ * no Scene is currently set.
+ */
+ static Scene getCurrentScene(View view) {
+ return (Scene) view.getTag(com.android.internal.R.id.current_scene);
}
/**
diff --git a/core/java/android/view/transition/Slide.java b/core/java/android/transition/Slide.java
index b2f5db5..b38973c 100644
--- a/core/java/android/view/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -28,6 +28,8 @@ import android.view.animation.DecelerateInterpolator;
* This transition captures the visibility of target objects before and
* after a scene change and animates any changes by sliding the target
* objects into or out of place.
+ *
+ * @hide
*/
public class Slide extends Visibility {
@@ -37,7 +39,7 @@ public class Slide extends Visibility {
private static final TimeInterpolator sDecelerator = new DecelerateInterpolator();
@Override
- protected Animator appear(ViewGroup sceneRoot,
+ public Animator onAppear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
View endView = (endValues != null) ? endValues.view : null;
@@ -49,7 +51,7 @@ public class Slide extends Visibility {
}
@Override
- protected Animator disappear(ViewGroup sceneRoot,
+ public Animator onDisappear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
View startView = (startValues != null) ? startValues.view : null;
diff --git a/core/java/android/view/transition/TextChange.java b/core/java/android/transition/TextChange.java
index 7973c97..4f14d46 100644
--- a/core/java/android/view/transition/TextChange.java
+++ b/core/java/android/transition/TextChange.java
@@ -14,14 +14,13 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.Color;
-import android.util.ArrayMap;
import android.view.ViewGroup;
import android.widget.TextView;
@@ -33,6 +32,8 @@ import java.util.Map;
* starting text stays until the transition ends, at which point it changes
* to the end text. This is useful in situations where you want to resize a
* text view to its new size before displaying the text that goes there.
+ *
+ * @hide
*/
public class TextChange extends Transition {
private static final String PROPNAME_TEXT = "android:textchange:text";
@@ -84,15 +85,18 @@ public class TextChange extends Transition {
/**
* Sets the type of changing animation that will be run, one of
- * {@link #CHANGE_BEHAVIOR_KEEP} and {@link #CHANGE_BEHAVIOR_OUT_IN}.
+ * {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT},
+ * {@link #CHANGE_BEHAVIOR_IN}, and {@link #CHANGE_BEHAVIOR_OUT_IN}.
*
* @param changeBehavior The type of fading animation to use when this
* transition is run.
+ * @return this textChange object.
*/
- public void setChangeBehavior(int changeBehavior) {
+ public TextChange setChangeBehavior(int changeBehavior) {
if (changeBehavior >= CHANGE_BEHAVIOR_KEEP && changeBehavior <= CHANGE_BEHAVIOR_OUT_IN) {
mChangeBehavior = changeBehavior;
}
+ return this;
}
@Override
@@ -100,19 +104,38 @@ public class TextChange extends Transition {
return sTransitionProperties;
}
- @Override
- protected void captureValues(TransitionValues values, boolean start) {
- if (values.view instanceof TextView) {
- TextView textview = (TextView) values.view;
- values.values.put(PROPNAME_TEXT, textview.getText());
+ /**
+ * Returns the type of changing animation that will be run.
+ *
+ * @return either {@link #CHANGE_BEHAVIOR_KEEP}, {@link #CHANGE_BEHAVIOR_OUT},
+ * {@link #CHANGE_BEHAVIOR_IN}, or {@link #CHANGE_BEHAVIOR_OUT_IN}.
+ */
+ public int getChangeBehavior() {
+ return mChangeBehavior;
+ }
+
+ private void captureValues(TransitionValues transitionValues) {
+ if (transitionValues.view instanceof TextView) {
+ TextView textview = (TextView) transitionValues.view;
+ transitionValues.values.put(PROPNAME_TEXT, textview.getText());
if (mChangeBehavior > CHANGE_BEHAVIOR_KEEP) {
- values.values.put(PROPNAME_TEXT_COLOR, textview.getCurrentTextColor());
+ transitionValues.values.put(PROPNAME_TEXT_COLOR, textview.getCurrentTextColor());
}
}
}
@Override
- protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ public void captureStartValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
if (startValues == null || endValues == null || !(endValues.view instanceof TextView)) {
return null;
@@ -120,8 +143,8 @@ public class TextChange extends Transition {
final TextView view = (TextView) endValues.view;
Map<String, Object> startVals = startValues.values;
Map<String, Object> endVals = endValues.values;
- final String startText = (String) startVals.get(PROPNAME_TEXT);
- final String endText = (String) endVals.get(PROPNAME_TEXT);
+ final CharSequence startText = (CharSequence) startVals.get(PROPNAME_TEXT);
+ final CharSequence endText = (CharSequence) endVals.get(PROPNAME_TEXT);
if (!startText.equals(endText)) {
view.setText(startText);
Animator anim;
diff --git a/core/java/android/view/transition/Transition.java b/core/java/android/transition/Transition.java
index a66fa52..59df183 100644
--- a/core/java/android/view/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -31,11 +31,12 @@ import android.view.ViewOverlay;
import android.widget.ListView;
import java.util.ArrayList;
+import java.util.List;
/**
* A Transition holds information about animations that will be run on its
* targets during a scene change. Subclasses of this abstract class may
- * choreograph several child transitions ({@link TransitionGroup} or they may
+ * choreograph several child transitions ({@link TransitionSet} or they may
* perform custom animations themselves. Any Transition has two main jobs:
* (1) capture property values, and (2) play animations based on changes to
* captured property values. A custom transition knows what property values
@@ -50,9 +51,42 @@ import java.util.ArrayList;
* a non-UI thread, so changes to the view due to transitions (such as moving
* and resizing the view) may be out of sync with the display inside those bounds.
* TextureView is more compatible with transitions in general, but some
- * specific transitions (such as {@link Crossfade}) may not be compatible
+ * specific transitions (such as {@link Fade}) may not be compatible
* with TextureView because they rely on {@link ViewOverlay} functionality,
* which does not currently work with TextureView.</p>
+ *
+ * <p>Transitions can be declared in XML resource files inside the <code>res/transition</code>
+ * directory. Transition resources consist of a tag name for one of the Transition
+ * subclasses along with attributes to define some of the attributes of that transition.
+ * For example, here is a minimal resource file that declares a {@link ChangeBounds} transition:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/transition/changebounds.xml ChangeBounds}
+ *
+ * <p>Note that attributes for the transition are not required, just as they are
+ * optional when declared in code; Transitions created from XML resources will use
+ * the same defaults as their code-created equivalents. Here is a slightly more
+ * elaborate example which declares a {@link TransitionSet} transition with
+ * {@link ChangeBounds} and {@link Fade} child transitions:</p>
+ *
+ * {@sample
+ * development/samples/ApiDemos/res/transition/changebounds_fadeout_sequential.xml TransitionSet}
+ *
+ * <p>In this example, the transitionOrdering attribute is used on the TransitionSet
+ * object to change from the default {@link TransitionSet#ORDERING_TOGETHER} behavior
+ * to be {@link TransitionSet#ORDERING_SEQUENTIAL} instead. Also, the {@link Fade}
+ * transition uses a fadingMode of {@link Fade#OUT} instead of the default
+ * out-in behavior. Finally, note the use of the <code>targets</code> sub-tag, which
+ * takes a set of {@link android.R.styleable#TransitionTarget target} tags, each
+ * of which lists a specific <code>targetId</code> which this transition acts upon.
+ * Use of targets is optional, but can be used to either limit the time spent checking
+ * attributes on unchanging views, or limiting the types of animations run on specific views.
+ * In this case, we know that only the <code>grayscaleContainer</code> will be
+ * disappearing, so we choose to limit the {@link Fade} transition to only that view.</p>
+ *
+ * Further information on XML resource descriptions for transitions can be found for
+ * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
+ * {@link android.R.styleable#TransitionTarget}, and {@link android.R.styleable#Fade}.
+ *
*/
public abstract class Transition implements Cloneable {
@@ -64,17 +98,17 @@ public abstract class Transition implements Cloneable {
long mStartDelay = -1;
long mDuration = -1;
TimeInterpolator mInterpolator = null;
- int[] mTargetIds;
- View[] mTargets;
+ ArrayList<Integer> mTargetIds = new ArrayList<Integer>();
+ ArrayList<View> mTargets = new ArrayList<View>();
private TransitionValuesMaps mStartValues = new TransitionValuesMaps();
private TransitionValuesMaps mEndValues = new TransitionValuesMaps();
- TransitionGroup mParent = null;
+ TransitionSet mParent = null;
// Per-animator information used for later canceling when future transitions overlap
private static ThreadLocal<ArrayMap<Animator, AnimationInfo>> sRunningAnimators =
new ThreadLocal<ArrayMap<Animator, AnimationInfo>>();
- // Scene Root is set at play() time in the cloned Transition
+ // Scene Root is set at createAnimator() time in the cloned Transition
ViewGroup mSceneRoot = null;
// Track all animators in use in case the transition gets canceled and needs to
@@ -91,14 +125,15 @@ public abstract class Transition implements Cloneable {
// The set of listeners to be sent transition lifecycle events.
ArrayList<TransitionListener> mListeners = null;
- // The set of animators collected from calls to play(), to be run in runAnimations()
+ // The set of animators collected from calls to createAnimator(),
+ // to be run in runAnimators()
ArrayList<Animator> mAnimators = new ArrayList<Animator>();
/**
* Constructs a Transition object with no target objects. A transition with
* no targets defaults to running on all target objects in the scene hierarchy
- * (if the transition is not contained in a TransitionGroup), or all target
- * objects passed down from its parent (if it is in a TransitionGroup).
+ * (if the transition is not contained in a TransitionSet), or all target
+ * objects passed down from its parent (if it is in a TransitionSet).
*/
public Transition() {}
@@ -110,6 +145,7 @@ public abstract class Transition implements Cloneable {
*
* @param duration The length of the animation, in milliseconds.
* @return This transition object.
+ * @attr ref android.R.styleable#Transition_duration
*/
public Transition setDuration(long duration) {
mDuration = duration;
@@ -121,8 +157,8 @@ public abstract class Transition implements Cloneable {
* the returned value will be negative, indicating that resulting animators will
* retain their own durations.
*
- * @return The duration set on this transition, if one has been set, otherwise
- * returns a negative number.
+ * @return The duration set on this transition, in milliseconds, if one has been
+ * set, otherwise returns a negative number.
*/
public long getDuration() {
return mDuration;
@@ -135,9 +171,12 @@ public abstract class Transition implements Cloneable {
* Transition is set, that delay will override the Animator delay.
*
* @param startDelay The length of the delay, in milliseconds.
+ * @return This transition object.
+ * @attr ref android.R.styleable#Transition_startDelay
*/
- public void setStartDelay(long startDelay) {
+ public Transition setStartDelay(long startDelay) {
mStartDelay = startDelay;
+ return this;
}
/**
@@ -145,8 +184,8 @@ public abstract class Transition implements Cloneable {
* the returned value will be negative, indicating that resulting animators will
* retain their own startDelays.
*
- * @return The startDealy set on this transition, if one has been set, otherwise
- * returns a negative number.
+ * @return The startDelay set on this transition, in milliseconds, if one has
+ * been set, otherwise returns a negative number.
*/
public long getStartDelay() {
return mStartDelay;
@@ -159,9 +198,12 @@ public abstract class Transition implements Cloneable {
* Transition is set, that interpolator will override the Animator interpolator.
*
* @param interpolator The time interpolator used by the transition
+ * @return This transition object.
+ * @attr ref android.R.styleable#Transition_interpolator
*/
- public void setInterpolator(TimeInterpolator interpolator) {
+ public Transition setInterpolator(TimeInterpolator interpolator) {
mInterpolator = interpolator;
+ return this;
}
/**
@@ -178,7 +220,7 @@ public abstract class Transition implements Cloneable {
/**
* Returns the set of property names used stored in the {@link TransitionValues}
- * object passed into {@link #captureValues(TransitionValues, boolean)} that
+ * object passed into {@link #captureStartValues(TransitionValues)} that
* this transition cares about for the purposes of canceling overlapping animations.
* When any transition is started on a given scene root, all transitions
* currently running on that same scene root are checked to see whether the
@@ -202,11 +244,17 @@ public abstract class Transition implements Cloneable {
}
/**
- * This method is called by the transition's parent (all the way up to the
+ * This method creates an animation that will be run for this transition
+ * given the information in the startValues and endValues structures captured
+ * earlier for the start and end scenes. Subclasses of Transition should override
+ * this method. The method should only be called by the transition system; it is
+ * not intended to be called from external classes.
+ *
+ * <p>This method is called by the transition's parent (all the way up to the
* topmost Transition in the hierarchy) with the sceneRoot and start/end
* values that the transition may need to set up initial target values
* and construct an appropriate animation. For example, if an overall
- * Transition is a {@link TransitionGroup} consisting of several
+ * Transition is a {@link TransitionSet} consisting of several
* child transitions in sequence, then some of the child transitions may
* want to set initial values on target views prior to the overall
* Transition commencing, to put them in an appropriate state for the
@@ -216,14 +264,13 @@ public abstract class Transition implements Cloneable {
* actually starting the animation. This is necessary because the scene
* change that triggers the Transition will automatically set the end-scene
* on all target views, so a Transition that wants to animate from a
- * different value should set that value prior to returning from this method.
+ * different value should set that value prior to returning from this method.</p>
*
* <p>Additionally, a Transition can perform logic to determine whether
* the transition needs to run on the given target and start/end values.
* For example, a transition that resizes objects on the screen may wish
* to avoid running for views which are not present in either the start
- * or end scenes. A return value of <code>null</code> indicates that
- * no animation should run. The default implementation returns null.</p>
+ * or end scenes.</p>
*
* <p>If there is an animator created and returned from this method, the
* transition mechanism will apply any applicable duration, startDelay,
@@ -234,31 +281,34 @@ public abstract class Transition implements Cloneable {
* <p>The method is called for every applicable target object, which is
* stored in the {@link TransitionValues#view} field.</p>
*
- * @param sceneRoot
- * @param startValues
- * @param endValues
- * @return A non-null Animator to be started at the appropriate time in the
- * overall transition for this scene change, null otherwise.
+ *
+ * @param sceneRoot The root of the transition hierarchy.
+ * @param startValues The values for a specific target in the start scene.
+ * @param endValues The values for the target in the end scene.
+ * @return A Animator to be started at the appropriate time in the
+ * overall transition for this scene change. A null value means no animation
+ * should be run.
*/
- protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
return null;
}
/**
- * This version of play() is called with the entire set of start/end
+ * This method, essentially a wrapper around all calls to createAnimator for all
+ * possible target views, is called with the entire set of start/end
* values. The implementation in Transition iterates through these lists
- * and calls {@link #play(ViewGroup, TransitionValues, TransitionValues)}
+ * and calls {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}
* with each set of start/end values on this transition. The
- * TransitionGroup subclass overrides this method and delegates it to
+ * TransitionSet subclass overrides this method and delegates it to
* each of its children in succession.
*
* @hide
*/
- protected void play(ViewGroup sceneRoot, TransitionValuesMaps startValues,
+ protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
TransitionValuesMaps endValues) {
if (DBG) {
- Log.d(LOG_TAG, "play() for " + this);
+ Log.d(LOG_TAG, "createAnimators() for " + this);
}
ArrayMap<View, TransitionValues> endCopy =
new ArrayMap<View, TransitionValues>(endValues.viewValues);
@@ -392,7 +442,7 @@ public abstract class Transition implements Cloneable {
}
}
// TODO: what to do about targetIds and itemIds?
- Animator animator = play(sceneRoot, start, end);
+ Animator animator = createAnimator(sceneRoot, start, end);
if (animator != null) {
// Save animation info for future cancellation purposes
View view = null;
@@ -450,19 +500,19 @@ public abstract class Transition implements Cloneable {
* views are ignored and only the ids are used).
*/
boolean isValidTarget(View target, long targetId) {
- if (mTargetIds == null && mTargets == null) {
+ if (mTargetIds.size() == 0 && mTargets.size() == 0) {
return true;
}
- if (mTargetIds != null) {
- for (int i = 0; i < mTargetIds.length; ++i) {
- if (mTargetIds[i] == targetId) {
+ if (mTargetIds.size() > 0) {
+ for (int i = 0; i < mTargetIds.size(); ++i) {
+ if (mTargetIds.get(i) == targetId) {
return true;
}
}
}
- if (target != null && mTargets != null) {
- for (int i = 0; i < mTargets.length; ++i) {
- if (mTargets[i] == target) {
+ if (target != null && mTargets.size() > 0) {
+ for (int i = 0; i < mTargets.size(); ++i) {
+ if (mTargets.get(i) == target) {
return true;
}
}
@@ -485,13 +535,13 @@ public abstract class Transition implements Cloneable {
*
* @hide
*/
- protected void runAnimations() {
+ protected void runAnimators() {
if (DBG) {
- Log.d(LOG_TAG, "runAnimations() on " + this);
+ Log.d(LOG_TAG, "runAnimators() on " + this);
}
start();
ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
- // Now start every Animator that was previously created for this transition in play()
+ // Now start every Animator that was previously created for this transition
for (Animator anim : mAnimators) {
if (DBG) {
Log.d(LOG_TAG, " anim: " + anim);
@@ -525,17 +575,49 @@ public abstract class Transition implements Cloneable {
}
/**
- * Captures the current scene of values for the properties that this
- * transition monitors. These values can be either the start or end
- * values used in a subsequent call to
- * {@link #play(ViewGroup, TransitionValues, TransitionValues)}, as indicated by
- * <code>start</code>. The main concern for an implementation is what the
+ * Captures the values in the start scene for the properties that this
+ * transition monitors. These values are then passed as the startValues
+ * structure in a later call to
+ * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
+ * The main concern for an implementation is what the
+ * properties are that the transition cares about and what the values are
+ * for all of those properties. The start and end values will be compared
+ * later during the
+ * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)}
+ * method to determine what, if any, animations, should be run.
+ *
+ * <p>Subclasses must implement this method. The method should only be called by the
+ * transition system; it is not intended to be called from external classes.</p>
+ *
+ * @param transitionValues The holder for any values that the Transition
+ * wishes to store. Values are stored in the <code>values</code> field
+ * of this TransitionValues object and are keyed from
+ * a String value. For example, to store a view's rotation value,
+ * a transition might call
+ * <code>transitionValues.values.put("appname:transitionname:rotation",
+ * view.getRotation())</code>. The target view will already be stored in
+ * the transitionValues structure when this method is called.
+ *
+ * @see #captureEndValues(TransitionValues)
+ * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
+ */
+ public abstract void captureStartValues(TransitionValues transitionValues);
+
+ /**
+ * Captures the values in the end scene for the properties that this
+ * transition monitors. These values are then passed as the endValues
+ * structure in a later call to
+ * {@link #createAnimator(ViewGroup, TransitionValues, TransitionValues)}.
+ * The main concern for an implementation is what the
* properties are that the transition cares about and what the values are
* for all of those properties. The start and end values will be compared
* later during the
- * {@link #play(android.view.ViewGroup, TransitionValues, TransitionValues)}
+ * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)}
* method to determine what, if any, animations, should be run.
*
+ * <p>Subclasses must implement this method. The method should only be called by the
+ * transition system; it is not intended to be called from external classes.</p>
+ *
* @param transitionValues The holder for any values that the Transition
* wishes to store. Values are stored in the <code>values</code> field
* of this TransitionValues object and are keyed from
@@ -544,29 +626,51 @@ public abstract class Transition implements Cloneable {
* <code>transitionValues.values.put("appname:transitionname:rotation",
* view.getRotation())</code>. The target view will already be stored in
* the transitionValues structure when this method is called.
+ *
+ * @see #captureStartValues(TransitionValues)
+ * @see #createAnimator(ViewGroup, TransitionValues, TransitionValues)
*/
- protected abstract void captureValues(TransitionValues transitionValues, boolean start);
+ public abstract void captureEndValues(TransitionValues transitionValues);
/**
- * Sets the ids of target views that this Transition is interested in
+ * Adds the id of a target view that this Transition is interested in
* animating. By default, there are no targetIds, and a Transition will
* listen for changes on every view in the hierarchy below the sceneRoot
- * of the Scene being transitioned into. Setting targetIDs constrains
+ * of the Scene being transitioned into. Setting targetIds constrains
* the Transition to only listen for, and act on, views with these IDs.
* Views with different IDs, or no IDs whatsoever, will be ignored.
*
+ * <p>Note that using ids to specify targets implies that ids should be unique
+ * within the view hierarchy underneat the scene root.</p>
+ *
* @see View#getId()
- * @param targetIds A list of IDs which specify the set of Views on which
- * the Transition will act.
- * @return Transition The Transition on which the targetIds have been set.
+ * @param targetId The id of a target view, must be a positive number.
+ * @return The Transition to which the targetId is added.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).addTargetId(someId);</code>
+ */
+ public Transition addTargetId(int targetId) {
+ if (targetId > 0) {
+ mTargetIds.add(targetId);
+ }
+ return this;
+ }
+
+ /**
+ * Removes the given targetId from the list of ids that this Transition
+ * is interested in animating.
+ *
+ * @param targetId The id of a target view, must be a positive number.
+ * @return The Transition from which the targetId is removed.
* Returning the same object makes it easier to chain calls during
* construction, such as
- * <code>transitionGroup.addTransitions(new Fade()).setTargetIds(someId);</code>
+ * <code>transitionSet.addTransitions(new Fade()).removeTargetId(someId);</code>
*/
- public Transition setTargetIds(int... targetIds) {
- int numTargets = targetIds.length;
- mTargetIds = new int[numTargets];
- System.arraycopy(targetIds, 0, mTargetIds, 0, numTargets);
+ public Transition removeTargetId(int targetId) {
+ if (targetId > 0) {
+ mTargetIds.remove(targetId);
+ }
return this;
}
@@ -578,28 +682,43 @@ public abstract class Transition implements Cloneable {
* the Transition to only listen for, and act on, these views.
* All other views will be ignored.
*
- * <p>The target list is like the {@link #setTargetIds(int...) targetId}
+ * <p>The target list is like the {@link #addTargetId(int) targetId}
* list except this list specifies the actual View instances, not the ids
* of the views. This is an important distinction when scene changes involve
* view hierarchies which have been inflated separately; different views may
* share the same id but not actually be the same instance. If the transition
- * should treat those views as the same, then seTargetIds() should be used
- * instead of setTargets(). If, on the other hand, scene changes involve
+ * should treat those views as the same, then {@link #addTargetId(int)} should be used
+ * instead of {@link #addTarget(View)}. If, on the other hand, scene changes involve
* changes all within the same view hierarchy, among views which do not
- * necessary have ids set on them, then the target list may be more
+ * necessarily have ids set on them, then the target list of views may be more
* convenient.</p>
*
- * @see #setTargetIds(int...)
- * @param targets A list of Views on which the Transition will act.
- * @return Transition The Transition on which the targets have been set.
+ * @see #addTargetId(int)
+ * @param target A View on which the Transition will act, must be non-null.
+ * @return The Transition to which the target is added.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionSet.addTransitions(new Fade()).addTarget(someView);</code>
+ */
+ public Transition addTarget(View target) {
+ mTargets.add(target);
+ return this;
+ }
+
+ /**
+ * Removes the given target from the list of targets that this Transition
+ * is interested in animating.
+ *
+ * @param target The target view, must be non-null.
+ * @return Transition The Transition from which the target is removed.
* Returning the same object makes it easier to chain calls during
* construction, such as
- * <code>transitionGroup.addTransitions(new Fade()).setTargets(someView);</code>
+ * <code>transitionSet.addTransitions(new Fade()).removeTarget(someView);</code>
*/
- public Transition setTargets(View... targets) {
- int numTargets = targets.length;
- mTargets = new View[numTargets];
- System.arraycopy(targets, 0, mTargets, 0, numTargets);
+ public Transition removeTarget(View target) {
+ if (target != null) {
+ mTargets.remove(target);
+ }
return this;
}
@@ -612,7 +731,7 @@ public abstract class Transition implements Cloneable {
*
* @return the list of target IDs
*/
- public int[] getTargetIds() {
+ public List<Integer> getTargetIds() {
return mTargetIds;
}
@@ -625,7 +744,7 @@ public abstract class Transition implements Cloneable {
*
* @return the list of target views
*/
- public View[] getTargets() {
+ public List<View> getTargets() {
return mTargets;
}
@@ -646,16 +765,19 @@ public abstract class Transition implements Cloneable {
mEndValues.idValues.clear();
mEndValues.itemIdValues.clear();
}
- if (mTargetIds != null && mTargetIds.length > 0 ||
- mTargets != null && mTargets.length > 0) {
- if (mTargetIds != null) {
- for (int i = 0; i < mTargetIds.length; ++i) {
- int id = mTargetIds[i];
+ if (mTargetIds.size() > 0 || mTargets.size() > 0) {
+ if (mTargetIds.size() > 0) {
+ for (int i = 0; i < mTargetIds.size(); ++i) {
+ int id = mTargetIds.get(i);
View view = sceneRoot.findViewById(id);
if (view != null) {
TransitionValues values = new TransitionValues();
values.view = view;
- captureValues(values, start);
+ if (start) {
+ captureStartValues(values);
+ } else {
+ captureEndValues(values);
+ }
if (start) {
mStartValues.viewValues.put(view, values);
if (id >= 0) {
@@ -670,13 +792,17 @@ public abstract class Transition implements Cloneable {
}
}
}
- if (mTargets != null) {
- for (int i = 0; i < mTargets.length; ++i) {
- View view = mTargets[i];
+ if (mTargets.size() > 0) {
+ for (int i = 0; i < mTargets.size(); ++i) {
+ View view = mTargets.get(i);
if (view != null) {
TransitionValues values = new TransitionValues();
values.view = view;
- captureValues(values, start);
+ if (start) {
+ captureStartValues(values);
+ } else {
+ captureEndValues(values);
+ }
if (start) {
mStartValues.viewValues.put(view, values);
} else {
@@ -723,7 +849,7 @@ public abstract class Transition implements Cloneable {
}
TransitionValues values = new TransitionValues();
values.view = view;
- captureValues(values, start);
+ captureStartValues(values);
if (start) {
if (!isListViewItem) {
mStartValues.viewValues.put(view, values);
@@ -757,7 +883,7 @@ public abstract class Transition implements Cloneable {
* necessary, for example, to query the before/after state of related views
* for a given transition.
*/
- protected TransitionValues getTransitionValues(View view, boolean start) {
+ public TransitionValues getTransitionValues(View view, boolean start) {
if (mParent != null) {
return mParent.getTransitionValues(view, start);
}
@@ -834,7 +960,7 @@ public abstract class Transition implements Cloneable {
/**
* Called by TransitionManager to play the transition. This calls
- * play() to set things up and create all of the animations and then
+ * createAnimators() to set things up and create all of the animations and then
* runAnimations() to actually start the animations.
*/
void playTransition(ViewGroup sceneRoot) {
@@ -889,11 +1015,8 @@ public abstract class Transition implements Cloneable {
}
}
- // setup() must be called on entire transition hierarchy and set of views
- // before calling play() on anything; every transition needs a chance to set up
- // target views appropriately before transitions begin running
- play(sceneRoot, mStartValues, mEndValues);
- runAnimations();
+ createAnimators(sceneRoot, mStartValues, mEndValues);
+ runAnimators();
}
/**
@@ -933,7 +1056,7 @@ public abstract class Transition implements Cloneable {
/**
* This method is called automatically by the transition and
- * TransitionGroup classes prior to a Transition subclass starting;
+ * TransitionSet classes prior to a Transition subclass starting;
* subclasses should not need to call it directly.
*
* @hide
@@ -954,9 +1077,9 @@ public abstract class Transition implements Cloneable {
/**
* This method is called automatically by the Transition and
- * TransitionGroup classes when a transition finishes, either because
+ * TransitionSet classes when a transition finishes, either because
* a transition did nothing (returned a null Animator from
- * {@link Transition#play(ViewGroup, TransitionValues,
+ * {@link Transition#createAnimator(ViewGroup, TransitionValues,
* TransitionValues)}) or because the transition returned a valid
* Animator and end() was called in the onAnimationEnd()
* callback of the AnimatorListener.
@@ -993,11 +1116,10 @@ public abstract class Transition implements Cloneable {
/**
* This method cancels a transition that is currently running.
- * Implementation TBD.
+ *
+ * @hide
*/
protected void cancel() {
- // TODO: how does this work with instances?
- // TODO: this doesn't actually do *anything* yet
int numAnimators = mCurrentAnimators.size();
for (int i = numAnimators - 1; i >= 0; i--) {
Animator animator = mCurrentAnimators.get(i);
@@ -1019,12 +1141,14 @@ public abstract class Transition implements Cloneable {
*
* @param listener the listener to be added to the current set of listeners
* for this animation.
+ * @return This transition object.
*/
- public void addListener(TransitionListener listener) {
+ public Transition addListener(TransitionListener listener) {
if (mListeners == null) {
mListeners = new ArrayList<TransitionListener>();
}
mListeners.add(listener);
+ return this;
}
/**
@@ -1032,29 +1156,22 @@ public abstract class Transition implements Cloneable {
*
* @param listener the listener to be removed from the current set of
* listeners for this transition.
+ * @return This transition object.
*/
- public void removeListener(TransitionListener listener) {
+ public Transition removeListener(TransitionListener listener) {
if (mListeners == null) {
- return;
+ return this;
}
mListeners.remove(listener);
if (mListeners.size() == 0) {
mListeners = null;
}
+ return this;
}
- /**
- * Gets the set of {@link TransitionListener} objects that are currently
- * listening for events on this <code>Transition</code> object.
- *
- * @return ArrayList<TransitionListener> The set of listeners.
- */
- public ArrayList<TransitionListener> getListeners() {
- return mListeners;
- }
-
- void setSceneRoot(ViewGroup sceneRoot) {
+ Transition setSceneRoot(ViewGroup sceneRoot) {
mSceneRoot = sceneRoot;
+ return this;
}
@Override
@@ -1076,9 +1193,9 @@ public abstract class Transition implements Cloneable {
/**
* Returns the name of this Transition. This name is used internally to distinguish
* between different transitions to determine when interrupting transitions overlap.
- * For example, a Move running on the same target view as another Move should determine
- * whether the old transition is animating to different end values and should be
- * canceled in favor of the new transition.
+ * For example, a ChangeBounds running on the same target view as another ChangeBounds
+ * should determine whether the old transition is animating to different end values
+ * and should be canceled in favor of the new transition.
*
* <p>By default, a Transition's name is simply the value of {@link Class#getName()},
* but subclasses are free to override and return something different.</p>
@@ -1101,22 +1218,22 @@ public abstract class Transition implements Cloneable {
if (mInterpolator != null) {
result += "interp(" + mInterpolator + ") ";
}
- if (mTargetIds != null || mTargets != null) {
+ if (mTargetIds.size() > 0 || mTargets.size() > 0) {
result += "tgts(";
- if (mTargetIds != null) {
- for (int i = 0; i < mTargetIds.length; ++i) {
+ if (mTargetIds.size() > 0) {
+ for (int i = 0; i < mTargetIds.size(); ++i) {
if (i > 0) {
result += ", ";
}
- result += mTargetIds[i];
+ result += mTargetIds.get(i);
}
}
- if (mTargets != null) {
- for (int i = 0; i < mTargets.length; ++i) {
+ if (mTargets.size() > 0) {
+ for (int i = 0; i < mTargets.size(); ++i) {
if (i > 0) {
result += ", ";
}
- result += mTargets[i];
+ result += mTargets.get(i);
}
}
result += ")";
@@ -1149,11 +1266,11 @@ public abstract class Transition implements Cloneable {
/**
* Notification about the cancellation of the transition.
- * Note that cancel() may be called by a parent {@link TransitionGroup} on
+ * Note that cancel may be called by a parent {@link TransitionSet} on
* a child transition which has not yet started. This allows the child
* transition to restore state on target objects which was set at
- * {@link #play(android.view.ViewGroup, TransitionValues, TransitionValues)
- * play()} time.
+ * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)
+ * createAnimator()} time.
*
* @param transition The transition which was canceled.
*/
@@ -1161,11 +1278,11 @@ public abstract class Transition implements Cloneable {
/**
* Notification when a transition is paused.
- * Note that play() may be called by a parent {@link TransitionGroup} on
+ * Note that createAnimator() may be called by a parent {@link TransitionSet} on
* a child transition which has not yet started. This allows the child
* transition to restore state on target objects which was set at
- * {@link #play(android.view.ViewGroup, TransitionValues, TransitionValues)
- * play()} time.
+ * {@link #createAnimator(android.view.ViewGroup, TransitionValues, TransitionValues)
+ * createAnimator()} time.
*
* @param transition The transition which was paused.
*/
@@ -1173,7 +1290,7 @@ public abstract class Transition implements Cloneable {
/**
* Notification when a transition is resumed.
- * Note that resume() may be called by a parent {@link TransitionGroup} on
+ * Note that resume() may be called by a parent {@link TransitionSet} on
* a child transition which has not yet started. This allows the child
* transition to restore state which may have changed in an earlier call
* to {@link #onTransitionPause(Transition)}.
diff --git a/core/java/android/view/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index be658af..ebedeeb 100644
--- a/core/java/android/view/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.content.Context;
import android.content.res.Resources;
@@ -35,6 +35,11 @@ import java.util.ArrayList;
/**
* This class inflates scenes and transitions from resource files.
+ *
+ * Information on XML resource descriptions for transitions can be found for
+ * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
+ * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
+ * and {@link android.R.styleable#TransitionManager}.
*/
public class TransitionInflater {
@@ -121,46 +126,12 @@ public class TransitionInflater {
}
}
- /**
- * Loads a {@link Scene} object from a resource
- *
- * @param resource The resource id of the scene to load
- * @return The loaded Scene object
- * @throws android.content.res.Resources.NotFoundException when the scene
- * cannot be loaded
- */
- public Scene inflateScene(int resource, ViewGroup parent) {
- Scene scene = mScenes.get(resource);
- if (scene != null) {
- return scene;
- }
- XmlResourceParser parser = mContext.getResources().getXml(resource);
- try {
- scene = createSceneFromXml(parser, Xml.asAttributeSet(parser), parent);
- mScenes.put(resource, scene);
- return scene;
- } catch (XmlPullParserException e) {
- InflateException ex = new InflateException(e.getMessage());
- ex.initCause(e);
- throw ex;
- } catch (IOException e) {
- InflateException ex = new InflateException(
- parser.getPositionDescription()
- + ": " + e.getMessage());
- ex.initCause(e);
- throw ex;
- } finally {
- parser.close();
- }
- }
-
-
//
// Transition loading
//
private Transition createTransitionFromXml(XmlPullParser parser,
- AttributeSet attrs, TransitionGroup transitionGroup)
+ AttributeSet attrs, TransitionSet transitionSet)
throws XmlPullParserException, IOException {
Transition transition = null;
@@ -180,10 +151,14 @@ public class TransitionInflater {
String name = parser.getName();
if ("fade".equals(name)) {
- transition = new Fade();
+ TypedArray a = mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Fade);
+ int fadingMode = a.getInt(com.android.internal.R.styleable.Fade_fadingMode,
+ Fade.IN | Fade.OUT);
+ transition = new Fade(fadingMode);
newTransition = true;
- } else if ("move".equals(name)) {
- transition = new Move();
+ } else if ("changeBounds".equals(name)) {
+ transition = new ChangeBounds();
newTransition = true;
} else if ("slide".equals(name)) {
transition = new Slide();
@@ -194,24 +169,31 @@ public class TransitionInflater {
} else if ("recolor".equals(name)) {
transition = new Recolor();
newTransition = true;
- } else if ("transitionGroup".equals(name)) {
- transition = new TransitionGroup();
- createTransitionFromXml(parser, attrs, ((TransitionGroup) transition));
+ } else if ("set".equals(name)) {
+ transition = new TransitionSet();
+ TypedArray a = mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.TransitionSet);
+ int ordering = a.getInt(
+ com.android.internal.R.styleable.TransitionSet_transitionOrdering,
+ TransitionSet.ORDERING_TOGETHER);
+ ((TransitionSet) transition).setOrdering(ordering);
+ createTransitionFromXml(parser, attrs, ((TransitionSet) transition));
+ a.recycle();
newTransition = true;
} else if ("targets".equals(name)) {
if (parser.getDepth() - 1 > depth && transition != null) {
// We're inside the child tag - add targets to the child
- getTargetIDs(parser, attrs, transition);
- } else if (parser.getDepth() - 1 == depth && transitionGroup != null) {
- // add targets to the group
- getTargetIDs(parser, attrs, transitionGroup);
+ getTargetIds(parser, attrs, transition);
+ } else if (parser.getDepth() - 1 == depth && transitionSet != null) {
+ // add targets to the set
+ getTargetIds(parser, attrs, transitionSet);
}
}
if (transition != null || "targets".equals(name)) {
if (newTransition) {
loadTransition(transition, attrs);
- if (transitionGroup != null) {
- transitionGroup.addTransitions(transition);
+ if (transitionSet != null) {
+ transitionSet.addTransition(transition);
}
}
} else {
@@ -222,7 +204,7 @@ public class TransitionInflater {
return transition;
}
- private void getTargetIDs(XmlPullParser parser,
+ private void getTargetIds(XmlPullParser parser,
AttributeSet attrs, Transition transition) throws XmlPullParserException, IOException {
// Make sure we are on a start tag.
@@ -240,8 +222,9 @@ public class TransitionInflater {
String name = parser.getName();
if (name.equals("target")) {
TypedArray a = mContext.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.Transition);
- int id = a.getResourceId(com.android.internal.R.styleable.Transition_targetID, -1);
+ com.android.internal.R.styleable.TransitionTarget);
+ int id = a.getResourceId(
+ com.android.internal.R.styleable.TransitionTarget_targetId, -1);
if (id >= 0) {
targetIds.add(id);
}
@@ -251,11 +234,9 @@ public class TransitionInflater {
}
int numTargets = targetIds.size();
if (numTargets > 0) {
- int[] targetsArray = new int[numTargets];
- for (int i = 0; i < targetIds.size(); ++i) {
- targetsArray[i] = targetIds.get(i);
+ for (int i = 0; i < numTargets; ++i) {
+ transition.addTargetId(targetIds.get(i));
}
- transition.setTargetIds(targetsArray);
}
}
@@ -268,9 +249,9 @@ public class TransitionInflater {
if (duration >= 0) {
transition.setDuration(duration);
}
- long startOffset = a.getInt(com.android.internal.R.styleable.Transition_startOffset, -1);
- if (startOffset > 0) {
- transition.setStartDelay(startOffset);
+ long startDelay = a.getInt(com.android.internal.R.styleable.Transition_startDelay, -1);
+ if (startDelay > 0) {
+ transition.setStartDelay(startDelay);
}
final int resID =
a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
@@ -313,20 +294,19 @@ public class TransitionInflater {
}
private void loadTransition(AttributeSet attrs, ViewGroup sceneRoot,
- TransitionManager transitionManager)
- throws Resources.NotFoundException {
+ TransitionManager transitionManager) throws Resources.NotFoundException {
TypedArray a = mContext.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.TransitionManager);
- int transitionId = attrs.getAttributeResourceValue(
+ int transitionId = a.getResourceId(
com.android.internal.R.styleable.TransitionManager_transition, -1);
Scene fromScene = null, toScene = null;
- int fromId = attrs.getAttributeResourceValue(
+ int fromId = a.getResourceId(
com.android.internal.R.styleable.TransitionManager_fromScene, -1);
- if (fromId >= 0) fromScene = inflateScene(fromId, sceneRoot);
- int toId = attrs.getAttributeResourceValue(
+ if (fromId >= 0) fromScene = Scene.getSceneForLayout(sceneRoot, fromId, mContext);
+ int toId = a.getResourceId(
com.android.internal.R.styleable.TransitionManager_toScene, -1);
- if (toId >= 0) toScene = inflateScene(toId, sceneRoot);
+ if (toId >= 0) toScene = Scene.getSceneForLayout(sceneRoot, toId, mContext);
if (transitionId >= 0) {
Transition transition = inflateTransition(transitionId);
if (transition != null) {
@@ -344,50 +324,4 @@ public class TransitionInflater {
}
a.recycle();
}
-
- //
- // Scene loading
- //
-
- private Scene createSceneFromXml(XmlPullParser parser, AttributeSet attrs, ViewGroup parent)
- throws XmlPullParserException, IOException {
- Scene scene = null;
-
- // Make sure we are on a start tag.
- int type;
- int depth = parser.getDepth();
-
- while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
- && type != XmlPullParser.END_DOCUMENT) {
-
- if (type != XmlPullParser.START_TAG) {
- continue;
- }
-
- String name = parser.getName();
- if (name.equals("scene")) {
- scene = loadScene(attrs, parent);
- } else {
- throw new RuntimeException("Unknown scene name: " + parser.getName());
- }
- }
-
- return scene;
- }
-
- private Scene loadScene(AttributeSet attrs, ViewGroup parent)
- throws Resources.NotFoundException {
-
- Scene scene;
- TypedArray a = mContext.obtainStyledAttributes(attrs,
- com.android.internal.R.styleable.Scene);
- int layoutId = a.getResourceId(com.android.internal.R.styleable.Scene_layout, -1);
- if (layoutId >= 0) {
- scene = new Scene(parent, layoutId, mContext);
- } else {
- scene = new Scene(parent);
- }
- a.recycle();
- return scene;
- }
}
diff --git a/core/java/android/view/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index bde891d..9904413 100644
--- a/core/java/android/view/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
+import android.content.Context;
import android.util.ArrayMap;
import android.util.Log;
-import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -34,14 +34,36 @@ import java.util.ArrayList;
* situations. Specifying other transitions for particular scene changes is
* only necessary if the application wants different transition behavior
* in these situations.
+ *
+ * <p>TransitionManagers can be declared in XML resource files inside the
+ * <code>res/transition</code> directory. TransitionManager resources consist of
+ * the <code>transitionManager</code>tag name, containing one or more
+ * <code>transition</code> tags, each of which describe the relationship of
+ * that transition to the from/to scene information in that tag.
+ * For example, here is a resource file that declares several scene
+ * transitions:</p>
+ *
+ * {@sample development/samples/ApiDemos/res/transition/transitions_mgr.xml TransitionManager}
+ *
+ * <p>For each of the <code>fromScene</code> and <code>toScene</code> attributes,
+ * there is a reference to a standard XML layout file. This is equivalent to
+ * creating a scene from a layout in code by calling
+ * {@link Scene#getSceneForLayout(ViewGroup, int, Context)}. For the
+ * <code>transition</code> attribute, there is a reference to a resource
+ * file in the <code>res/transition</code> directory which describes that
+ * transition.</p>
+ *
+ * Information on XML resource descriptions for transitions can be found for
+ * {@link android.R.styleable#Transition}, {@link android.R.styleable#TransitionSet},
+ * {@link android.R.styleable#TransitionTarget}, {@link android.R.styleable#Fade},
+ * and {@link android.R.styleable#TransitionManager}.
*/
public class TransitionManager {
// TODO: how to handle enter/exit?
private static String LOG_TAG = "TransitionManager";
- private static final Transition sDefaultTransition = new AutoTransition();
- private Transition mDefaultTransition = new AutoTransition();
+ private static Transition sDefaultTransition = new AutoTransition();
ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
@@ -59,7 +81,7 @@ public class TransitionManager {
* @param transition The default transition to be used for scene changes.
*/
public void setDefaultTransition(Transition transition) {
- mDefaultTransition = transition;
+ sDefaultTransition = transition;
}
/**
@@ -69,8 +91,8 @@ public class TransitionManager {
* @return The current default transition.
* @see #setDefaultTransition(Transition)
*/
- public Transition getDefaultTransition() {
- return mDefaultTransition;
+ public static Transition getDefaultTransition() {
+ return sDefaultTransition;
}
/**
@@ -80,7 +102,7 @@ public class TransitionManager {
* transition to run.
* @param transition The transition that will play when the given scene is
* entered. A value of null will result in the default behavior of
- * using {@link AutoTransition}.
+ * using the {@link #getDefaultTransition() default transition} instead.
*/
public void setTransition(Scene scene, Transition transition) {
mSceneTransitions.put(scene, transition);
@@ -96,7 +118,7 @@ public class TransitionManager {
* be run
* @param transition The transition that will play when the given scene is
* entered. A value of null will result in the default behavior of
- * using {@link AutoTransition}.
+ * using the {@link #getDefaultTransition() default transition} instead.
*/
public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
@@ -114,15 +136,15 @@ public class TransitionManager {
*
* @param scene The scene being entered
* @return The Transition to be used for the given scene change. If no
- * Transition was specified for this scene change, {@link AutoTransition}
- * will be used instead.
+ * Transition was specified for this scene change, the {@link #getDefaultTransition()
+ * default transition} will be used instead.
*/
private Transition getTransition(Scene scene) {
Transition transition = null;
ViewGroup sceneRoot = scene.getSceneRoot();
if (sceneRoot != null) {
// TODO: cached in Scene instead? long-term, cache in View itself
- Scene currScene = sceneRoot.getCurrentScene();
+ Scene currScene = Scene.getCurrentScene(sceneRoot);
if (currScene != null) {
ArrayMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(scene);
if (sceneTransitionMap != null) {
@@ -134,7 +156,7 @@ public class TransitionManager {
}
}
transition = mSceneTransitions.get(scene);
- return (transition != null) ? transition : new AutoTransition();
+ return (transition != null) ? transition : sDefaultTransition;
}
/**
@@ -234,7 +256,7 @@ public class TransitionManager {
}
// Notify previous scene that it is being exited
- Scene previousScene = sceneRoot.getCurrentScene();
+ Scene previousScene = Scene.getCurrentScene(sceneRoot);
if (previousScene != null) {
previousScene.exit();
}
@@ -256,7 +278,7 @@ public class TransitionManager {
}
/**
- * Static utility method to simply change to the given scene using
+ * Convenience method to simply change to the given scene using
* the default transition for TransitionManager.
*
* @param scene The Scene to change to
@@ -266,15 +288,14 @@ public class TransitionManager {
}
/**
- * Static utility method to simply change to the given scene using
+ * Convenience method to simply change to the given scene using
* the given transition.
*
* <p>Passing in <code>null</code> for the transition parameter will
* result in the scene changing without any transition running, and is
* equivalent to calling {@link Scene#exit()} on the scene root's
- * {@link ViewGroup#getCurrentScene() current scene}, followed by
- * {@link Scene#enter()} on the scene specified by the <code>scene</code>
- * parameter.</p>
+ * current scene, followed by {@link Scene#enter()} on the scene
+ * specified by the <code>scene</code> parameter.</p>
*
* @param scene The Scene to change to
* @param transition The transition to use for this scene change. A
@@ -285,55 +306,20 @@ public class TransitionManager {
}
/**
- * Static utility method to simply change to a scene defined by the
- * code in the given runnable, which will be executed after
- * the current values have been captured for the transition.
- * This is equivalent to creating a Scene and calling {@link
- * Scene#setEnterAction(Runnable)} with the runnable, then calling
- * {@link #go(Scene, Transition)}. The transition used will be the
- * default provided by TransitionManager.
- *
- * @param sceneRoot The root of the View hierarchy used when this scene
- * runs a transition automatically.
- * @param action The runnable whose {@link Runnable#run() run()} method will
- * be called.
- */
- public static void go(ViewGroup sceneRoot, Runnable action) {
- Scene scene = new Scene(sceneRoot);
- scene.setEnterAction(action);
- changeScene(scene, sDefaultTransition);
- }
-
- /**
- * Static utility method to simply change to a scene defined by the
- * code in the given runnable, which will be executed after
- * the current values have been captured for the transition.
- * This is equivalent to creating a Scene and calling {@link
- * Scene#setEnterAction(Runnable)} with the runnable, then calling
- * {@link #go(Scene, Transition)}. The given transition will be
- * used to animate the changes.
- *
- * <p>Passing in <code>null</code> for the transition parameter will
- * result in the scene changing without any transition running, and is
- * equivalent to calling {@link Scene#exit()} on the scene root's
- * {@link ViewGroup#getCurrentScene() current scene}, followed by
- * {@link Scene#enter()} on a new scene specified by the
- * <code>action</code> parameter.</p>
+ * Convenience method to animate, using the default transition,
+ * to a new scene defined by all changes within the given scene root between
+ * calling this method and the next rendering frame.
+ * Equivalent to calling {@link #beginDelayedTransition(ViewGroup, Transition)}
+ * with a value of <code>null</code> for the <code>transition</code> parameter.
*
* @param sceneRoot The root of the View hierarchy to run the transition on.
- * @param action The runnable whose {@link Runnable#run() run()} method will
- * be called.
- * @param transition The transition to use for this change. A
- * value of null causes the change to happen with no transition.
*/
- public static void go(ViewGroup sceneRoot, Runnable action, Transition transition) {
- Scene scene = new Scene(sceneRoot);
- scene.setEnterAction(action);
- changeScene(scene, transition);
+ public static void beginDelayedTransition(final ViewGroup sceneRoot) {
+ beginDelayedTransition(sceneRoot, null);
}
/**
- * Static utility method to animate to a new scene defined by all changes within
+ * Convenience method to animate to a new scene defined by all changes within
* the given scene root between calling this method and the next rendering frame.
* Calling this method causes TransitionManager to capture current values in the
* scene root and then post a request to run a transition on the next frame.
@@ -367,7 +353,7 @@ public class TransitionManager {
}
final Transition finalTransition = transition.clone();
sceneChangeSetup(sceneRoot, transition);
- sceneRoot.setCurrentScene(null);
+ Scene.setCurrentScene(sceneRoot, null);
sceneChangeRunTransition(sceneRoot, finalTransition);
}
}
diff --git a/core/java/android/view/transition/TransitionGroup.java b/core/java/android/transition/TransitionSet.java
index b3bacde..1972c2a 100644
--- a/core/java/android/view/transition/TransitionGroup.java
+++ b/core/java/android/transition/TransitionSet.java
@@ -14,22 +14,24 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
+import android.animation.TimeInterpolator;
import android.util.AndroidRuntimeException;
+import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
/**
- * A TransitionGroup is a parent of child transitions (including other
- * TransitionGroups). Using TransitionGroups enables more complex
- * choreography of transitions, where some groups play {@link #TOGETHER} and
- * others play {@link #SEQUENTIALLY}. For example, {@link AutoTransition}
- * uses a TransitionGroup to sequentially play a Fade(Fade.OUT), followed by
- * a {@link Move}, followed by a Fade(Fade.OUT) transition.
+ * A TransitionSet is a parent of child transitions (including other
+ * TransitionSets). Using TransitionSets enables more complex
+ * choreography of transitions, where some sets play {@link #ORDERING_TOGETHER} and
+ * others play {@link #ORDERING_SEQUENTIAL}. For example, {@link AutoTransition}
+ * uses a TransitionSet to sequentially play a Fade(Fade.OUT), followed by
+ * a {@link ChangeBounds}, followed by a Fade(Fade.OUT) transition.
*/
-public class TransitionGroup extends Transition {
+public class TransitionSet extends Transition {
ArrayList<Transition> mTransitions = new ArrayList<Transition>();
private boolean mPlayTogether = true;
@@ -37,88 +39,96 @@ public class TransitionGroup extends Transition {
boolean mStarted = false;
/**
- * A flag used to indicate that the child transitions of this group
+ * A flag used to indicate that the child transitions of this set
* should all start at the same time.
*/
- public static final int TOGETHER = 0;
+ public static final int ORDERING_TOGETHER = 0;
/**
- * A flag used to indicate that the child transitions of this group should
+ * A flag used to indicate that the child transitions of this set should
* play in sequence; when one child transition ends, the next child
* transition begins. Note that a transition does not end until all
* instances of it (which are playing on all applicable targets of the
* transition) end.
*/
- public static final int SEQUENTIALLY = 1;
+ public static final int ORDERING_SEQUENTIAL = 1;
/**
- * Constructs an empty transition group. Add child transitions to the
- * group by calling to {@link #addTransitions(Transition...)} )}. By default,
- * child transitions will play {@link #TOGETHER}.
+ * Constructs an empty transition set. Add child transitions to the
+ * set by calling {@link #addTransition(Transition)} )}. By default,
+ * child transitions will play {@link #ORDERING_TOGETHER together}.
*/
- public TransitionGroup() {
+ public TransitionSet() {
}
/**
- * Constructs an empty transition group with the specified ordering.
+ * Sets the play order of this set's child transitions.
*
- * @param ordering {@link #TOGETHER} to start this group's child
- * transitions together, {@link #SEQUENTIALLY} to play the child
- * transitions in sequence.
- * @see #setOrdering(int)
- */
- public TransitionGroup(int ordering) {
- setOrdering(ordering);
- }
-
- /**
- * Sets the play order of this group's child transitions.
- *
- * @param ordering {@link #TOGETHER} to start this group's child
- * transitions together, {@link #SEQUENTIALLY} to play the child
+ * @param ordering {@link #ORDERING_TOGETHER} to play this set's child
+ * transitions together, {@link #ORDERING_SEQUENTIAL} to play the child
* transitions in sequence.
+ * @return This transitionSet object.
*/
- public void setOrdering(int ordering) {
+ public TransitionSet setOrdering(int ordering) {
switch (ordering) {
- case SEQUENTIALLY:
+ case ORDERING_SEQUENTIAL:
mPlayTogether = false;
break;
- case TOGETHER:
+ case ORDERING_TOGETHER:
mPlayTogether = true;
break;
default:
- throw new AndroidRuntimeException("Invalid parameter for TransitionGroup " +
+ throw new AndroidRuntimeException("Invalid parameter for TransitionSet " +
"ordering: " + ordering);
}
+ return this;
}
/**
- * Adds child transitions to this group. The order of the child transitions
- * passed in determines the order in which they are started.
+ * Returns the ordering of this TransitionSet. By default, the value is
+ * {@link #ORDERING_TOGETHER}.
+ *
+ * @return {@link #ORDERING_TOGETHER} if child transitions will play at the same
+ * time, {@link #ORDERING_SEQUENTIAL} if they will play in sequence.
*
- * @param transitions A list of child transition to be added to this group.
+ * @see #setOrdering(int)
*/
- public void addTransitions(Transition... transitions) {
- if (transitions != null) {
- int numTransitions = transitions.length;
- for (int i = 0; i < numTransitions; ++i) {
- mTransitions.add(transitions[i]);
- transitions[i].mParent = this;
- if (mDuration >= 0) {
- transitions[i].setDuration(mDuration);
- }
+ public int getOrdering() {
+ return mPlayTogether ? ORDERING_TOGETHER : ORDERING_SEQUENTIAL;
+ }
+
+ /**
+ * Adds child transition to this set. The order in which this child transition
+ * is added relative to other child transitions that are added, in addition to
+ * the {@link #getOrdering() ordering} property, determines the
+ * order in which the transitions are started.
+ *
+ * <p>If this transitionSet has a {@link #getDuration() duration} set on it, the
+ * child transition will inherit that duration. Transitions are assumed to have
+ * a maximum of one transitionSet parent.</p>
+ *
+ * @param transition A non-null child transition to be added to this set.
+ * @return This transitionSet object.
+ */
+ public TransitionSet addTransition(Transition transition) {
+ if (transition != null) {
+ mTransitions.add(transition);
+ transition.mParent = this;
+ if (mDuration >= 0) {
+ transition.setDuration(mDuration);
}
}
+ return this;
}
/**
- * Setting a non-negative duration on a TransitionGroup causes all of the child
+ * Setting a non-negative duration on a TransitionSet causes all of the child
* transitions (current and future) to inherit this duration.
*
* @param duration The length of the animation, in milliseconds.
- * @return This transitionGroup object.
+ * @return This transitionSet object.
*/
@Override
- public Transition setDuration(long duration) {
+ public TransitionSet setDuration(long duration) {
super.setDuration(duration);
if (mDuration >= 0) {
int numTransitions = mTransitions.size();
@@ -129,23 +139,65 @@ public class TransitionGroup extends Transition {
return this;
}
+ @Override
+ public TransitionSet setStartDelay(long startDelay) {
+ return (TransitionSet) super.setStartDelay(startDelay);
+ }
+
+ @Override
+ public TransitionSet setInterpolator(TimeInterpolator interpolator) {
+ return (TransitionSet) super.setInterpolator(interpolator);
+ }
+
+ @Override
+ public TransitionSet addTarget(View target) {
+ return (TransitionSet) super.addTarget(target);
+ }
+
+ @Override
+ public TransitionSet addTargetId(int targetId) {
+ return (TransitionSet) super.addTargetId(targetId);
+ }
+
+ @Override
+ public TransitionSet addListener(TransitionListener listener) {
+ return (TransitionSet) super.addListener(listener);
+ }
+
+ @Override
+ public TransitionSet removeTargetId(int targetId) {
+ return (TransitionSet) super.removeTargetId(targetId);
+ }
+
+ @Override
+ public TransitionSet removeTarget(View target) {
+ return (TransitionSet) super.removeTarget(target);
+ }
+
+ @Override
+ public TransitionSet removeListener(TransitionListener listener) {
+ return (TransitionSet) super.removeListener(listener);
+ }
+
/**
- * Removes the specified child transition from this group.
+ * Removes the specified child transition from this set.
*
* @param transition The transition to be removed.
+ * @return This transitionSet object.
*/
- public void removeTransition(Transition transition) {
+ public TransitionSet removeTransition(Transition transition) {
mTransitions.remove(transition);
transition.mParent = null;
+ return this;
}
/**
* Sets up listeners for each of the child transitions. This is used to
- * determine when this transition group is finished (all child transitions
+ * determine when this transition set is finished (all child transitions
* must finish first).
*/
private void setupStartEndListeners() {
- TransitionGroupListener listener = new TransitionGroupListener(this);
+ TransitionSetListener listener = new TransitionSetListener(this);
for (Transition childTransition : mTransitions) {
childTransition.addListener(listener);
}
@@ -154,28 +206,28 @@ public class TransitionGroup extends Transition {
/**
* This listener is used to detect when all child transitions are done, at
- * which point this transition group is also done.
+ * which point this transition set is also done.
*/
- static class TransitionGroupListener extends TransitionListenerAdapter {
- TransitionGroup mTransitionGroup;
- TransitionGroupListener(TransitionGroup transitionGroup) {
- mTransitionGroup = transitionGroup;
+ static class TransitionSetListener extends TransitionListenerAdapter {
+ TransitionSet mTransitionSet;
+ TransitionSetListener(TransitionSet transitionSet) {
+ mTransitionSet = transitionSet;
}
@Override
public void onTransitionStart(Transition transition) {
- if (!mTransitionGroup.mStarted) {
- mTransitionGroup.start();
- mTransitionGroup.mStarted = true;
+ if (!mTransitionSet.mStarted) {
+ mTransitionSet.start();
+ mTransitionSet.mStarted = true;
}
}
@Override
public void onTransitionEnd(Transition transition) {
- --mTransitionGroup.mCurrentListeners;
- if (mTransitionGroup.mCurrentListeners == 0) {
+ --mTransitionSet.mCurrentListeners;
+ if (mTransitionSet.mCurrentListeners == 0) {
// All child trans
- mTransitionGroup.mStarted = false;
- mTransitionGroup.end();
+ mTransitionSet.mStarted = false;
+ mTransitionSet.end();
}
transition.removeListener(this);
}
@@ -185,10 +237,10 @@ public class TransitionGroup extends Transition {
* @hide
*/
@Override
- protected void play(ViewGroup sceneRoot, TransitionValuesMaps startValues,
+ protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues,
TransitionValuesMaps endValues) {
for (Transition childTransition : mTransitions) {
- childTransition.play(sceneRoot, startValues, endValues);
+ childTransition.createAnimators(sceneRoot, startValues, endValues);
}
}
@@ -196,7 +248,7 @@ public class TransitionGroup extends Transition {
* @hide
*/
@Override
- protected void runAnimations() {
+ protected void runAnimators() {
setupStartEndListeners();
if (!mPlayTogether) {
// Setup sequence with listeners
@@ -207,28 +259,38 @@ public class TransitionGroup extends Transition {
previousTransition.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
- nextTransition.runAnimations();
+ nextTransition.runAnimators();
transition.removeListener(this);
}
});
}
Transition firstTransition = mTransitions.get(0);
if (firstTransition != null) {
- firstTransition.runAnimations();
+ firstTransition.runAnimators();
}
} else {
for (Transition childTransition : mTransitions) {
- childTransition.runAnimations();
+ childTransition.runAnimators();
}
}
}
@Override
- protected void captureValues(TransitionValues transitionValues, boolean start) {
+ public void captureStartValues(TransitionValues transitionValues) {
int targetId = transitionValues.view.getId();
for (Transition childTransition : mTransitions) {
if (childTransition.isValidTarget(transitionValues.view, targetId)) {
- childTransition.captureValues(transitionValues, start);
+ childTransition.captureStartValues(transitionValues);
+ }
+ }
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ int targetId = transitionValues.view.getId();
+ for (Transition childTransition : mTransitions) {
+ if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ childTransition.captureEndValues(transitionValues);
}
}
}
@@ -253,6 +315,7 @@ public class TransitionGroup extends Transition {
}
}
+ /** @hide */
@Override
protected void cancel() {
super.cancel();
@@ -263,12 +326,13 @@ public class TransitionGroup extends Transition {
}
@Override
- void setSceneRoot(ViewGroup sceneRoot) {
+ TransitionSet setSceneRoot(ViewGroup sceneRoot) {
super.setSceneRoot(sceneRoot);
int numTransitions = mTransitions.size();
for (int i = 0; i < numTransitions; ++i) {
mTransitions.get(i).setSceneRoot(sceneRoot);
}
+ return (TransitionSet) this;
}
@Override
@@ -281,8 +345,8 @@ public class TransitionGroup extends Transition {
}
@Override
- public TransitionGroup clone() {
- TransitionGroup clone = (TransitionGroup) super.clone();
+ public TransitionSet clone() {
+ TransitionSet clone = (TransitionSet) super.clone();
clone.mTransitions = new ArrayList<Transition>();
int numTransitions = mTransitions.size();
for (int i = 0; i < numTransitions; ++i) {
diff --git a/core/java/android/view/transition/TransitionValues.java b/core/java/android/transition/TransitionValues.java
index 6e5d3d3..8989f89 100644
--- a/core/java/android/view/transition/TransitionValues.java
+++ b/core/java/android/transition/TransitionValues.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.util.ArrayMap;
import android.view.View;
@@ -33,11 +33,11 @@ import java.util.Map;
* "Fader" as "android:fader:alpha".
*
* <p>These values are cached during the
- * {@link Transition#captureValues(TransitionValues, boolean)}
+ * {@link Transition#captureStartValues(TransitionValues)}
* capture} phases of a scene change, once when the start values are captured
* and again when the end values are captured. These start/end values are then
* passed into the transitions via the
- * for {@link Transition#play(ViewGroup, TransitionValues, TransitionValues)}
+ * for {@link Transition#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
* method.</p>
*/
public class TransitionValues {
diff --git a/core/java/android/view/transition/TransitionValuesMaps.java b/core/java/android/transition/TransitionValuesMaps.java
index 4cfce4d..131596b 100644
--- a/core/java/android/view/transition/TransitionValuesMaps.java
+++ b/core/java/android/transition/TransitionValuesMaps.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.util.ArrayMap;
import android.util.LongSparseArray;
diff --git a/core/java/android/view/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 348dcfb..75d3e7c 100644
--- a/core/java/android/view/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-package android.view.transition;
+package android.transition;
import android.animation.Animator;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewOverlay;
-import android.view.ViewParent;
/**
* This transition tracks changes to the visibility of target views in the
@@ -30,13 +28,13 @@ import android.view.ViewParent;
* utility for subclasses such as {@link Fade}, which use this visibility
* information to determine the specific animations to run when visibility
* changes occur. Subclasses should implement one or both of the methods
- * {@link #appear(ViewGroup, TransitionValues, int, TransitionValues, int), and
- * {@link #disappear(ViewGroup, TransitionValues, int, TransitionValues, int)}.
+ * {@link #onAppear(ViewGroup, TransitionValues, int, TransitionValues, int)},
+ * {@link #onDisappear(ViewGroup, TransitionValues, int, TransitionValues, int)},
*
* <p>Note that a view's visibility change is determined by both whether the view
* itself is changing and whether its parent hierarchy's visibility is changing.
* That is, a view that appears in the end scene will only trigger a call to
- * {@link #appear(android.view.ViewGroup, TransitionValues, int, TransitionValues, int)
+ * {@link #onAppear(android.view.ViewGroup, TransitionValues, int, TransitionValues, int)
* appear()} if its parent hierarchy was stable between the start and end scenes.
* This is done to avoid causing a visibility transition on every node in a hierarchy
* when only the top-most node is the one that should be transitioned in/out.
@@ -75,11 +73,20 @@ public abstract class Visibility extends Transition {
return sTransitionProperties;
}
+ private void captureValues(TransitionValues transitionValues) {
+ int visibility = transitionValues.view.getVisibility();
+ transitionValues.values.put(PROPNAME_VISIBILITY, visibility);
+ transitionValues.values.put(PROPNAME_PARENT, transitionValues.view.getParent());
+ }
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
+ }
+
@Override
- protected void captureValues(TransitionValues values, boolean start) {
- int visibility = values.view.getVisibility();
- values.values.put(PROPNAME_VISIBILITY, visibility);
- values.values.put(PROPNAME_PARENT, values.view.getParent());
+ public void captureEndValues(TransitionValues transitionValues) {
+ captureValues(transitionValues);
}
/**
@@ -87,7 +94,7 @@ public abstract class Visibility extends Transition {
* object. This is determined by testing the same properties in the values
* object that are used to determine whether the object is appearing or
* disappearing in the {@link
- * #play(android.view.ViewGroup, TransitionValues, TransitionValues)}
+ * Transition#createAnimator(ViewGroup, TransitionValues, TransitionValues)}
* method. This method can be called by, for example, subclasses that want
* to know whether the object is visible in the same way that Visibility
* determines it for the actual animation.
@@ -207,14 +214,14 @@ public abstract class Visibility extends Transition {
}
@Override
- protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
TransitionValues endValues) {
VisibilityInfo visInfo = getVisibilityChangeInfo(startValues, endValues);
if (visInfo.visibilityChange) {
// Only transition views that are either targets of this transition
// or whose parent hierarchies remain stable between scenes
boolean isTarget = false;
- if (mTargets != null || mTargetIds != null) {
+ if (mTargets.size() > 0 || mTargetIds.size() > 0) {
View startView = startValues != null ? startValues.view : null;
View endView = endValues != null ? endValues.view : null;
int startId = startView != null ? startView.getId() : -1;
@@ -225,10 +232,10 @@ public abstract class Visibility extends Transition {
!isHierarchyVisibilityChanging(sceneRoot,
visInfo.startParent, visInfo.endParent))) {
if (visInfo.fadeIn) {
- return appear(sceneRoot, startValues, visInfo.startVisibility,
+ return onAppear(sceneRoot, startValues, visInfo.startVisibility,
endValues, visInfo.endVisibility);
} else {
- return disappear(sceneRoot, startValues, visInfo.startVisibility,
+ return onDisappear(sceneRoot, startValues, visInfo.startVisibility,
endValues, visInfo.endVisibility
);
}
@@ -239,17 +246,20 @@ public abstract class Visibility extends Transition {
/**
* The default implementation of this method does nothing. Subclasses
- * should override if they need to set up anything prior to the
- * transition starting.
+ * should override if they need to create an Animator when targets appear.
+ * The method should only be called by the Visibility class; it is
+ * not intended to be called from external classes.
*
- * @param sceneRoot
- * @param startValues
- * @param startVisibility
- * @param endValues
- * @param endVisibility
- * @return
+ * @param sceneRoot The root of the transition hierarchy
+ * @param startValues The target values in the start scene
+ * @param startVisibility The target visibility in the start scene
+ * @param endValues The target values in the end scene
+ * @param endVisibility The target visibility in the end scene
+ * @return An Animator to be started at the appropriate time in the
+ * overall transition for this scene change. A null value means no animation
+ * should be run.
*/
- protected Animator appear(ViewGroup sceneRoot,
+ public Animator onAppear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
return null;
@@ -257,17 +267,21 @@ public abstract class Visibility extends Transition {
/**
* The default implementation of this method does nothing. Subclasses
- * should override if they need to set up anything prior to the
- * transition starting.
+ * should override if they need to create an Animator when targets disappear.
+ * The method should only be called by the Visibility class; it is
+ * not intended to be called from external classes.
+ *
*
- * @param sceneRoot
- * @param startValues
- * @param startVisibility
- * @param endValues
- * @param endVisibility
- * @return
+ * @param sceneRoot The root of the transition hierarchy
+ * @param startValues The target values in the start scene
+ * @param startVisibility The target visibility in the start scene
+ * @param endValues The target values in the end scene
+ * @param endVisibility The target visibility in the end scene
+ * @return An Animator to be started at the appropriate time in the
+ * overall transition for this scene change. A null value means no animation
+ * should be run.
*/
- protected Animator disappear(ViewGroup sceneRoot,
+ public Animator onDisappear(ViewGroup sceneRoot,
TransitionValues startValues, int startVisibility,
TransitionValues endValues, int endVisibility) {
return null;
diff --git a/core/java/android/view/transition/package.html b/core/java/android/transition/package.html
index 37dc0ec..f357d34 100644
--- a/core/java/android/view/transition/package.html
+++ b/core/java/android/transition/package.html
@@ -3,15 +3,15 @@
<p>The classes in this package enable "scenes & transitions" functionality for
view hiearchies.</p>
-<p>A <b>Scene</b> is an encapsulation of the state of a view hiearchy,
+<p>A <b>Scene</b> is an encapsulation of the state of a view hierarchy,
including the views in that hierarchy and the various values (layout-related
-and otherwise) that those views have. A scene be defined by a layout hierarchy
-directly or some code which sets up the scene dynamically as it is entered.</p>
+and otherwise) that those views have. A scene can be defined by a layout hierarchy
+directly or by code which sets up the scene dynamically as it is entered.</p>
<p>A <b>Transition</b> is a mechanism to automatically animate changes that occur
when a new scene is entered. Some transition capabilities are automatic. That
is, entering a scene may cause animations to run which fade out views that
-go away, move and resize existing views that change, and fade in views that
+go away, changeBounds and resize existing views that change, and fade in views that
become visible. There are additional transitions that can animate other
attributes, such as color changes, and which can optionally be specified
to take place during particular scene changes. Finally, developers can
@@ -19,7 +19,8 @@ define their own Transition subclasses which monitor particular property
changes and which run custom animations when those properties change values.</p>
<p><b>TransitionManager</b> is used to specify custom transitions for particular
-scene changes, and to cause scene changes with transitions to take place.</p>
+scene changes, and to cause scene changes with specific transitions to
+take place.</p>
</body>
</html>
diff --git a/core/java/android/util/MapCollections.java b/core/java/android/util/MapCollections.java
index 09f1f8e..f4a9b0b 100644
--- a/core/java/android/util/MapCollections.java
+++ b/core/java/android/util/MapCollections.java
@@ -328,12 +328,12 @@ abstract class MapCollections<K, V> {
@Override
public Object[] toArray() {
- return toArrayHelper(1);
+ return toArrayHelper(0);
}
@Override
public <T> T[] toArray(T[] array) {
- return toArrayHelper(array, 1);
+ return toArrayHelper(array, 0);
}
@Override
diff --git a/core/java/android/util/SuperNotCalledException.java b/core/java/android/util/SuperNotCalledException.java
new file mode 100644
index 0000000..1836142
--- /dev/null
+++ b/core/java/android/util/SuperNotCalledException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2013 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.util;
+
+/**
+ * @hide
+ */
+public final class SuperNotCalledException extends AndroidRuntimeException {
+ public SuperNotCalledException(String msg) {
+ super(msg);
+ }
+}
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 28c1058..2351548 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -17,7 +17,6 @@
package android.view;
import android.content.Context;
-import android.os.Build;
import android.os.Handler;
import android.os.Message;
@@ -202,6 +201,7 @@ public class GestureDetector {
private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
+ private static final int DOUBLE_TAP_MIN_TIME = ViewConfiguration.getDoubleTapMinTime();
// constants for Message.what used by GestureHandler below
private static final int SHOW_PRESS = 1;
@@ -323,7 +323,7 @@ public class GestureDetector {
/**
* Creates a GestureDetector with the supplied listener.
- * You may only use this constructor from a UI thread (this is the usual situation).
+ * You may only use this constructor from a {@link android.os.Looper} thread.
* @see android.os.Handler#Handler()
*
* @param context the application's context
@@ -337,14 +337,14 @@ public class GestureDetector {
}
/**
- * Creates a GestureDetector with the supplied listener.
- * You may only use this constructor from a UI thread (this is the usual situation).
+ * Creates a GestureDetector with the supplied listener that runs deferred events on the
+ * thread associated with the supplied {@link android.os.Handler}.
* @see android.os.Handler#Handler()
*
* @param context the application's context
* @param listener the listener invoked for all the callbacks, this must
* not be null.
- * @param handler the handler to use
+ * @param handler the handler to use for running deferred listener events.
*
* @throws NullPointerException if {@code listener} is null.
*/
@@ -362,14 +362,15 @@ public class GestureDetector {
}
/**
- * Creates a GestureDetector with the supplied listener.
- * You may only use this constructor from a UI thread (this is the usual situation).
+ * Creates a GestureDetector with the supplied listener that runs deferred events on the
+ * thread associated with the supplied {@link android.os.Handler}.
* @see android.os.Handler#Handler()
*
* @param context the application's context
* @param listener the listener invoked for all the callbacks, this must
* not be null.
- * @param handler the handler to use
+ * @param handler the handler to use for running deferred listener events.
+ * @param unused currently not used.
*
* @throws NullPointerException if {@code listener} is null.
*/
@@ -672,7 +673,8 @@ public class GestureDetector {
return false;
}
- if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) {
+ final long deltaTime = secondDown.getEventTime() - firstUp.getEventTime();
+ if (deltaTime > DOUBLE_TAP_TIMEOUT || deltaTime < DOUBLE_TAP_MIN_TIME) {
return false;
}
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index afc7b3e..e829116 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -424,12 +424,17 @@ public final class InputDevice implements Parcelable {
/**
* The controller number for a given input device.
* <p>
- * Each game controller or joystick is given a unique controller number when initially
- * configured by the system. The number is not stable and may be changed by the system at any
- * point. All controller numbers will be non-negative. A game controller or joystick will be
- * given a unique number indexed from one; everything else will be assigned a controller number
+ * Each gamepad or joystick is given a unique, positive controller number when initially
+ * configured by the system. This number may change due to events such as device disconnects /
+ * reconnects or user initiated reassignment. Any change in number will trigger an event that
+ * can be observed by registering an {@link InputManager.InputDeviceListener}.
+ * </p>
+ * <p>
+ * All input devices which are not gamepads or joysticks will be assigned a controller number
* of 0.
* </p>
+ *
+ * @return The controller number of the device.
*/
public int getControllerNumber() {
return mControllerNumber;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 907290b..30531ed 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -57,6 +57,7 @@ import android.util.LongSparseLongArray;
import android.util.Pools.SynchronizedPool;
import android.util.Property;
import android.util.SparseArray;
+import android.util.SuperNotCalledException;
import android.util.TypedValue;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -74,7 +75,6 @@ import android.view.animation.Transformation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
-import android.view.transition.Scene;
import android.widget.ScrollBarDrawable;
import static android.os.Build.VERSION_CODES.*;
@@ -1575,8 +1575,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
protected Object mTag;
- private Scene mCurrentScene = null;
-
// for mPrivateFlags:
/** {@hide} */
static final int PFLAG_WANTS_FOCUS = 0x00000001;
@@ -2207,6 +2205,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8;
+ /**
+ * Flag indicating that an overridden method correctly called down to
+ * the superclass implementation as required by the API spec.
+ */
+ static final int PFLAG3_CALLED_SUPER = 0x10;
+
/* End of masks for mPrivateFlags3 */
@@ -5958,6 +5962,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Invalidate too, since the default behavior for views is to be
// be drawn at 50% alpha rather than to change the drawable.
invalidate(true);
+
+ if (!enabled) {
+ cancelPendingInputEvents();
+ }
}
/**
@@ -8836,9 +8844,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Change the view's z order in the tree, so it's on top of other sibling
* views. This ordering change may affect layout, if the parent container
- * uses an order-dependent layout scheme (e.g., LinearLayout). This
+ * uses an order-dependent layout scheme (e.g., LinearLayout). Prior
+ * to {@link android.os.Build.VERSION_CODES#KITKAT} this
* method should be followed by calls to {@link #requestLayout()} and
- * {@link View#invalidate()} on the parent.
+ * {@link View#invalidate()} on the view's parent to force the parent to redraw
+ * with the new child ordering.
*
* @see ViewGroup#bringChildToFront(View)
*/
@@ -9536,9 +9546,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setPivotX(float pivotX) {
ensureTransformationInfo();
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
final TransformationInfo info = mTransformationInfo;
- if (info.mPivotX != pivotX) {
+ boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
+ PFLAG_PIVOT_EXPLICITLY_SET;
+ if (info.mPivotX != pivotX || !pivotSet) {
+ mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
invalidateViewProperty(true, false);
info.mPivotX = pivotX;
info.mMatrixDirty = true;
@@ -9586,9 +9598,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
public void setPivotY(float pivotY) {
ensureTransformationInfo();
- mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
final TransformationInfo info = mTransformationInfo;
- if (info.mPivotY != pivotY) {
+ boolean pivotSet = (mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) ==
+ PFLAG_PIVOT_EXPLICITLY_SET;
+ if (info.mPivotY != pivotY || !pivotSet) {
+ mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
invalidateViewProperty(true, false);
info.mPivotY = pivotY;
info.mMatrixDirty = true;
@@ -12187,7 +12201,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
cleanupDraw();
mCurrentAnimation = null;
- mCurrentScene = null;
}
private void cleanupDraw() {
@@ -12366,6 +12379,61 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Cancel any deferred high-level input events that were previously posted to the event queue.
+ *
+ * <p>Many views post high-level events such as click handlers to the event queue
+ * to run deferred in order to preserve a desired user experience - clearing visible
+ * pressed states before executing, etc. This method will abort any events of this nature
+ * that are currently in flight.</p>
+ *
+ * <p>Custom views that generate their own high-level deferred input events should override
+ * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p>
+ *
+ * <p>This will also cancel pending input events for any child views.</p>
+ *
+ * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases.
+ * This will not impact newer events posted after this call that may occur as a result of
+ * lower-level input events still waiting in the queue. If you are trying to prevent
+ * double-submitted events for the duration of some sort of asynchronous transaction
+ * you should also take other steps to protect against unexpected double inputs e.g. calling
+ * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when
+ * the transaction completes, tracking already submitted transaction IDs, etc.</p>
+ */
+ public final void cancelPendingInputEvents() {
+ dispatchCancelPendingInputEvents();
+ }
+
+ /**
+ * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight.
+ * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling.
+ */
+ void dispatchCancelPendingInputEvents() {
+ mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER;
+ onCancelPendingInputEvents();
+ if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) {
+ throw new SuperNotCalledException("View " + getClass().getSimpleName() +
+ " did not call through to super.onCancelPendingInputEvents()");
+ }
+ }
+
+ /**
+ * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or
+ * a parent view.
+ *
+ * <p>This method is responsible for removing any pending high-level input events that were
+ * posted to the event queue to run later. Custom view classes that post their own deferred
+ * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or
+ * {@link android.os.Handler} should override this method, call
+ * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate.
+ * </p>
+ */
+ public void onCancelPendingInputEvents() {
+ removePerformClickCallback();
+ cancelLongPress();
+ mPrivateFlags3 |= PFLAG3_CALLED_SUPER;
+ }
+
+ /**
* Store this view hierarchy's frozen state into the given container.
*
* @param container The SparseArray in which to save the view's state.
@@ -13412,6 +13480,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
dispatchDraw(canvas);
+ if (mOverlay != null && !mOverlay.isEmpty()) {
+ mOverlay.getOverlayView().draw(canvas);
+ }
} else {
draw(canvas);
}
@@ -18100,31 +18171,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * Set the current Scene that this view is in. The current scene is set only
- * on the root view of a scene, not for every view in that hierarchy. This
- * information is used by Scene to determine whether there is a previous
- * scene which should be exited before the new scene is entered.
- *
- * @param scene The new scene being set on the view
- *
- * @hide
- */
- public void setCurrentScene(Scene scene) {
- mCurrentScene = scene;
- }
-
- /**
- * Gets the current {@link Scene} set on this view. A scene is set on a view
- * only if that view is the scene root.
- *
- * @return The current Scene set on this view. A value of null indicates that
- * no Scene is current set.
- */
- public Scene getCurrentScene() {
- return mCurrentScene;
- }
-
- /**
* Interface definition for a callback to be invoked when a hardware key event is
* dispatched to this view. The callback will be invoked before the key event is
* given to the view. This is only useful for hardware keyboards; a software input
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index f8cb9c0..c3f064f 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -97,6 +97,13 @@ public class ViewConfiguration {
private static final int DOUBLE_TAP_TIMEOUT = 300;
/**
+ * Defines the minimum duration in milliseconds between the first tap's up event and
+ * the second tap's down event for an interaction to be considered a
+ * double-tap.
+ */
+ private static final int DOUBLE_TAP_MIN_TIME = 40;
+
+ /**
* Defines the maximum duration in milliseconds between a touch pad
* touch and release for a given touch to be considered a tap (click) as
* opposed to a hover movement gesture.
@@ -436,6 +443,17 @@ public class ViewConfiguration {
}
/**
+ * @return the minimum duration in milliseconds between the first tap's
+ * up event and the second tap's down event for an interaction to be considered a
+ * double-tap.
+ *
+ * @hide
+ */
+ public static int getDoubleTapMinTime() {
+ return DOUBLE_TAP_MIN_TIME;
+ }
+
+ /**
* @return the maximum duration in milliseconds between a touch pad
* touch and release for a given touch to be considered a tap (click) as
* opposed to a hover movement gesture.
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index ed128b0..92e5e96 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -698,6 +698,11 @@ public class ViewDebug {
captureViewLayer(group.getChildAt(i), clientStream, localVisible);
}
}
+
+ if (view.mOverlay != null) {
+ ViewGroup overlayContainer = view.getOverlay().mOverlayViewGroup;
+ captureViewLayer(overlayContainer, clientStream, localVisible);
+ }
}
private static void outputDisplayList(View root, String parameter) throws IOException {
@@ -743,7 +748,7 @@ public class ViewDebug {
}
}
- private static Bitmap performViewCapture(final View captureView, final boolean skpiChildren) {
+ private static Bitmap performViewCapture(final View captureView, final boolean skipChildren) {
if (captureView != null) {
final CountDownLatch latch = new CountDownLatch(1);
final Bitmap[] cache = new Bitmap[1];
@@ -752,7 +757,7 @@ public class ViewDebug {
public void run() {
try {
cache[0] = captureView.createSnapshot(
- Bitmap.Config.ARGB_8888, 0, skpiChildren);
+ Bitmap.Config.ARGB_8888, 0, skipChildren);
} catch (OutOfMemoryError e) {
Log.w("View", "Out of memory for bitmap");
} finally {
@@ -815,6 +820,13 @@ public class ViewDebug {
} else if (isRequestedView(view, className, hashCode)) {
return view;
}
+ if (view.mOverlay != null) {
+ final View found = findView((ViewGroup) view.mOverlay.mOverlayViewGroup,
+ className, hashCode);
+ if (found != null) {
+ return found;
+ }
+ }
if (view instanceof HierarchyHandler) {
final View found = ((HierarchyHandler)view)
.findHierarchyView(className, hashCode);
@@ -823,12 +835,19 @@ public class ViewDebug {
}
}
}
-
return null;
}
private static boolean isRequestedView(View view, String className, int hashCode) {
- return view.getClass().getName().equals(className) && view.hashCode() == hashCode;
+ if (view.hashCode() == hashCode) {
+ String viewClassName = view.getClass().getName();
+ if (className.equals("ViewOverlay")) {
+ return viewClassName.equals("android.view.ViewOverlay$OverlayViewGroup");
+ } else {
+ return className.equals(viewClassName);
+ }
+ }
+ return false;
}
private static void dumpViewHierarchy(Context context, ViewGroup group,
@@ -850,6 +869,12 @@ public class ViewDebug {
} else {
dumpView(context, view, out, level + 1, includeProperties);
}
+ if (view.mOverlay != null) {
+ ViewOverlay overlay = view.getOverlay();
+ ViewGroup overlayContainer = overlay.mOverlayViewGroup;
+ dumpViewHierarchy(context, overlayContainer, out, level + 2, skipChildren,
+ includeProperties);
+ }
}
if (group instanceof HierarchyHandler) {
((HierarchyHandler)group).dumpViewHierarchyWithProperties(out, level + 1);
@@ -863,7 +888,11 @@ public class ViewDebug {
for (int i = 0; i < level; i++) {
out.write(' ');
}
- out.write(view.getClass().getName());
+ String className = view.getClass().getName();
+ if (className.equals("android.view.ViewOverlay$OverlayViewGroup")) {
+ className = "ViewOverlay";
+ }
+ out.write(className);
out.write('@');
out.write(Integer.toHexString(view.hashCode()));
out.write(' ');
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 03a9c37..faeee3f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1123,6 +1123,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
removeFromArray(index);
addInArray(child, mChildrenCount);
child.mParent = this;
+ requestLayout();
+ invalidate();
}
}
@@ -3180,6 +3182,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
+ @Override
+ void dispatchCancelPendingInputEvents() {
+ super.dispatchCancelPendingInputEvents();
+
+ final View[] children = mChildren;
+ final int count = mChildrenCount;
+ for (int i = 0; i < count; i++) {
+ children[i].dispatchCancelPendingInputEvents();
+ }
+ }
+
/**
* When this property is set to true, this ViewGroup supports static transformations on
* children; this causes
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 26596d9..35113db 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -148,9 +148,11 @@ public interface ViewParent {
/**
* Change the z order of the child so it's on top of all other children.
* This ordering change may affect layout, if this container
- * uses an order-dependent layout scheme (e.g., LinearLayout). This
+ * uses an order-dependent layout scheme (e.g., LinearLayout). Prior
+ * to {@link android.os.Build.VERSION_CODES#KITKAT} this
* method should be followed by calls to {@link #requestLayout()} and
- * {@link View#invalidate()} on this parent.
+ * {@link View#invalidate()} on this parent to force the parent to redraw
+ * with the new child ordering.
*
* @param child The child to bring to the top of the z order
*/
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index e6bf420..cea7e49 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -93,11 +93,16 @@ public class ViewPropertyAnimator {
private boolean mInterpolatorSet = false;
/**
- * Listener for the lifecycle events of the underlying
+ * Listener for the lifecycle events of the underlying ValueAnimator object.
*/
private Animator.AnimatorListener mListener = null;
/**
+ * Listener for the update events of the underlying ValueAnimator object.
+ */
+ private ValueAnimator.AnimatorUpdateListener mUpdateListener = null;
+
+ /**
* A lazily-created ValueAnimator used in order to get some default animator properties
* (duration, start delay, interpolator, etc.).
*/
@@ -353,7 +358,10 @@ public class ViewPropertyAnimator {
* Sets a listener for events in the underlying Animators that run the property
* animations.
*
- * @param listener The listener to be called with AnimatorListener events.
+ * @see Animator.AnimatorListener
+ *
+ * @param listener The listener to be called with AnimatorListener events. A value of
+ * <code>null</code> removes any existing listener.
* @return This object, allowing calls to methods in this class to be chained.
*/
public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
@@ -362,6 +370,25 @@ public class ViewPropertyAnimator {
}
/**
+ * Sets a listener for update events in the underlying ValueAnimator that runs
+ * the property animations. Note that the underlying animator is animating between
+ * 0 and 1 (these values are then turned into the actual property values internally
+ * by ViewPropertyAnimator). So the animator cannot give information on the current
+ * values of the properties being animated by this ViewPropertyAnimator, although
+ * the view object itself can be queried to get the current values.
+ *
+ * @see android.animation.ValueAnimator.AnimatorUpdateListener
+ *
+ * @param listener The listener to be called with update events. A value of
+ * <code>null</code> removes any existing listener.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
+ mUpdateListener = listener;
+ return this;
+ }
+
+ /**
* Starts the currently pending property animations immediately. Calling <code>start()</code>
* is optional because all animations start automatically at the next opportunity. However,
* if the animations are needed to start immediately and synchronously (not at the time when
@@ -1073,6 +1100,9 @@ public class ViewPropertyAnimator {
} else {
mView.invalidateViewProperty(false, false);
}
+ if (mUpdateListener != null) {
+ mUpdateListener.onAnimationUpdate(animation);
+ }
}
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 354e815..c7d61eb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -81,6 +81,7 @@ import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Locale;
/**
* The top of a view hierarchy, implementing the needed protocol between View
@@ -228,7 +229,8 @@ public final class ViewRootImpl implements ViewParent,
InputStage mFirstInputStage;
InputStage mFirstPostImeInputStage;
- SyntheticInputStage mSyntheticInputStage;
+
+ boolean mFlipControllerFallbackKeys;
boolean mWindowAttributesChanged = false;
int mWindowAttributesChangesFlag = 0;
@@ -366,6 +368,8 @@ public final class ViewRootImpl implements ViewParent,
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
+ mFlipControllerFallbackKeys =
+ context.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mAttachInfo.mScreenOn = powerManager.isScreenOn();
@@ -590,8 +594,8 @@ public final class ViewRootImpl implements ViewParent,
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
- mSyntheticInputStage = new SyntheticInputStage();
- InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
+ InputStage syntheticInputStage = new SyntheticInputStage();
+ InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
@@ -1449,7 +1453,7 @@ public final class ViewRootImpl implements ViewParent,
}
DisplayList displayList = mView.mDisplayList;
- if (displayList != null) {
+ if (displayList != null && displayList.isValid()) {
layerCanvas.drawDisplayList(displayList, null,
DisplayList.FLAG_CLIP_CHILDREN);
} else {
@@ -2873,8 +2877,11 @@ public final class ViewRootImpl implements ViewParent,
mView.dispatchConfigurationChanged(config);
}
}
+
+ mFlipControllerFallbackKeys =
+ mContext.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
}
-
+
/**
* Return true if child is an ancestor of parent, (or equal to the parent).
*/
@@ -3774,9 +3781,6 @@ public final class ViewRootImpl implements ViewParent,
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
- // The synthetic stage occasionally needs to know about keys in order to debounce taps
- mSyntheticInputStage.notifyKeyEvent(event);
-
// Deliver the key to the view hierarchy.
if (mView.dispatchKeyEvent(event)) {
return FINISH_HANDLED;
@@ -3904,6 +3908,7 @@ public final class ViewRootImpl implements ViewParent,
private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
private final SyntheticTouchNavigationHandler mTouchNavigation =
new SyntheticTouchNavigationHandler();
+ private final SyntheticKeyHandler mKeys = new SyntheticKeyHandler();
public SyntheticInputStage() {
super(null);
@@ -3926,7 +3931,12 @@ public final class ViewRootImpl implements ViewParent,
mTouchNavigation.process(event);
return FINISH_HANDLED;
}
+ } else if (q.mEvent instanceof KeyEvent) {
+ if (mKeys.process((KeyEvent) q.mEvent)) {
+ return FINISH_HANDLED;
+ }
}
+
return FORWARD;
}
@@ -3949,10 +3959,6 @@ public final class ViewRootImpl implements ViewParent,
}
super.onDeliverToNext(q);
}
-
- public void notifyKeyEvent(KeyEvent e) {
- mTouchNavigation.notifyKeyEvent(e);
- }
}
/**
@@ -4380,15 +4386,6 @@ public final class ViewRootImpl implements ViewParent,
/* TODO: These constants should eventually be moved to ViewConfiguration. */
- // Tap timeout in milliseconds.
- private static final int TAP_TIMEOUT = 250;
-
- // Debounce timeout for touch nav devices with a button under their pad, in milliseconds
- private static final int DEBOUNCE_TIME = 250;
-
- // The maximum distance traveled for a gesture to be considered a tap in millimeters.
- private static final int TAP_SLOP_MILLIMETERS = 5;
-
// The nominal distance traveled to move by one unit.
private static final int TICK_DISTANCE_MILLIMETERS = 12;
@@ -4416,13 +4413,6 @@ public final class ViewRootImpl implements ViewParent,
/* Configuration for the current input device. */
- // The tap timeout and scaled slop.
- private int mConfigTapTimeout;
- private float mConfigTapSlop;
-
- // Amount of time to wait between button presses and tap generation for debouncing
- private int mConfigDebounceTime;
-
// The scaled tick distance. A movement of this amount should generally translate
// into a single dpad event in a given direction.
private float mConfigTickDistance;
@@ -4471,8 +4461,6 @@ public final class ViewRootImpl implements ViewParent,
// The last time a confirm key was pressed on the touch nav device
private long mLastConfirmKeyTime = Long.MAX_VALUE;
- private boolean mHasButtonUnderPad;
-
public SyntheticTouchNavigationHandler() {
super(true);
}
@@ -4509,21 +4497,15 @@ public final class ViewRootImpl implements ViewParent,
float nominalRes = (xRes + yRes) * 0.5f;
// Precompute all of the configuration thresholds we will need.
- mConfigTapTimeout = TAP_TIMEOUT;
- mConfigTapSlop = TAP_SLOP_MILLIMETERS * nominalRes;
mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
mConfigMinFlingVelocity =
MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
mConfigMaxFlingVelocity =
MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
- mConfigDebounceTime = DEBOUNCE_TIME;
- mHasButtonUnderPad = device.hasButtonUnderPad();
if (LOCAL_DEBUG) {
Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
+ " (" + Integer.toHexString(mCurrentSource) + "): "
- + "mConfigTapTimeout=" + mConfigTapTimeout
- + ", mConfigTapSlop=" + mConfigTapSlop
+ ", mConfigTickDistance=" + mConfigTickDistance
+ ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
+ ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
@@ -4585,18 +4567,7 @@ public final class ViewRootImpl implements ViewParent,
// Detect taps and flings.
if (action == MotionEvent.ACTION_UP) {
- if (!mConsumedMovement
- && Math.hypot(mLastX - mStartX, mLastY - mStartY) < mConfigTapSlop
- && time <= mStartTime + mConfigTapTimeout) {
- if (!mHasButtonUnderPad ||
- time >= mLastConfirmKeyTime + mConfigDebounceTime) {
- // It's a tap!
- finishKeys(time);
- sendKeyDownOrRepeat(time, KeyEvent.KEYCODE_DPAD_CENTER, metaState);
- sendKeyUp(time);
- }
- } else if (mConsumedMovement
- && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
+ if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
// It might be a fling.
mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
@@ -4627,13 +4598,6 @@ public final class ViewRootImpl implements ViewParent,
}
}
- public void notifyKeyEvent(KeyEvent e) {
- final int keyCode = e.getKeyCode();
- if (KeyEvent.isConfirmKey(e.getKeyCode())) {
- mLastConfirmKeyTime = e.getDownTime();
- }
- }
-
private void finishKeys(long time) {
cancelFling();
sendKeyUp(time);
@@ -4802,6 +4766,63 @@ public final class ViewRootImpl implements ViewParent,
};
}
+ final class SyntheticKeyHandler {
+
+ public boolean process(KeyEvent event) {
+ // In some locales (like Japan) controllers use B for confirm and A for back, rather
+ // than vice versa, so we need to special case this here since the input system itself
+ // is not locale-aware.
+ int keyCode;
+ switch(event.getKeyCode()) {
+ case KeyEvent.KEYCODE_BUTTON_A:
+ case KeyEvent.KEYCODE_BUTTON_C:
+ case KeyEvent.KEYCODE_BUTTON_X:
+ case KeyEvent.KEYCODE_BUTTON_Z:
+ keyCode = mFlipControllerFallbackKeys ?
+ KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_DPAD_CENTER;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_B:
+ case KeyEvent.KEYCODE_BUTTON_Y:
+ keyCode = mFlipControllerFallbackKeys ?
+ KeyEvent.KEYCODE_DPAD_CENTER : KeyEvent.KEYCODE_BACK;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_THUMBL:
+ case KeyEvent.KEYCODE_BUTTON_THUMBR:
+ case KeyEvent.KEYCODE_BUTTON_START:
+ case KeyEvent.KEYCODE_BUTTON_1:
+ case KeyEvent.KEYCODE_BUTTON_2:
+ case KeyEvent.KEYCODE_BUTTON_3:
+ case KeyEvent.KEYCODE_BUTTON_4:
+ case KeyEvent.KEYCODE_BUTTON_5:
+ case KeyEvent.KEYCODE_BUTTON_6:
+ case KeyEvent.KEYCODE_BUTTON_7:
+ case KeyEvent.KEYCODE_BUTTON_8:
+ case KeyEvent.KEYCODE_BUTTON_9:
+ case KeyEvent.KEYCODE_BUTTON_10:
+ case KeyEvent.KEYCODE_BUTTON_11:
+ case KeyEvent.KEYCODE_BUTTON_12:
+ case KeyEvent.KEYCODE_BUTTON_13:
+ case KeyEvent.KEYCODE_BUTTON_14:
+ case KeyEvent.KEYCODE_BUTTON_15:
+ case KeyEvent.KEYCODE_BUTTON_16:
+ keyCode = KeyEvent.KEYCODE_DPAD_CENTER;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_SELECT:
+ case KeyEvent.KEYCODE_BUTTON_MODE:
+ keyCode = KeyEvent.KEYCODE_MENU;
+ default:
+ return false;
+ }
+
+ enqueueInputEvent(new KeyEvent(event.getDownTime(), event.getEventTime(),
+ event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(),
+ event.getScanCode(), event.getFlags() | KeyEvent.FLAG_FALLBACK,
+ event.getSource()));
+ return true;
+ }
+
+ }
+
/**
* Returns true if the key is used for keyboard navigation.
* @param keyEvent The key event.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index ba63421..c61516b 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -2279,9 +2279,12 @@ public class AccessibilityNodeInfo implements Parcelable {
if (other.mExtras != null && !other.mExtras.isEmpty()) {
getExtras().putAll(other.mExtras);
}
- mRangeInfo = other.mRangeInfo;
- mCollectionInfo = other.mCollectionInfo;
- mCollectionItemInfo = other.mCollectionItemInfo;
+ mRangeInfo = (other.mRangeInfo != null)
+ ? RangeInfo.obtain(other.mRangeInfo) : null;
+ mCollectionInfo = (other.mCollectionInfo != null)
+ ? CollectionInfo.obtain(other.mCollectionInfo) : null;
+ mCollectionItemInfo = (other.mCollectionItemInfo != null)
+ ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
}
/**
@@ -2602,6 +2605,17 @@ public class AccessibilityNodeInfo implements Parcelable {
private float mCurrent;
/**
+ * Obtains a pooled instance that is a clone of another one.
+ *
+ * @param other The instance to clone.
+ *
+ * @hide
+ */
+ public static RangeInfo obtain(RangeInfo other) {
+ return obtain(other.mType, other.mMin, other.mMax, other.mCurrent);
+ }
+
+ /**
* Obtains a pooled instance.
*
* @param type The type of the range.
@@ -2708,6 +2722,18 @@ public class AccessibilityNodeInfo implements Parcelable {
private boolean mHierarchical;
/**
+ * Obtains a pooled instance that is a clone of another one.
+ *
+ * @param other The instance to clone.
+ *
+ * @hide
+ */
+ public static CollectionInfo obtain(CollectionInfo other) {
+ return CollectionInfo.obtain(other.mRowCount, other.mColumnCount,
+ other.mHierarchical);
+ }
+
+ /**
* Obtains a pooled instance.
*
* @param rowCount The number of rows.
@@ -2796,6 +2822,18 @@ public class AccessibilityNodeInfo implements Parcelable {
new SynchronizedPool<CollectionItemInfo>(MAX_POOL_SIZE);
/**
+ * Obtains a pooled instance that is a clone of another one.
+ *
+ * @param other The instance to clone.
+ *
+ * @hide
+ */
+ public static CollectionItemInfo obtain(CollectionItemInfo other) {
+ return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan,
+ other.mColumnIndex, other.mColumnSpan, other.mHeading);
+ }
+
+ /**
* Obtains a pooled instance.
*
* @param rowIndex The row index at which the item is located.
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index d4c6abe..557239f 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -140,7 +140,7 @@ public class CaptioningManager {
*
* @param listener the listener to add
*/
- public void addCaptioningStateChangeListener(CaptioningChangeListener listener) {
+ public void addCaptioningChangeListener(CaptioningChangeListener listener) {
synchronized (mListeners) {
if (mListeners.isEmpty()) {
registerObserver(Secure.ACCESSIBILITY_CAPTIONING_ENABLED);
@@ -163,11 +163,11 @@ public class CaptioningManager {
/**
* Removes a listener previously added using
- * {@link #addCaptioningStateChangeListener}.
+ * {@link #addCaptioningChangeListener}.
*
* @param listener the listener to remove
*/
- public void removeCaptioningStateChangeListener(CaptioningChangeListener listener) {
+ public void removeCaptioningChangeListener(CaptioningChangeListener listener) {
synchronized (mListeners) {
mListeners.remove(listener);
@@ -366,7 +366,7 @@ public class CaptioningManager {
* Listener for changes in captioning properties, including enabled state
* and user style preferences.
*/
- public abstract class CaptioningChangeListener {
+ public static abstract class CaptioningChangeListener {
/**
* Called when the captioning enabled state changes.
*
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 19492c2..7a38a16 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -333,8 +333,11 @@ public abstract class WebSettings {
}
/**
- * Sets whether the WebView loads pages in overview mode. The default is
- * false.
+ * Sets whether the WebView loads pages in overview mode, that is,
+ * zooms out the content to fit on screen by width. This setting is
+ * taken into account when the content width is greater than the width
+ * of the WebView control, for example, when {@link #getUseWideViewPort}
+ * is enabled. The default is false.
*/
public void setLoadWithOverviewMode(boolean overview) {
throw new MustOverrideException();
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f0e8c4f..8fc3ce3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1070,7 +1070,7 @@ public class WebView extends AbsoluteLayout
/**
* Exports the contents of this Webview as PDF. Only supported for API levels
- * {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE} and above.
+ * {@link android.os.Build.VERSION_CODES#KITKAT} and above.
*
* TODO(sgurun) the parameter list is stale. Fix it before unhiding.
*
@@ -1123,10 +1123,18 @@ public class WebView extends AbsoluteLayout
}
/**
- * Sets the initial scale for this WebView. 0 means default. If
- * {@link WebSettings#getUseWideViewPort()} is true, it zooms out all the
- * way. Otherwise it starts with 100%. If initial scale is greater than 0,
- * WebView starts with this value as initial scale.
+ * Sets the initial scale for this WebView. 0 means default.
+ * The behavior for the default scale depends on the state of
+ * {@link WebSettings#getUseWideViewPort()} and
+ * {@link WebSettings#getLoadWithOverviewMode()}.
+ * If the content fits into the WebView control by width, then
+ * the zoom is set to 100%. For wide content, the behavor
+ * depends on the state of {@link WebSettings#getLoadWithOverviewMode()}.
+ * If its value is true, the content will be zoomed out to be fit
+ * by width into the WebView control, otherwise not.
+ *
+ * If initial scale is greater than 0, WebView starts with this value
+ * as initial scale.
* Please note that unlike the scale properties in the viewport meta tag,
* this method doesn't take the screen density into account.
*
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index c308024..7378d74 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1250,7 +1250,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mFastScroller.setEnabled(true);
}
- recomputePadding();
+ resolvePadding();
if (mFastScroller != null) {
mFastScroller.updateLayout();
@@ -1312,7 +1312,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* @see #setFastScrollAlwaysVisible(boolean)
*/
public boolean isFastScrollAlwaysVisible() {
- return mFastScrollEnabled && mFastScrollAlwaysVisible;
+ if (mFastScroller == null) {
+ return mFastScrollEnabled && mFastScrollAlwaysVisible;
+ } else {
+ return mFastScroller.isEnabled() && mFastScroller.isAlwaysShowEnabled();
+ }
}
@Override
@@ -1331,7 +1335,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@ViewDebug.ExportedProperty
public boolean isFastScrollEnabled() {
- return mFastScrollEnabled;
+ if (mFastScroller == null) {
+ return mFastScrollEnabled;
+ } else {
+ return mFastScroller.isEnabled();
+ }
}
@Override
@@ -1356,7 +1364,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
@Override
protected boolean isVerticalScrollBarHidden() {
- return mFastScrollEnabled;
+ return isFastScrollEnabled();
}
/**
@@ -2843,6 +2851,23 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
return new AdapterContextMenuInfo(view, position, id);
}
+ @Override
+ public void onCancelPendingInputEvents() {
+ super.onCancelPendingInputEvents();
+ if (mPerformClick != null) {
+ removeCallbacks(mPerformClick);
+ }
+ if (mPendingCheckForTap != null) {
+ removeCallbacks(mPendingCheckForTap);
+ }
+ if (mPendingCheckForLongPress != null) {
+ removeCallbacks(mPendingCheckForLongPress);
+ }
+ if (mPendingCheckForKeyLongPress != null) {
+ removeCallbacks(mPendingCheckForKeyLongPress);
+ }
+ }
+
/**
* A base class for Runnables that will check that their view is still attached to
* the original window as when the Runnable was created.
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 778c8db..dff1531 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -29,12 +29,14 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ActionProvider;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
+import android.widget.ListPopupWindow.ForwardingListener;
/**
* This class is a view for choosing an activity for handling a given {@link Intent}.
@@ -228,17 +230,37 @@ public class ActivityChooserView extends ViewGroup implements ActivityChooserMod
mDefaultActivityButton.setOnLongClickListener(mCallbacks);
mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.image);
- mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.expand_activities_button);
- mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
- mExpandActivityOverflowButton.setAccessibilityDelegate(new AccessibilityDelegate() {
+ final FrameLayout expandButton = (FrameLayout) findViewById(R.id.expand_activities_button);
+ expandButton.setOnClickListener(mCallbacks);
+ expandButton.setAccessibilityDelegate(new AccessibilityDelegate() {
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
info.setCanOpenPopup(true);
}
});
+ expandButton.setOnTouchListener(new ForwardingListener(expandButton) {
+ @Override
+ public ListPopupWindow getPopup() {
+ return getListPopupWindow();
+ }
+
+ @Override
+ protected boolean onForwardingStarted() {
+ showPopup();
+ return true;
+ }
+
+ @Override
+ protected boolean onForwardingStopped() {
+ dismissPopup();
+ return true;
+ }
+ });
+ mExpandActivityOverflowButton = expandButton;
+
mExpandActivityOverflowButtonImage =
- (ImageView) mExpandActivityOverflowButton.findViewById(R.id.image);
+ (ImageView) expandButton.findViewById(R.id.image);
mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
mAdapter = new ActivityChooserViewAdapter();
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index c48955f..006b96e 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -152,9 +152,6 @@ class FastScroller {
/** The number of headers at the top of the view. */
private int mHeaderCount;
- /** The number of items in the list. */
- private int mItemCount = -1;
-
/** The index of the current section. */
private int mCurrentSection = -1;
@@ -324,6 +321,7 @@ class FastScroller {
getSectionsFromIndexer();
refreshDrawablePressedState();
+ updateLongList(listView.getChildCount(), listView.getCount());
setScrollbarPosition(mList.getVerticalScrollbarPosition());
postAutoHide();
}
@@ -343,14 +341,10 @@ class FastScroller {
* @param enabled Whether the fast scroll thumb is enabled.
*/
public void setEnabled(boolean enabled) {
- mEnabled = enabled;
+ if (mEnabled != enabled) {
+ mEnabled = enabled;
- if (enabled) {
- if (mAlwaysShow) {
- setState(STATE_VISIBLE);
- }
- } else {
- stop();
+ onStateDependencyChanged();
}
}
@@ -358,19 +352,17 @@ class FastScroller {
* @return Whether the fast scroll thumb is enabled.
*/
public boolean isEnabled() {
- return mEnabled;
+ return mEnabled && (mLongList || mAlwaysShow);
}
/**
* @param alwaysShow Whether the fast scroll thumb should always be shown
*/
public void setAlwaysShow(boolean alwaysShow) {
- mAlwaysShow = alwaysShow;
+ if (mAlwaysShow != alwaysShow) {
+ mAlwaysShow = alwaysShow;
- if (alwaysShow) {
- setState(STATE_VISIBLE);
- } else if (mState == STATE_VISIBLE) {
- postAutoHide();
+ onStateDependencyChanged();
}
}
@@ -382,6 +374,23 @@ class FastScroller {
return mAlwaysShow;
}
+ /**
+ * Called when one of the variables affecting enabled state changes.
+ */
+ private void onStateDependencyChanged() {
+ if (isEnabled()) {
+ if (isAlwaysShowEnabled()) {
+ setState(STATE_VISIBLE);
+ } else if (mState == STATE_VISIBLE) {
+ postAutoHide();
+ }
+ } else {
+ stop();
+ }
+
+ mList.resolvePadding();
+ }
+
public void setScrollBarStyle(int style) {
if (mScrollBarStyle != style) {
mScrollBarStyle = style;
@@ -439,6 +448,18 @@ class FastScroller {
final int firstVisibleItem = mList.getFirstVisiblePosition();
setThumbPos(getPosFromItemCount(firstVisibleItem, visibleItemCount, totalItemCount));
}
+
+ updateLongList(visibleItemCount, totalItemCount);
+ }
+
+ private void updateLongList(int visibleItemCount, int totalItemCount) {
+ final boolean longList = visibleItemCount > 0
+ && totalItemCount / visibleItemCount >= MIN_PAGES;
+ if (mLongList != longList) {
+ mLongList = longList;
+
+ onStateDependencyChanged();
+ }
}
/**
@@ -795,19 +816,8 @@ class FastScroller {
mList.postDelayed(mDeferHide, FADE_TIMEOUT);
}
- private boolean isLongList(int visibleItemCount, int totalItemCount) {
- // Are there enough pages to require fast scroll? Recompute only if
- // total count changes.
- if (mItemCount != totalItemCount && visibleItemCount > 0) {
- mItemCount = totalItemCount;
- mLongList = mItemCount / visibleItemCount >= MIN_PAGES;
- }
-
- return mLongList;
- }
-
public void onScroll(int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- if (!mEnabled || !mAlwaysShow && !isLongList(visibleItemCount, totalItemCount)) {
+ if (!isEnabled()) {
setState(STATE_NONE);
return;
}
@@ -1221,7 +1231,7 @@ class FastScroller {
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return false;
}
@@ -1233,14 +1243,18 @@ class FastScroller {
// need to allow the parent time to decide whether it wants
// to intercept events. If it does, we will receive a CANCEL
// event.
- if (mList.isInScrollingContainer()) {
- mInitialTouchY = ev.getY();
- startPendingDrag();
- return false;
+ if (!mList.isInScrollingContainer()) {
+ beginDrag();
+ return true;
}
- beginDrag();
- return true;
+ mInitialTouchY = ev.getY();
+ startPendingDrag();
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (!isPointInside(ev.getX(), ev.getY())) {
+ cancelPendingDrag();
}
break;
case MotionEvent.ACTION_UP:
@@ -1253,7 +1267,7 @@ class FastScroller {
}
public boolean onInterceptHoverEvent(MotionEvent ev) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return false;
}
@@ -1269,18 +1283,11 @@ class FastScroller {
}
public boolean onTouchEvent(MotionEvent me) {
- if (!mEnabled) {
+ if (!isEnabled()) {
return false;
}
switch (me.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- if (isPointInside(me.getX(), me.getY())) {
- beginDrag();
- return true;
- }
- } break;
-
case MotionEvent.ACTION_UP: {
if (mHasPendingDrag) {
// Allow a tap to scroll.
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index f2da765..b7e1fdd 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -974,10 +974,12 @@ public class ListPopupWindow {
* currently touched list item.
* <p>
* Example usage:
- * <pre>ListPopupWindow myPopup = new ListPopupWindow(context);
+ * <pre>
+ * ListPopupWindow myPopup = new ListPopupWindow(context);
* myPopup.setAnchor(myAnchor);
* OnTouchListener dragListener = myPopup.createDragToOpenListener(myAnchor);
- * myAnchor.setOnTouchListener(dragListener);</pre>
+ * myAnchor.setOnTouchListener(dragListener);
+ * </pre>
*
* @param src the view on which the resulting listener will be set
* @return a touch listener that controls drag-to-open behavior
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 941ddfc..389d9d6 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -248,7 +248,7 @@ public class ListView extends AbsListView {
* <p>
* Note: When first introduced, this method could only be called before
* setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
- * {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, this method may be
+ * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
* called at any time. If the ListView's adapter does not extend
* {@link HeaderViewListAdapter}, it will be wrapped with a supporting
* instance of {@link WrapperListAdapter}.
@@ -285,7 +285,7 @@ public class ListView extends AbsListView {
* <p>
* Note: When first introduced, this method could only be called before
* setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
- * {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, this method may be
+ * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
* called at any time. If the ListView's adapter does not extend
* {@link HeaderViewListAdapter}, it will be wrapped with a supporting
* instance of {@link WrapperListAdapter}.
@@ -341,7 +341,7 @@ public class ListView extends AbsListView {
* <p>
* Note: When first introduced, this method could only be called before
* setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
- * {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, this method may be
+ * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
* called at any time. If the ListView's adapter does not extend
* {@link HeaderViewListAdapter}, it will be wrapped with a supporting
* instance of {@link WrapperListAdapter}.
@@ -378,7 +378,7 @@ public class ListView extends AbsListView {
* <p>
* Note: When first introduced, this method could only be called before
* setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
- * {@link android.os.Build.VERSION_CODES#KEY_LIME_PIE}, this method may be
+ * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be
* called at any time. If the ListView's adapter does not extend
* {@link HeaderViewListAdapter}, it will be wrapped with a supporting
* instance of {@link WrapperListAdapter}.
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index e5344c6..603db70 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -82,8 +82,10 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
* currently touched list item.
* <p>
* Example usage:
- * <pre>PopupMenu myPopup = new PopupMenu(context, myAnchor);
- * myAnchor.setOnTouchListener(myPopup.getDragToOpenListener());</pre>
+ * <pre>
+ * PopupMenu myPopup = new PopupMenu(context, myAnchor);
+ * myAnchor.setOnTouchListener(myPopup.getDragToOpenListener());
+ * </pre>
*
* @return a touch listener that controls drag-to-open behavior
*/
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index f73e2c4..92c9b93 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -462,6 +462,7 @@ public class RelativeLayout extends ViewGroup {
views = mSortedVerticalChildren;
count = views.length;
+ final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
for (int i = 0; i < count; i++) {
View child = views[i];
@@ -476,14 +477,26 @@ public class RelativeLayout extends ViewGroup {
if (isWrapContentWidth) {
if (isLayoutRtl()) {
- width = Math.max(width, myWidth - params.mLeft);
+ if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
+ width = Math.max(width, myWidth - params.mLeft);
+ } else {
+ width = Math.max(width, myWidth - params.mLeft - params.leftMargin);
+ }
} else {
- width = Math.max(width, params.mRight);
+ if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
+ width = Math.max(width, params.mRight);
+ } else {
+ width = Math.max(width, params.mRight + params.rightMargin);
+ }
}
}
if (isWrapContentHeight) {
- height = Math.max(height, params.mBottom);
+ if (targetSdkVersion < Build.VERSION_CODES.KITKAT) {
+ height = Math.max(height, params.mBottom);
+ } else {
+ height = Math.max(height, params.mBottom + params.bottomMargin);
+ }
}
if (child != ignore || verticalGravity) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a2d48a8..3c9cc98 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1519,6 +1519,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* with this TextView. By default there is no associated UndoManager, so null
* is returned. One can be associated with the TextView through
* {@link #setUndoManager(android.content.UndoManager, String)}
+ *
+ * @hide
*/
public final UndoManager getUndoManager() {
return mEditor == null ? null : mEditor.mUndoManager;
@@ -1535,6 +1537,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* @param tag String tag identifying this particular TextView owner in the
* UndoManager. This is used to keep the correct association with the
* {@link android.content.UndoOwner} of any operations inside of the UndoManager.
+ *
+ * @hide
*/
public final void setUndoManager(UndoManager undoManager, String tag) {
if (undoManager != null) {
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 0ddc131..009b729 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -29,9 +29,13 @@ import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
import android.media.Metadata;
+import android.media.SubtitleController;
+import android.media.SubtitleTrack.RenderingWidget;
+import android.media.WebVttRenderer;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
@@ -43,7 +47,6 @@ import android.widget.MediaController.MediaPlayerControl;
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
import java.util.Map;
import java.util.Vector;
@@ -54,7 +57,8 @@ import java.util.Vector;
* it can be used in any layout manager, and provides various display options
* such as scaling and tinting.
*/
-public class VideoView extends SurfaceView implements MediaPlayerControl {
+public class VideoView extends SurfaceView
+ implements MediaPlayerControl, SubtitleController.Anchor {
private String TAG = "VideoView";
// settable by the client
private Uri mUri;
@@ -96,14 +100,11 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private boolean mCanSeekBack;
private boolean mCanSeekForward;
- /** List of views overlaid on top of the video. */
- private ArrayList<View> mOverlays;
+ /** Subtitle rendering widget overlaid on top of the video. */
+ private RenderingWidget mSubtitleWidget;
- /**
- * Listener for overlay layout changes. Invalidates the video view to ensure
- * that captions are redrawn whenever their layout changes.
- */
- private OnLayoutChangeListener mOverlayLayoutListener;
+ /** Listener for changes to subtitle data, used to redraw when needed. */
+ private RenderingWidget.OnChangedListener mSubtitlesChangedListener;
public VideoView(Context context) {
super(context);
@@ -208,7 +209,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
- mPendingSubtitleTracks = 0;
+ mPendingSubtitleTracks = new Vector<Pair<InputStream, MediaFormat>>();
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
}
@@ -256,23 +257,19 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
* specify "und" for the language.
*/
public void addSubtitleSource(InputStream is, MediaFormat format) {
- // always signal unsupported message for now
- try {
- if (is != null) {
- is.close();
- }
- } catch (IOException e) {
- }
-
if (mMediaPlayer == null) {
- ++mPendingSubtitleTracks;
+ mPendingSubtitleTracks.add(Pair.create(is, format));
} else {
- mInfoListener.onInfo(
- mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+ try {
+ mMediaPlayer.addSubtitleSource(is, format);
+ } catch (IllegalStateException e) {
+ mInfoListener.onInfo(
+ mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+ }
}
}
- private int mPendingSubtitleTracks;
+ private Vector<Pair<InputStream, MediaFormat>> mPendingSubtitleTracks;
public void stopPlayback() {
if (mMediaPlayer != null) {
@@ -300,6 +297,14 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
release(false);
try {
mMediaPlayer = new MediaPlayer();
+ // TODO: create SubtitleController in MediaPlayer, but we need
+ // a context for the subtitle renderers
+ final Context context = getContext();
+ final SubtitleController controller = new SubtitleController(
+ context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
+ controller.registerRenderer(new WebVttRenderer(context));
+ mMediaPlayer.setSubtitleAnchor(controller, this);
+
if (mAudioSession != 0) {
mMediaPlayer.setAudioSessionId(mAudioSession);
} else {
@@ -318,9 +323,13 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
- for (int ix = 0; ix < mPendingSubtitleTracks; ix++) {
- mInfoListener.onInfo(
- mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+ for (Pair<InputStream, MediaFormat> pending: mPendingSubtitleTracks) {
+ try {
+ mMediaPlayer.addSubtitleSource(pending.first, pending.second);
+ } catch (IllegalStateException e) {
+ mInfoListener.onInfo(
+ mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+ }
}
// we don't set the target state here either, but preserve the
@@ -340,7 +349,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
} finally {
- mPendingSubtitleTracks = 0;
+ mPendingSubtitleTracks.clear();
}
}
@@ -604,7 +613,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
- mPendingSubtitleTracks = 0;
+ mPendingSubtitleTracks.clear();
mCurrentState = STATE_IDLE;
if (cleartargetstate) {
mTargetState = STATE_IDLE;
@@ -779,12 +788,29 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (mSubtitleWidget != null) {
+ mSubtitleWidget.onAttachedToWindow();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mSubtitleWidget != null) {
+ mSubtitleWidget.onDetachedFromWindow();
+ }
+ }
+
+ @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- // Layout overlay views, if necessary.
- if (changed && mOverlays != null && !mOverlays.isEmpty()) {
- measureAndLayoutOverlays();
+ if (mSubtitleWidget != null) {
+ measureAndLayoutSubtitleWidget();
}
}
@@ -792,86 +818,65 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
public void draw(Canvas canvas) {
super.draw(canvas);
- final int count = mOverlays.size();
- for (int i = 0; i < count; i++) {
- final View overlay = mOverlays.get(i);
- overlay.draw(canvas);
+ if (mSubtitleWidget != null) {
+ final int saveCount = canvas.save();
+ canvas.translate(getPaddingLeft(), getPaddingTop());
+ mSubtitleWidget.draw(canvas);
+ canvas.restoreToCount(saveCount);
}
}
/**
- * Adds a view to be overlaid on top of this video view. During layout, the
- * view will be forced to match the bounds, less padding, of the video view.
- * <p>
- * Overlays are drawn in the order they are added. The last added overlay
- * will be drawn on top.
+ * Forces a measurement and layout pass for all overlaid views.
*
- * @param overlay the view to overlay
- * @see #removeOverlay(View)
+ * @see #setSubtitleWidget(RenderingWidget)
*/
- private void addOverlay(View overlay) {
- if (mOverlays == null) {
- mOverlays = new ArrayList<View>(1);
- }
+ private void measureAndLayoutSubtitleWidget() {
+ final int width = getWidth() - getPaddingLeft() - getPaddingRight();
+ final int height = getHeight() - getPaddingTop() - getPaddingBottom();
- if (mOverlayLayoutListener == null) {
- mOverlayLayoutListener = new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- invalidate();
- }
- };
- }
+ mSubtitleWidget.setSize(width, height);
+ }
- if (mOverlays.isEmpty()) {
- setWillNotDraw(false);
+ /** @hide */
+ @Override
+ public void setSubtitleWidget(RenderingWidget subtitleWidget) {
+ if (mSubtitleWidget == subtitleWidget) {
+ return;
}
- mOverlays.add(overlay);
- overlay.addOnLayoutChangeListener(mOverlayLayoutListener);
- measureAndLayoutOverlays();
- }
+ final boolean attachedToWindow = isAttachedToWindow();
+ if (mSubtitleWidget != null) {
+ if (attachedToWindow) {
+ mSubtitleWidget.onDetachedFromWindow();
+ }
- /**
- * Removes a view previously added using {@link #addOverlay}.
- *
- * @param overlay the view to remove
- * @see #addOverlay(View)
- */
- private void removeOverlay(View overlay) {
- if (mOverlays == null) {
- return;
+ mSubtitleWidget.setOnChangedListener(null);
}
- overlay.removeOnLayoutChangeListener(mOverlayLayoutListener);
- mOverlays.remove(overlay);
+ mSubtitleWidget = subtitleWidget;
- if (mOverlays.isEmpty()) {
+ if (subtitleWidget != null) {
+ if (mSubtitlesChangedListener == null) {
+ mSubtitlesChangedListener = new RenderingWidget.OnChangedListener() {
+ @Override
+ public void onChanged(RenderingWidget renderingWidget) {
+ invalidate();
+ }
+ };
+ }
+
+ setWillNotDraw(false);
+ subtitleWidget.setOnChangedListener(mSubtitlesChangedListener);
+
+ if (attachedToWindow) {
+ subtitleWidget.onAttachedToWindow();
+ requestLayout();
+ }
+ } else {
setWillNotDraw(true);
}
invalidate();
}
-
- /**
- * Forces a measurement and layout pass for all overlaid views.
- *
- * @see #addOverlay(View)
- */
- private void measureAndLayoutOverlays() {
- final int left = getPaddingLeft();
- final int top = getPaddingTop();
- final int right = getWidth() - left - getPaddingRight();
- final int bottom = getHeight() - top - getPaddingBottom();
- final int widthSpec = MeasureSpec.makeMeasureSpec(right - left, MeasureSpec.EXACTLY);
- final int heightSpec = MeasureSpec.makeMeasureSpec(bottom - top, MeasureSpec.EXACTLY);
-
- final int count = mOverlays.size();
- for (int i = 0; i < count; i++) {
- final View overlay = mOverlays.get(i);
- overlay.measure(widthSpec, heightSpec);
- overlay.layout(left, top, right, bottom);
- }
- }
}