summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/bluetooth/BluetoothGatt.java8
-rw-r--r--core/java/android/content/Intent.java6
-rw-r--r--core/java/android/hardware/FlushCompleteListener.java35
-rw-r--r--core/java/android/hardware/Sensor.java22
-rw-r--r--core/java/android/hardware/SensorManager.java162
-rw-r--r--core/java/android/hardware/SystemSensorManager.java116
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDevice.java4
-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/nfc/cardemulation/ApduServiceInfo.java14
-rw-r--r--core/java/android/nfc/cardemulation/CardEmulation.java343
-rw-r--r--core/java/android/nfc/cardemulation/CardEmulationManager.java4
-rw-r--r--core/java/android/nfc/cardemulation/HostApduService.java31
-rw-r--r--core/java/android/nfc/cardemulation/OffHostApduService.java5
-rw-r--r--core/java/android/printservice/PrinterDiscoverySession.java2
-rw-r--r--core/java/android/security/IKeystoreService.java16
-rw-r--r--core/java/android/view/ScaleGestureDetector.java132
-rw-r--r--core/java/android/view/View.java6
-rw-r--r--core/java/android/webkit/CallbackProxy.java43
-rw-r--r--core/java/android/webkit/DebugFlags.java18
-rw-r--r--core/java/android/webkit/HTML5VideoFullScreen.java5
-rw-r--r--core/java/android/webkit/HTML5VideoViewProxy.java5
-rw-r--r--core/java/android/webkit/WebView.java55
-rw-r--r--core/java/android/webkit/WebViewClassic.java2
-rw-r--r--core/java/android/widget/AbsListView.java34
-rw-r--r--core/java/android/widget/ListPopupWindow.java6
-rw-r--r--core/java/android/widget/PopupMenu.java6
-rw-r--r--core/java/android/widget/VideoView.java176
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java168
-rw-r--r--core/java/com/android/internal/app/RestrictionsPinActivity.java88
-rw-r--r--core/java/com/android/internal/app/RestrictionsPinSetupActivity.java21
33 files changed, 1371 insertions, 269 deletions
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index b390aa1..a2bb78c 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -702,6 +702,10 @@ public final class BluetoothGatt implements BluetoothProfile {
* @param start Start or stop advertising
*/
/*package*/ void listen(boolean start) {
+ if (mContext == null || !mContext.getResources().
+ getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) {
+ throw new UnsupportedOperationException("BluetoothGatt#listen is blocked");
+ }
if (DBG) Log.d(TAG, "listen() - start: " + start);
if (mService == null || mClientIf == 0) return;
@@ -728,6 +732,10 @@ public final class BluetoothGatt implements BluetoothProfile {
/*package*/ void setAdvData(boolean advData, boolean includeName, boolean includeTxPower,
Integer minInterval, Integer maxInterval,
Integer appearance, Byte[] manufacturerData) {
+ if (mContext == null || !mContext.getResources().
+ getBoolean(com.android.internal.R.bool.config_bluetooth_le_peripheral_mode_supported)) {
+ throw new UnsupportedOperationException("BluetoothGatt#setAdvData is blocked");
+ }
if (DBG) Log.d(TAG, "setAdvData()");
if (mService == null || mClientIf == 0) return;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d7ca915..dfc0412 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3300,8 +3300,10 @@ public class Intent implements Parcelable, Cloneable {
/**
* Optional extra for {@link #ACTION_SHUTDOWN} that allows the sender to qualify that
* this shutdown is only for the user space of the system, not a complete shutdown.
- * Hardware should not be shut down when this is true. The default if not supplied
- * is false.
+ * When this is true, hardware devices can use this information to determine that
+ * they shouldn't do a complete shutdown of their device since this is not a
+ * complete shutdown down to the kernel, but only user space restarting.
+ * The default if not supplied is false.
*/
public static final String EXTRA_SHUTDOWN_USERSPACE_ONLY
= "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
diff --git a/core/java/android/hardware/FlushCompleteListener.java b/core/java/android/hardware/FlushCompleteListener.java
new file mode 100644
index 0000000..cb5b9e3
--- /dev/null
+++ b/core/java/android/hardware/FlushCompleteListener.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ * @hide
+ */
+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..bbede57 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,26 @@ 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
+ * @hide
+ */
+ 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.
+ * @hide
+ */
+ 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..b6ca62a 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -608,8 +608,72 @@ public abstract class SensorManager {
}
/**
- * 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 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 rate 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 maxBatchReportLatency 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.
+ * @hide
+ */
+ 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.
*
* <p class="note"></p>
* Note: Don't use this method with a one shot trigger sensor such as
@@ -655,31 +719,55 @@ public abstract class SensorManager {
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(rate);
+ 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)
+ * @hide
+ */
+ 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.
+ * @hide
+ */
+ public boolean flush(Sensor sensor) {
+ return flushImpl(sensor);
+ }
+
+ /** @hide */
+ protected abstract boolean flushImpl(Sensor sensor);
/**
* <p>
@@ -1079,15 +1167,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 +1495,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/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/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/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index b83911a..41c6603 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -105,8 +105,12 @@ public final class ApduServiceInfo implements Parcelable {
if (onHost) {
parser = si.loadXmlMetaData(pm, HostApduService.SERVICE_META_DATA);
if (parser == null) {
- throw new XmlPullParserException("No " + HostApduService.SERVICE_META_DATA +
- " meta-data");
+ Log.d(TAG, "Didn't find service meta-data, trying legacy.");
+ parser = si.loadXmlMetaData(pm, HostApduService.OLD_SERVICE_META_DATA);
+ if (parser == null) {
+ throw new XmlPullParserException("No " + HostApduService.SERVICE_META_DATA +
+ " meta-data");
+ }
}
} else {
parser = si.loadXmlMetaData(pm, OffHostApduService.SERVICE_META_DATA);
@@ -170,12 +174,12 @@ public final class ApduServiceInfo implements Parcelable {
com.android.internal.R.styleable.AidGroup_description);
String groupCategory = groupAttrs.getString(
com.android.internal.R.styleable.AidGroup_category);
- if (!CardEmulationManager.CATEGORY_PAYMENT.equals(groupCategory)) {
- groupCategory = CardEmulationManager.CATEGORY_OTHER;
+ if (!CardEmulation.CATEGORY_PAYMENT.equals(groupCategory)) {
+ groupCategory = CardEmulation.CATEGORY_OTHER;
}
currentGroup = mCategoryToGroup.get(groupCategory);
if (currentGroup != null) {
- if (!CardEmulationManager.CATEGORY_OTHER.equals(groupCategory)) {
+ if (!CardEmulation.CATEGORY_OTHER.equals(groupCategory)) {
Log.e(TAG, "Not allowing multiple aid-groups in the " +
groupCategory + " category");
currentGroup = null;
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
new file mode 100644
index 0000000..3cd7863
--- /dev/null
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -0,0 +1,343 @@
+/*
+ * 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.nfc.cardemulation;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.app.ActivityThread;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.nfc.INfcCardEmulation;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.List;
+
+public final class CardEmulation {
+ static final String TAG = "CardEmulation";
+
+ /**
+ * Activity action: ask the user to change the default
+ * card emulation service for a certain category. This will
+ * show a dialog that asks the user whether he wants to
+ * replace the current default service with the service
+ * identified with the ComponentName specified in
+ * {@link #EXTRA_SERVICE_COMPONENT}, for the category
+ * specified in {@link #EXTRA_CATEGORY}
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CHANGE_DEFAULT =
+ "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
+
+ /**
+ * The category extra for {@link #ACTION_CHANGE_DEFAULT}
+ *
+ * @see #ACTION_CHANGE_DEFAULT
+ */
+ public static final String EXTRA_CATEGORY = "category";
+
+ /**
+ * The ComponentName object passed in as a parcelable
+ * extra for {@link #ACTION_CHANGE_DEFAULT}
+ *
+ * @see #ACTION_CHANGE_DEFAULT
+ */
+ public static final String EXTRA_SERVICE_COMPONENT = "component";
+
+ /**
+ * The payment category can be used to indicate that an AID
+ * represents a payment application.
+ */
+ public static final String CATEGORY_PAYMENT = "payment";
+
+ /**
+ * If an AID group does not contain a category, or the
+ * specified category is not defined by the platform version
+ * that is parsing the AID group, all AIDs in the group will
+ * automatically be categorized under the {@link #CATEGORY_OTHER}
+ * category.
+ */
+ public static final String CATEGORY_OTHER = "other";
+
+ /**
+ * Return value for {@link #getSelectionModeForCategory(String)}.
+ *
+ * <p>In this mode, the user has set a default service for this
+ * AID category. If a remote reader selects any of the AIDs
+ * that the default service has registered in this category,
+ * that service will automatically be bound to to handle
+ * the transaction.
+ *
+ * <p>There are still cases where a service that is
+ * not the default for a category can selected:
+ * <p>
+ * If a remote reader selects an AID in this category
+ * that is not handled by the default service, and there is a set
+ * of other services {S} that do handle this AID, the
+ * user is asked if he wants to use any of the services in
+ * {S} instead.
+ * <p>
+ * As a special case, if the size of {S} is one, containing a single service X,
+ * and all AIDs X has registered in this category are not
+ * registered by any other service, then X will be
+ * selected automatically without asking the user.
+ * <p>Example:
+ * <ul>
+ * <li>Service A registers AIDs "1", "2" and "3" in the category
+ * <li>Service B registers AIDs "3" and "4" in the category
+ * <li>Service C registers AIDs "5" and "6" in the category
+ * </ul>
+ * In this case, the following will happen when service A
+ * is the default:
+ * <ul>
+ * <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
+ * <li>Reader selects AID "4": the user is asked to confirm he
+ * wants to use service B, because its AIDs overlap with service A.
+ * <li>Reader selects AID "5" or "6": service C is invoked automatically,
+ * because all AIDs it has asked for are only registered by C,
+ * and there is no overlap.
+ * </ul>
+ *
+ */
+ public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
+
+ /**
+ * Return value for {@link #getSelectionModeForCategory(String)}.
+ *
+ * <p>In this mode, whenever an AID of this category is selected,
+ * the user is asked which service he wants to use to handle
+ * the transaction, even if there is only one matching service.
+ */
+ public static final int SELECTION_MODE_ALWAYS_ASK = 1;
+
+ /**
+ * Return value for {@link #getSelectionModeForCategory(String)}.
+ *
+ * <p>In this mode, the user will only be asked to select a service
+ * if the selected AID has been registered by multiple applications.
+ */
+ public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
+
+ static boolean sIsInitialized = false;
+ static HashMap<Context, CardEmulation> sCardEmus = new HashMap();
+ static INfcCardEmulation sService;
+
+ final Context mContext;
+
+ private CardEmulation(Context context, INfcCardEmulation service) {
+ mContext = context.getApplicationContext();
+ sService = service;
+ }
+
+ public static synchronized CardEmulation getInstance(NfcAdapter adapter) {
+ if (adapter == null) throw new NullPointerException("NfcAdapter is null");
+ Context context = adapter.getContext();
+ if (context == null) {
+ Log.e(TAG, "NfcAdapter context is null.");
+ throw new UnsupportedOperationException();
+ }
+ if (!sIsInitialized) {
+ IPackageManager pm = ActivityThread.getPackageManager();
+ if (pm == null) {
+ Log.e(TAG, "Cannot get PackageManager");
+ throw new UnsupportedOperationException();
+ }
+ try {
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
+ Log.e(TAG, "This device does not support card emulation");
+ throw new UnsupportedOperationException();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "PackageManager query failed.");
+ throw new UnsupportedOperationException();
+ }
+ sIsInitialized = true;
+ }
+ CardEmulation manager = sCardEmus.get(context);
+ if (manager == null) {
+ // Get card emu service
+ INfcCardEmulation service = adapter.getCardEmulationService();
+ manager = new CardEmulation(context, service);
+ sCardEmus.put(context, manager);
+ }
+ return manager;
+ }
+
+ /**
+ * Allows an application to query whether a service is currently
+ * the default service to handle a card emulation category.
+ *
+ * <p>Note that if {@link #getSelectionModeForCategory(String)}
+ * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
+ * return false.
+ *
+ * @param service The ComponentName of the service
+ * @param category The category
+ * @return whether service is currently the default service for the category.
+ */
+ public boolean isDefaultServiceForCategory(ComponentName service, String category) {
+ try {
+ return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, category);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service,
+ category);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
+ *
+ * Allows an application to query whether a service is currently
+ * the default handler for a specified ISO7816-4 Application ID.
+ *
+ * @param service The ComponentName of the service
+ * @param aid The ISO7816-4 Application ID
+ * @return
+ */
+ public boolean isDefaultServiceForAid(ComponentName service, String aid) {
+ try {
+ return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Returns the application selection mode for the passed in category.
+ * Valid return values are:
+ * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
+ * application for this category, which will be preferred.
+ * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
+ * every time what app he would like to use in this category.
+ * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
+ * to pick a service if there is a conflict.
+ * @param category The category, for example {@link #CATEGORY_PAYMENT}
+ * @return
+ */
+ public int getSelectionModeForCategory(String category) {
+ if (CATEGORY_PAYMENT.equals(category)) {
+ String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
+ if (defaultComponent != null) {
+ return SELECTION_MODE_PREFER_DEFAULT;
+ } else {
+ return SELECTION_MODE_ALWAYS_ASK;
+ }
+ } else {
+ // All other categories are in "only ask if conflict" mode
+ return SELECTION_MODE_ASK_IF_CONFLICT;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public boolean setDefaultServiceForCategory(ComponentName service, String category) {
+ try {
+ return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, category);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service,
+ category);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public boolean setDefaultForNextTap(ComponentName service) {
+ try {
+ return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+ /**
+ * @hide
+ */
+ public List<ApduServiceInfo> getServices(String category) {
+ try {
+ return sService.getServices(UserHandle.myUserId(), category);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return null;
+ }
+ try {
+ return sService.getServices(UserHandle.myUserId(), category);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return null;
+ }
+ }
+ }
+
+ void recoverService() {
+ NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+ sService = adapter.getCardEmulationService();
+ }
+}
diff --git a/core/java/android/nfc/cardemulation/CardEmulationManager.java b/core/java/android/nfc/cardemulation/CardEmulationManager.java
index 9d60c73..124ea1c 100644
--- a/core/java/android/nfc/cardemulation/CardEmulationManager.java
+++ b/core/java/android/nfc/cardemulation/CardEmulationManager.java
@@ -33,6 +33,10 @@ import android.util.Log;
import java.util.HashMap;
import java.util.List;
+/**
+ * TODO Remove when calling .apks are upgraded
+ * @hide
+ */
public final class CardEmulationManager {
static final String TAG = "CardEmulationManager";
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/core/java/android/nfc/cardemulation/HostApduService.java
index ae94b2f..174acc0 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/core/java/android/nfc/cardemulation/HostApduService.java
@@ -40,13 +40,31 @@ public abstract class HostApduService extends Service {
*/
@SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE =
+ "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
+
+ /**
+ * The name of the meta-data element that contains
+ * more information about this service.
+ */
+ public static final String SERVICE_META_DATA =
+ "android.nfc.cardemulation.host_apdu_service";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ * TODO Remove
+ * @hide
+ */
+ public static final String OLD_SERVICE_INTERFACE =
"android.nfc.HostApduService";
/**
* The name of the meta-data element that contains
* more information about this service.
+ *
+ * TODO Remove
+ * @hide
*/
- public static final String SERVICE_META_DATA = "android.nfc.HostApduService";
+ public static final String OLD_SERVICE_META_DATA = "android.nfc.HostApduService";
/**
* Reason for {@link #onDeactivated(int)}.
@@ -63,7 +81,7 @@ public abstract class HostApduService extends Service {
* currently active on the logical channel).
*
* <p>Note that this next AID may still be resolved to this
- * service, in which case {@link #processCommandApdu(byte[], int)}
+ * service, in which case {@link #processCommandApdu(byte[], Bundle)}
* will be called again.
*/
public static final int DEACTIVATION_DESELECTED = 1;
@@ -131,7 +149,7 @@ public abstract class HostApduService extends Service {
byte[] apdu = dataBundle.getByteArray(KEY_DATA);
if (apdu != null) {
- byte[] responseApdu = processCommandApdu(apdu, 0);
+ byte[] responseApdu = processCommandApdu(apdu, null);
if (responseApdu != null) {
if (mNfcService == null) {
Log.e(TAG, "Response not sent; service was deactivated.");
@@ -230,7 +248,7 @@ public abstract class HostApduService extends Service {
* transaction.
*
* <p>Note: this method may be called anywhere between
- * the first {@link #processCommandApdu(byte[], int)}
+ * the first {@link #processCommandApdu(byte[], Bundle)}
* call and a {@link #onDeactivated(int)} call.
*/
public final void notifyUnhandled() {
@@ -290,8 +308,11 @@ public abstract class HostApduService extends Service {
* @param flags
* @return a byte-array containing the response APDU, or null if no
* response APDU can be sent at this point.
+ * @hide
*/
- public abstract byte[] processCommandApdu(byte[] commandApdu, int flags);
+ public byte[] processCommandApdu(byte[] commandApdu, int flags) {
+ return null;
+ }
/**
* This method will be called in two possible scenarios:
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/core/java/android/nfc/cardemulation/OffHostApduService.java
index 79599db..15f63f9 100644
--- a/core/java/android/nfc/cardemulation/OffHostApduService.java
+++ b/core/java/android/nfc/cardemulation/OffHostApduService.java
@@ -42,13 +42,14 @@ public abstract class OffHostApduService extends Service {
*/
@SdkConstant(SdkConstantType.SERVICE_ACTION)
public static final String SERVICE_INTERFACE =
- "android.nfc.OffHostApduService";
+ "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
/**
* The name of the meta-data element that contains
* more information about this service.
*/
- public static final String SERVICE_META_DATA = "android.nfc.OffHostApduService";
+ public static final String SERVICE_META_DATA =
+ "android.nfc.cardemulation.off_host_apdu_service";
/**
* The Android platform itself will not bind to this service,
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 1f86ecc..6464cc1 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -80,7 +80,7 @@ import java.util.List;
public abstract class PrinterDiscoverySession {
private static final String LOG_TAG = "PrinterDiscoverySession";
- private static final int MAX_ITEMS_PER_CALLBACK = 100;
+ private static final int MAX_ITEMS_PER_CALLBACK = 50;
private static int sIdCounter = 0;
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index 3d75dc8..bf8d4e5 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -244,7 +244,8 @@ public interface IKeystoreService extends IInterface {
return _result;
}
- public int generate(String name, int uid, int flags) throws RemoteException {
+ public int generate(String name, int uid, int keyType, int keySize, int flags,
+ byte[][] args) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
@@ -252,7 +253,17 @@ public interface IKeystoreService extends IInterface {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
_data.writeInt(uid);
+ _data.writeInt(keyType);
+ _data.writeInt(keySize);
_data.writeInt(flags);
+ if (args == null) {
+ _data.writeInt(0);
+ } else {
+ _data.writeInt(args.length);
+ for (int i = 0; i < args.length; i++) {
+ _data.writeByteArray(args[i]);
+ }
+ }
mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
@@ -560,7 +571,8 @@ public interface IKeystoreService extends IInterface {
public int zero() throws RemoteException;
- public int generate(String name, int uid, int flags) throws RemoteException;
+ public int generate(String name, int uid, int keyType, int keySize, int flags, byte[][] args)
+ throws RemoteException;
public int import_key(String name, byte[] data, int uid, int flags) throws RemoteException;
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 51c5c7b..0bebc04 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -18,6 +18,8 @@ package android.view;
import android.content.Context;
import android.content.res.Resources;
+import android.os.Build;
+import android.os.Handler;
import android.os.SystemClock;
import android.util.FloatMath;
@@ -128,6 +130,8 @@ public class ScaleGestureDetector {
private float mFocusX;
private float mFocusY;
+ private boolean mDoubleTapScales;
+
private float mCurrSpan;
private float mPrevSpan;
private float mInitialSpan;
@@ -148,9 +152,14 @@ public class ScaleGestureDetector {
private int mTouchHistoryDirection;
private long mTouchHistoryLastAcceptedTime;
private int mTouchMinMajor;
+ private MotionEvent mDoubleTapEvent;
+ private int mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
+ private final Handler mHandler;
private static final long TOUCH_STABILIZE_TIME = 128; // ms
- private static final int TOUCH_MIN_MAJOR = 48; // dp
+ private static final int DOUBLE_TAP_MODE_NONE = 0;
+ private static final int DOUBLE_TAP_MODE_IN_PROGRESS = 1;
+
/**
* Consistency verifier for debugging purposes.
@@ -158,8 +167,37 @@ public class ScaleGestureDetector {
private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
InputEventConsistencyVerifier.isInstrumentationEnabled() ?
new InputEventConsistencyVerifier(this, 0) : null;
+ private GestureDetector mGestureDetector;
+
+ private boolean mEventBeforeOrAboveStartingGestureEvent;
+ /**
+ * Creates a ScaleGestureDetector with the supplied listener.
+ * You may only use this constructor from a {@link android.os.Looper Looper} thread.
+ *
+ * @param context the application's context
+ * @param listener the listener invoked for all the callbacks, this must
+ * not be null.
+ *
+ * @throws NullPointerException if {@code listener} is null.
+ */
public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
+ this(context, listener, null);
+ }
+
+ /**
+ * Creates a ScaleGestureDetector with the supplied listener.
+ * @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 for running deferred listener events.
+ *
+ * @throws NullPointerException if {@code listener} is null.
+ */
+ public ScaleGestureDetector(Context context, OnScaleGestureListener listener,
+ Handler handler) {
mContext = context;
mListener = listener;
mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
@@ -167,8 +205,12 @@ public class ScaleGestureDetector {
final Resources res = context.getResources();
mTouchMinMajor = res.getDimensionPixelSize(
com.android.internal.R.dimen.config_minScalingTouchMajor);
- mMinSpan = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_minScalingSpan);
+ mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
+ mHandler = handler;
+ // Quick scale is enabled by default after JB_MR2
+ if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ setQuickScaleEnabled(true);
+ }
}
/**
@@ -263,8 +305,14 @@ public class ScaleGestureDetector {
final int action = event.getActionMasked();
+ // Forward the event to check for double tap gesture
+ if (mDoubleTapScales) {
+ mGestureDetector.onTouchEvent(event);
+ }
+
final boolean streamComplete = action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_CANCEL;
+
if (action == MotionEvent.ACTION_DOWN || streamComplete) {
// Reset any scale in progress with the listener.
// If it's an ACTION_DOWN we're beginning a new event stream.
@@ -273,6 +321,7 @@ public class ScaleGestureDetector {
mListener.onScaleEnd(this);
mInProgress = false;
mInitialSpan = 0;
+ mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
}
if (streamComplete) {
@@ -284,21 +333,37 @@ public class ScaleGestureDetector {
final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_UP ||
action == MotionEvent.ACTION_POINTER_DOWN;
+
+
final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
final int skipIndex = pointerUp ? event.getActionIndex() : -1;
// Determine focal point
float sumX = 0, sumY = 0;
final int count = event.getPointerCount();
- for (int i = 0; i < count; i++) {
- if (skipIndex == i) continue;
- sumX += event.getX(i);
- sumY += event.getY(i);
- }
final int div = pointerUp ? count - 1 : count;
- final float focusX = sumX / div;
- final float focusY = sumY / div;
+ final float focusX;
+ final float focusY;
+ if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS) {
+ // In double tap mode, the focal pt is always where the double tap
+ // gesture started
+ focusX = mDoubleTapEvent.getX();
+ focusY = mDoubleTapEvent.getY();
+ if (event.getY() < focusY) {
+ mEventBeforeOrAboveStartingGestureEvent = true;
+ } else {
+ mEventBeforeOrAboveStartingGestureEvent = false;
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ if (skipIndex == i) continue;
+ sumX += event.getX(i);
+ sumY += event.getY(i);
+ }
+ focusX = sumX / div;
+ focusY = sumY / div;
+ }
addTouchHistory(event);
@@ -320,7 +385,12 @@ public class ScaleGestureDetector {
// the focal point.
final float spanX = devX * 2;
final float spanY = devY * 2;
- final float span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
+ final float span;
+ if (inDoubleTapMode()) {
+ span = spanY;
+ } else {
+ span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
+ }
// Dispatch begin/end events as needed.
// If the configuration changes, notify the app to reset its current state by beginning
@@ -328,10 +398,11 @@ public class ScaleGestureDetector {
final boolean wasInProgress = mInProgress;
mFocusX = focusX;
mFocusY = focusY;
- if (mInProgress && (span < mMinSpan || configChanged)) {
+ if (!inDoubleTapMode() && mInProgress && (span < mMinSpan || configChanged)) {
mListener.onScaleEnd(this);
mInProgress = false;
mInitialSpan = span;
+ mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
}
if (configChanged) {
mPrevSpanX = mCurrSpanX = spanX;
@@ -354,6 +425,7 @@ public class ScaleGestureDetector {
mCurrSpan = span;
boolean updatePrev = true;
+
if (mInProgress) {
updatePrev = mListener.onScale(this);
}
@@ -369,6 +441,34 @@ public class ScaleGestureDetector {
return true;
}
+
+ private boolean inDoubleTapMode() {
+ return mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS;
+ }
+
+ /**
+ * Set whether the associated {@link OnScaleGestureListener} should receive onScale callbacks
+ * when the user performs a doubleTap followed by a swipe. Note that this is enabled by default
+ * if the app targets API 19 and newer.
+ * @param scales true to enable quick scaling, false to disable
+ */
+ public void setQuickScaleEnabled(boolean scales) {
+ mDoubleTapScales = scales;
+ if (mDoubleTapScales && mGestureDetector == null) {
+ GestureDetector.SimpleOnGestureListener gestureListener =
+ new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ // Double tap: start watching for a swipe
+ mDoubleTapEvent = e;
+ mDoubleTapMode = DOUBLE_TAP_MODE_IN_PROGRESS;
+ return true;
+ }
+ };
+ mGestureDetector = new GestureDetector(mContext, gestureListener, mHandler);
+ }
+ }
+
/**
* Returns {@code true} if a scale gesture is in progress.
*/
@@ -472,6 +572,12 @@ public class ScaleGestureDetector {
* @return The current scaling factor.
*/
public float getScaleFactor() {
+ if (inDoubleTapMode() && mEventBeforeOrAboveStartingGestureEvent) {
+ // Drag is moving up; the further away from the gesture
+ // start, the smaller the span should be, the closer,
+ // the larger the span, and therefore the larger the scale
+ return (1 / mCurrSpan) / (1 / mPrevSpan);
+ }
return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
}
@@ -493,4 +599,4 @@ public class ScaleGestureDetector {
public long getEventTime() {
return mCurrTime;
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5b279ec..907290b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13256,14 +13256,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// Keep the DRAWING_CACHE_QUALITY_LOW flag just in case
switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
case DRAWING_CACHE_QUALITY_AUTO:
- quality = Bitmap.Config.ARGB_8888;
- break;
case DRAWING_CACHE_QUALITY_LOW:
- quality = Bitmap.Config.ARGB_8888;
- break;
case DRAWING_CACHE_QUALITY_HIGH:
- quality = Bitmap.Config.ARGB_8888;
- break;
default:
quality = Bitmap.Config.ARGB_8888;
break;
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index fea6be6..7707392 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -50,7 +50,9 @@ import java.util.Map;
*/
class CallbackProxy extends Handler {
// Logging tag
- private static final String LOGTAG = "CallbackProxy";
+ static final String LOGTAG = "WebViewCallback";
+ // Enables API callback tracing
+ private static final boolean TRACE = DebugFlags.TRACE_CALLBACK;
// Instance of WebViewClient that is the client callback.
private volatile WebViewClient mWebViewClient;
// Instance of WebChromeClient for handling all chrome functions.
@@ -258,6 +260,7 @@ class CallbackProxy extends Handler {
}
boolean override = false;
if (mWebViewClient != null) {
+ if (TRACE) Log.d(LOGTAG, "shouldOverrideUrlLoading=" + overrideUrl);
override = mWebViewClient.shouldOverrideUrlLoading(mWebView.getWebView(),
overrideUrl);
} else {
@@ -307,6 +310,7 @@ class CallbackProxy extends Handler {
String startedUrl = msg.getData().getString("url");
mWebView.onPageStarted(startedUrl);
if (mWebViewClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onPageStarted=" + startedUrl);
mWebViewClient.onPageStarted(mWebView.getWebView(), startedUrl,
(Bitmap) msg.obj);
}
@@ -316,18 +320,21 @@ class CallbackProxy extends Handler {
String finishedUrl = (String) msg.obj;
mWebView.onPageFinished(finishedUrl);
if (mWebViewClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onPageFinished=" + finishedUrl);
mWebViewClient.onPageFinished(mWebView.getWebView(), finishedUrl);
}
break;
case RECEIVED_ICON:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onReceivedIcon");
mWebChromeClient.onReceivedIcon(mWebView.getWebView(), (Bitmap) msg.obj);
}
break;
case RECEIVED_TOUCH_ICON_URL:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onReceivedTouchIconUrl");
mWebChromeClient.onReceivedTouchIconUrl(mWebView.getWebView(),
(String) msg.obj, msg.arg1 == 1);
}
@@ -335,6 +342,7 @@ class CallbackProxy extends Handler {
case RECEIVED_TITLE:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onReceivedTitle");
mWebChromeClient.onReceivedTitle(mWebView.getWebView(),
(String) msg.obj);
}
@@ -345,6 +353,7 @@ class CallbackProxy extends Handler {
int reasonCode = msg.arg1;
final String description = msg.getData().getString("description");
final String failUrl = msg.getData().getString("failingUrl");
+ if (TRACE) Log.d(LOGTAG, "onReceivedError=" + failUrl);
mWebViewClient.onReceivedError(mWebView.getWebView(), reasonCode,
description, failUrl);
}
@@ -356,6 +365,7 @@ class CallbackProxy extends Handler {
Message dontResend =
(Message) msg.getData().getParcelable("dontResend");
if (mWebViewClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onFormResubmission");
mWebViewClient.onFormResubmission(mWebView.getWebView(), dontResend,
resend);
} else {
@@ -379,6 +389,7 @@ class CallbackProxy extends Handler {
HttpAuthHandler handler = (HttpAuthHandler) msg.obj;
String host = msg.getData().getString("host");
String realm = msg.getData().getString("realm");
+ if (TRACE) Log.d(LOGTAG, "onReceivedHttpAuthRequest");
mWebViewClient.onReceivedHttpAuthRequest(mWebView.getWebView(), handler,
host, realm);
}
@@ -388,6 +399,7 @@ class CallbackProxy extends Handler {
if (mWebViewClient != null) {
HashMap<String, Object> map =
(HashMap<String, Object>) msg.obj;
+ if (TRACE) Log.d(LOGTAG, "onReceivedSslError");
mWebViewClient.onReceivedSslError(mWebView.getWebView(),
(SslErrorHandler) map.get("handler"),
(SslError) map.get("error"));
@@ -396,6 +408,7 @@ class CallbackProxy extends Handler {
case PROCEEDED_AFTER_SSL_ERROR:
if (mWebViewClient != null && mWebViewClient instanceof WebViewClientClassicExt) {
+ if (TRACE) Log.d(LOGTAG, "onProceededAfterSslError");
((WebViewClientClassicExt) mWebViewClient).onProceededAfterSslError(
mWebView.getWebView(),
(SslError) msg.obj);
@@ -404,6 +417,7 @@ class CallbackProxy extends Handler {
case CLIENT_CERT_REQUEST:
if (mWebViewClient != null && mWebViewClient instanceof WebViewClientClassicExt) {
+ if (TRACE) Log.d(LOGTAG, "onReceivedClientCertRequest");
HashMap<String, Object> map = (HashMap<String, Object>) msg.obj;
((WebViewClientClassicExt) mWebViewClient).onReceivedClientCertRequest(
mWebView.getWebView(),
@@ -418,6 +432,7 @@ class CallbackProxy extends Handler {
// changed.
synchronized (this) {
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onProgressChanged=" + mLatestProgress);
mWebChromeClient.onProgressChanged(mWebView.getWebView(),
mLatestProgress);
}
@@ -427,14 +442,18 @@ class CallbackProxy extends Handler {
case UPDATE_VISITED:
if (mWebViewClient != null) {
+ String url = (String) msg.obj;
+ if (TRACE) Log.d(LOGTAG, "doUpdateVisitedHistory=" + url);
mWebViewClient.doUpdateVisitedHistory(mWebView.getWebView(),
- (String) msg.obj, msg.arg1 != 0);
+ url, msg.arg1 != 0);
}
break;
case LOAD_RESOURCE:
if (mWebViewClient != null) {
- mWebViewClient.onLoadResource(mWebView.getWebView(), (String) msg.obj);
+ String url = (String) msg.obj;
+ if (TRACE) Log.d(LOGTAG, "onLoadResource=" + url);
+ mWebViewClient.onLoadResource(mWebView.getWebView(), url);
}
break;
@@ -448,6 +467,7 @@ class CallbackProxy extends Handler {
String referer = msg.getData().getString("referer");
Long contentLength = msg.getData().getLong("contentLength");
+ if (TRACE) Log.d(LOGTAG, "onDownloadStart");
if (mDownloadListener instanceof BrowserDownloadListener) {
((BrowserDownloadListener) mDownloadListener).onDownloadStart(url,
userAgent, contentDisposition, mimetype, referer, contentLength);
@@ -460,6 +480,7 @@ class CallbackProxy extends Handler {
case CREATE_WINDOW:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onCreateWindow");
if (!mWebChromeClient.onCreateWindow(mWebView.getWebView(),
msg.arg1 == 1, msg.arg2 == 1,
(Message) msg.obj)) {
@@ -473,12 +494,14 @@ class CallbackProxy extends Handler {
case REQUEST_FOCUS:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onRequestFocus");
mWebChromeClient.onRequestFocus(mWebView.getWebView());
}
break;
case CLOSE_WINDOW:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onCloseWindow");
mWebChromeClient.onCloseWindow(((WebViewClassic) msg.obj).getWebView());
}
break;
@@ -500,6 +523,7 @@ class CallbackProxy extends Handler {
case ASYNC_KEYEVENTS:
if (mWebViewClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onUnhandledKeyEvent");
mWebViewClient.onUnhandledKeyEvent(mWebView.getWebView(),
(KeyEvent) msg.obj);
}
@@ -521,6 +545,7 @@ class CallbackProxy extends Handler {
WebStorage.QuotaUpdater quotaUpdater =
(WebStorage.QuotaUpdater) map.get("quotaUpdater");
+ if (TRACE) Log.d(LOGTAG, "onExceededDatabaseQuota");
mWebChromeClient.onExceededDatabaseQuota(url,
databaseIdentifier, quota, estimatedDatabaseSize,
totalQuota, quotaUpdater);
@@ -538,6 +563,7 @@ class CallbackProxy extends Handler {
WebStorage.QuotaUpdater quotaUpdater =
(WebStorage.QuotaUpdater) map.get("quotaUpdater");
+ if (TRACE) Log.d(LOGTAG, "onReachedMaxAppCacheSize");
mWebChromeClient.onReachedMaxAppCacheSize(requiredStorage,
quota, quotaUpdater);
}
@@ -551,6 +577,7 @@ class CallbackProxy extends Handler {
GeolocationPermissions.Callback callback =
(GeolocationPermissions.Callback)
map.get("callback");
+ if (TRACE) Log.d(LOGTAG, "onGeolocationPermissionsShowPrompt");
mWebChromeClient.onGeolocationPermissionsShowPrompt(origin,
callback);
}
@@ -558,6 +585,7 @@ class CallbackProxy extends Handler {
case GEOLOCATION_PERMISSIONS_HIDE_PROMPT:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onGeolocationPermissionsHidePrompt");
mWebChromeClient.onGeolocationPermissionsHidePrompt();
}
break;
@@ -566,6 +594,7 @@ class CallbackProxy extends Handler {
if (mWebChromeClient != null) {
final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
JsDialogHelper helper = new JsDialogHelper(receiver.mJsResult, msg);
+ if (TRACE) Log.d(LOGTAG, "onJsAlert");
if (!helper.invokeCallback(mWebChromeClient, mWebView.getWebView())) {
helper.showDialog(mContext);
}
@@ -577,6 +606,7 @@ class CallbackProxy extends Handler {
if(mWebChromeClient != null) {
final JsResultReceiver receiver = (JsResultReceiver) msg.obj;
final JsResult res = receiver.mJsResult;
+ if (TRACE) Log.d(LOGTAG, "onJsTimeout");
if (mWebChromeClient.onJsTimeout()) {
res.confirm();
} else {
@@ -598,6 +628,7 @@ class CallbackProxy extends Handler {
case SCALE_CHANGED:
if (mWebViewClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onScaleChanged");
mWebViewClient.onScaleChanged(mWebView.getWebView(), msg.getData()
.getFloat("old"), msg.getData().getFloat("new"));
}
@@ -624,6 +655,7 @@ class CallbackProxy extends Handler {
ConsoleMessage.MessageLevel messageLevel =
ConsoleMessage.MessageLevel.values()[msgLevel];
+ if (TRACE) Log.d(LOGTAG, "onConsoleMessage");
if (!mWebChromeClient.onConsoleMessage(new ConsoleMessage(message, sourceID,
lineNumber, messageLevel))) {
// If false was returned the user did not provide their own console function so
@@ -654,12 +686,14 @@ class CallbackProxy extends Handler {
case GET_VISITED_HISTORY:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "getVisitedHistory");
mWebChromeClient.getVisitedHistory((ValueCallback<String[]>)msg.obj);
}
break;
case OPEN_FILE_CHOOSER:
if (mWebChromeClient != null) {
+ if (TRACE) Log.d(LOGTAG, "openFileChooser");
UploadFileMessageData data = (UploadFileMessageData)msg.obj;
mWebChromeClient.openFileChooser(data.getUploadFile(), data.getAcceptType(),
data.getCapture());
@@ -668,6 +702,7 @@ class CallbackProxy extends Handler {
case ADD_HISTORY_ITEM:
if (mWebBackForwardListClient != null) {
+ if (TRACE) Log.d(LOGTAG, "onNewHistoryItem");
mWebBackForwardListClient.onNewHistoryItem(
(WebHistoryItem) msg.obj);
}
@@ -693,6 +728,7 @@ class CallbackProxy extends Handler {
String realm = msg.getData().getString("realm");
String account = msg.getData().getString("account");
String args = msg.getData().getString("args");
+ if (TRACE) Log.d(LOGTAG, "onReceivedLoginRequest");
mWebViewClient.onReceivedLoginRequest(mWebView.getWebView(), realm,
account, args);
}
@@ -910,6 +946,7 @@ class CallbackProxy extends Handler {
return null;
}
// Note: This method does _not_ send a message.
+ if (TRACE) Log.d(LOGTAG, "shouldInterceptRequest=" + url);
WebResourceResponse r =
mWebViewClient.shouldInterceptRequest(mWebView.getWebView(), url);
if (r == null) {
diff --git a/core/java/android/webkit/DebugFlags.java b/core/java/android/webkit/DebugFlags.java
index 349113e..524f610 100644
--- a/core/java/android/webkit/DebugFlags.java
+++ b/core/java/android/webkit/DebugFlags.java
@@ -24,25 +24,33 @@ package android.webkit;
* The name of each flags maps directly to the name of the class in which that
* flag is used.
*
+ * @hide Only used by WebView implementations.
*/
-class DebugFlags {
+public class DebugFlags {
+ public static final boolean COOKIE_SYNC_MANAGER = false;
+ public static final boolean TRACE_API = false;
+ public static final boolean TRACE_CALLBACK = false;
+ public static final boolean TRACE_JAVASCRIPT_BRIDGE = false;
+ public static final boolean URL_UTIL = false;
+ public static final boolean WEB_SYNC_MANAGER = false;
+
+ // TODO: Delete these when WebViewClassic is moved
public static final boolean BROWSER_FRAME = false;
public static final boolean CACHE_MANAGER = false;
public static final boolean CALLBACK_PROXY = false;
public static final boolean COOKIE_MANAGER = false;
- public static final boolean COOKIE_SYNC_MANAGER = false;
public static final boolean FRAME_LOADER = false;
public static final boolean J_WEB_CORE_JAVA_BRIDGE = false;// HIGHLY VERBOSE
public static final boolean LOAD_LISTENER = false;
+ public static final boolean MEASURE_PAGE_SWAP_FPS = false;
public static final boolean NETWORK = false;
public static final boolean SSL_ERROR_HANDLER = false;
public static final boolean STREAM_LOADER = false;
- public static final boolean URL_UTIL = false;
public static final boolean WEB_BACK_FORWARD_LIST = false;
public static final boolean WEB_SETTINGS = false;
- public static final boolean WEB_SYNC_MANAGER = false;
public static final boolean WEB_VIEW = false;
public static final boolean WEB_VIEW_CORE = false;
- public static final boolean MEASURE_PAGE_SWAP_FPS = false;
+
+
}
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index b52218d..6fb32c8 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -19,6 +19,7 @@ package android.webkit;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.Metadata;
+import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
@@ -293,12 +294,16 @@ public class HTML5VideoFullScreen extends HTML5VideoView
mLayout.setVisibility(View.VISIBLE);
WebChromeClient client = webView.getWebChromeClient();
if (client != null) {
+ if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onShowCustomView");
client.onShowCustomView(mLayout, mCallback);
// Plugins like Flash will draw over the video so hide
// them while we're playing.
if (webView.getViewManager() != null)
webView.getViewManager().hideAll();
+ if (DebugFlags.TRACE_CALLBACK) {
+ Log.d(CallbackProxy.LOGTAG, "getVideoLoadingProgressView");
+ }
mProgressView = client.getVideoLoadingProgressView();
if (mProgressView != null) {
mLayout.addView(mProgressView, layoutParams);
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index a3d62ae..e8538f6 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -180,6 +180,7 @@ class HTML5VideoViewProxy extends Handler
if (!mHTML5VideoView.fullScreenExited() && mHTML5VideoView.isFullScreenMode()) {
WebChromeClient client = webView.getWebChromeClient();
if (client != null) {
+ if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onHideCustomView");
client.onHideCustomView();
}
}
@@ -405,6 +406,7 @@ class HTML5VideoViewProxy extends Handler
case ERROR: {
WebChromeClient client = mWebView.getWebChromeClient();
if (client != null) {
+ if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onHideCustomView");
client.onHideCustomView();
}
break;
@@ -412,6 +414,9 @@ class HTML5VideoViewProxy extends Handler
case LOAD_DEFAULT_POSTER: {
WebChromeClient client = mWebView.getWebChromeClient();
if (client != null) {
+ if (DebugFlags.TRACE_CALLBACK) {
+ Log.d(CallbackProxy.LOGTAG, "getDefaultVideoPoster");
+ }
doSetPoster(client.getDefaultVideoPoster());
}
break;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index eded438..f0e8c4f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -244,7 +244,7 @@ public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
- private static final String LOGTAG = "webview_proxy";
+ private static final String LOGTAG = "WebView";
// Throwing an exception for incorrect thread usage if the
// build target is JB MR2 or newer. Defaults to false, and is
@@ -496,6 +496,7 @@ public class WebView extends AbsoluteLayout
sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
Build.VERSION_CODES.JELLY_BEAN_MR2;
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "WebView<init>");
ensureProviderCreated();
mProvider.init(javaScriptInterfaces, privateBrowsing);
@@ -510,6 +511,7 @@ public class WebView extends AbsoluteLayout
*/
public void setHorizontalScrollbarOverlay(boolean overlay) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setHorizontalScrollbarOverlay=" + overlay);
mProvider.setHorizontalScrollbarOverlay(overlay);
}
@@ -520,6 +522,7 @@ public class WebView extends AbsoluteLayout
*/
public void setVerticalScrollbarOverlay(boolean overlay) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setVerticalScrollbarOverlay=" + overlay);
mProvider.setVerticalScrollbarOverlay(overlay);
}
@@ -574,6 +577,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public void setCertificate(SslCertificate certificate) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setCertificate=" + certificate);
mProvider.setCertificate(certificate);
}
@@ -597,6 +601,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public void savePassword(String host, String username, String password) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "savePassword=" + host);
mProvider.savePassword(host, username, password);
}
@@ -616,6 +621,7 @@ public class WebView extends AbsoluteLayout
public void setHttpAuthUsernamePassword(String host, String realm,
String username, String password) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setHttpAuthUsernamePassword=" + host);
mProvider.setHttpAuthUsernamePassword(host, realm, username, password);
}
@@ -645,6 +651,7 @@ public class WebView extends AbsoluteLayout
*/
public void destroy() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "destroy");
mProvider.destroy();
}
@@ -683,6 +690,7 @@ public class WebView extends AbsoluteLayout
*/
public void setNetworkAvailable(boolean networkUp) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setNetworkAvailable=" + networkUp);
mProvider.setNetworkAvailable(networkUp);
}
@@ -699,6 +707,7 @@ public class WebView extends AbsoluteLayout
*/
public WebBackForwardList saveState(Bundle outState) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "saveState");
return mProvider.saveState(outState);
}
@@ -715,6 +724,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public boolean savePicture(Bundle b, final File dest) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "savePicture=" + dest.getName());
return mProvider.savePicture(b, dest);
}
@@ -732,6 +742,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public boolean restorePicture(Bundle b, File src) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "restorePicture=" + src.getName());
return mProvider.restorePicture(b, src);
}
@@ -749,6 +760,7 @@ public class WebView extends AbsoluteLayout
*/
public WebBackForwardList restoreState(Bundle inState) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "restoreState");
return mProvider.restoreState(inState);
}
@@ -765,6 +777,7 @@ public class WebView extends AbsoluteLayout
*/
public void loadUrl(String url, Map<String, String> additionalHttpHeaders) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadUrl(extra headers)=" + url);
mProvider.loadUrl(url, additionalHttpHeaders);
}
@@ -775,6 +788,7 @@ public class WebView extends AbsoluteLayout
*/
public void loadUrl(String url) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadUrl=" + url);
mProvider.loadUrl(url);
}
@@ -789,6 +803,7 @@ public class WebView extends AbsoluteLayout
*/
public void postUrl(String url, byte[] postData) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "postUrl=" + url);
mProvider.postUrl(url, postData);
}
@@ -823,6 +838,7 @@ public class WebView extends AbsoluteLayout
*/
public void loadData(String data, String mimeType, String encoding) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadData");
mProvider.loadData(data, mimeType, encoding);
}
@@ -855,6 +871,7 @@ public class WebView extends AbsoluteLayout
public void loadDataWithBaseURL(String baseUrl, String data,
String mimeType, String encoding, String historyUrl) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "loadDataWithBaseURL=" + baseUrl);
mProvider.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
}
@@ -871,6 +888,7 @@ public class WebView extends AbsoluteLayout
*/
public void evaluateJavascript(String script, ValueCallback<String> resultCallback) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "evaluateJavascript=" + script);
mProvider.evaluateJavaScript(script, resultCallback);
}
@@ -881,6 +899,7 @@ public class WebView extends AbsoluteLayout
*/
public void saveWebArchive(String filename) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "saveWebArchive=" + filename);
mProvider.saveWebArchive(filename);
}
@@ -898,6 +917,7 @@ public class WebView extends AbsoluteLayout
*/
public void saveWebArchive(String basename, boolean autoname, ValueCallback<String> callback) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "saveWebArchive(auto)=" + basename);
mProvider.saveWebArchive(basename, autoname, callback);
}
@@ -906,6 +926,7 @@ public class WebView extends AbsoluteLayout
*/
public void stopLoading() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "stopLoading");
mProvider.stopLoading();
}
@@ -914,6 +935,7 @@ public class WebView extends AbsoluteLayout
*/
public void reload() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "reload");
mProvider.reload();
}
@@ -932,6 +954,7 @@ public class WebView extends AbsoluteLayout
*/
public void goBack() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "goBack");
mProvider.goBack();
}
@@ -950,6 +973,7 @@ public class WebView extends AbsoluteLayout
*/
public void goForward() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "goForward");
mProvider.goForward();
}
@@ -975,6 +999,7 @@ public class WebView extends AbsoluteLayout
*/
public void goBackOrForward(int steps) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "goBackOrForwad=" + steps);
mProvider.goBackOrForward(steps);
}
@@ -994,6 +1019,7 @@ public class WebView extends AbsoluteLayout
*/
public boolean pageUp(boolean top) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "pageUp");
return mProvider.pageUp(top);
}
@@ -1005,6 +1031,7 @@ public class WebView extends AbsoluteLayout
*/
public boolean pageDown(boolean bottom) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "pageDown");
return mProvider.pageDown(bottom);
}
@@ -1017,6 +1044,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public void clearView() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearView");
mProvider.clearView();
}
@@ -1036,6 +1064,7 @@ public class WebView extends AbsoluteLayout
*/
public Picture capturePicture() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "capturePicture");
return mProvider.capturePicture();
}
@@ -1073,6 +1102,7 @@ public class WebView extends AbsoluteLayout
ValueCallback<Boolean> resultCallback, CancellationSignal cancellationSignal)
throws java.io.IOException {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "exportToPdf");
mProvider.exportToPdf(fd, attributes, resultCallback, cancellationSignal);
}
@@ -1104,6 +1134,7 @@ public class WebView extends AbsoluteLayout
*/
public void setInitialScale(int scaleInPercent) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setInitialScale=" + scaleInPercent);
mProvider.setInitialScale(scaleInPercent);
}
@@ -1114,6 +1145,7 @@ public class WebView extends AbsoluteLayout
*/
public void invokeZoomPicker() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "invokeZoomPicker");
mProvider.invokeZoomPicker();
}
@@ -1137,6 +1169,7 @@ public class WebView extends AbsoluteLayout
*/
public HitTestResult getHitTestResult() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "getHitTestResult");
return mProvider.getHitTestResult();
}
@@ -1155,6 +1188,7 @@ public class WebView extends AbsoluteLayout
*/
public void requestFocusNodeHref(Message hrefMsg) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "requestFocusNodeHref");
mProvider.requestFocusNodeHref(hrefMsg);
}
@@ -1167,6 +1201,7 @@ public class WebView extends AbsoluteLayout
*/
public void requestImageRef(Message msg) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "requestImageRef");
mProvider.requestImageRef(msg);
}
@@ -1271,6 +1306,7 @@ public class WebView extends AbsoluteLayout
*/
public void pauseTimers() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "pauseTimers");
mProvider.pauseTimers();
}
@@ -1280,6 +1316,7 @@ public class WebView extends AbsoluteLayout
*/
public void resumeTimers() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "resumeTimers");
mProvider.resumeTimers();
}
@@ -1292,6 +1329,7 @@ public class WebView extends AbsoluteLayout
*/
public void onPause() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "onPause");
mProvider.onPause();
}
@@ -1300,6 +1338,7 @@ public class WebView extends AbsoluteLayout
*/
public void onResume() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "onResume");
mProvider.onResume();
}
@@ -1319,6 +1358,7 @@ public class WebView extends AbsoluteLayout
*/
public void freeMemory() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "freeMemory");
mProvider.freeMemory();
}
@@ -1330,6 +1370,7 @@ public class WebView extends AbsoluteLayout
*/
public void clearCache(boolean includeDiskFiles) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearCache");
mProvider.clearCache(includeDiskFiles);
}
@@ -1341,6 +1382,7 @@ public class WebView extends AbsoluteLayout
*/
public void clearFormData() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearFormData");
mProvider.clearFormData();
}
@@ -1349,6 +1391,7 @@ public class WebView extends AbsoluteLayout
*/
public void clearHistory() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearHistory");
mProvider.clearHistory();
}
@@ -1358,6 +1401,7 @@ public class WebView extends AbsoluteLayout
*/
public void clearSslPreferences() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearSslPreferences");
mProvider.clearSslPreferences();
}
@@ -1399,6 +1443,7 @@ public class WebView extends AbsoluteLayout
*/
public void findNext(boolean forward) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "findNext");
mProvider.findNext(forward);
}
@@ -1414,6 +1459,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public int findAll(String find) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "findAll");
StrictMode.noteSlowCall("findAll blocks UI: prefer findAllAsync");
return mProvider.findAll(find);
}
@@ -1428,6 +1474,7 @@ public class WebView extends AbsoluteLayout
*/
public void findAllAsync(String find) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "findAllAsync");
mProvider.findAllAsync(find);
}
@@ -1448,6 +1495,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public boolean showFindDialog(String text, boolean showIme) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "showFindDialog");
return mProvider.showFindDialog(text, showIme);
}
@@ -1483,6 +1531,7 @@ public class WebView extends AbsoluteLayout
*/
public void clearMatches() {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "clearMatches");
mProvider.clearMatches();
}
@@ -1543,6 +1592,7 @@ public class WebView extends AbsoluteLayout
@Deprecated
public void setPictureListener(PictureListener listener) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "setPictureListener=" + listener);
mProvider.setPictureListener(listener);
}
@@ -1592,6 +1642,7 @@ public class WebView extends AbsoluteLayout
*/
public void addJavascriptInterface(Object object, String name) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "addJavascriptInterface=" + name);
mProvider.addJavascriptInterface(object, name);
}
@@ -1604,6 +1655,7 @@ public class WebView extends AbsoluteLayout
*/
public void removeJavascriptInterface(String name) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "removeJavascriptInterface=" + name);
mProvider.removeJavascriptInterface(name);
}
@@ -1693,6 +1745,7 @@ public class WebView extends AbsoluteLayout
public void flingScroll(int vx, int vy) {
checkThread();
+ if (DebugFlags.TRACE_API) Log.d(LOGTAG, "flingScroll");
mProvider.flingScroll(vx, vy);
}
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index b1a7878..3f22d53 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -7951,6 +7951,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// triggered in setNewPicture
Picture picture = mContext.getApplicationInfo().targetSdkVersion <
Build.VERSION_CODES.JELLY_BEAN_MR2 ? capturePicture() : null;
+ if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onNewPicture");
mPictureListener.onNewPicture(getWebView(), picture);
}
}
@@ -8038,6 +8039,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// triggered in pageSwapCallback
Picture picture = mContext.getApplicationInfo().targetSdkVersion <
Build.VERSION_CODES.JELLY_BEAN_MR2 ? capturePicture() : null;
+ if (DebugFlags.TRACE_CALLBACK) Log.d(CallbackProxy.LOGTAG, "onNewPicture");
mPictureListener.onNewPicture(getWebView(), picture);
}
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index be47bf0..c308024 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4924,11 +4924,37 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* Scrolls the list items within the view by a specified number of pixels.
*
* @param y the amount of pixels to scroll by vertically
- * @return true if the list is able to scroll, or false if the list is
- * already at the beginning/end and unable to scroll any more.
+ * @see #canScrollList(int)
*/
- public boolean scrollListBy(int y) {
- return !trackMotionScroll(-y, -y);
+ public void scrollListBy(int y) {
+ trackMotionScroll(-y, -y);
+ }
+
+ /**
+ * Check if the items in the list can be scrolled in a certain direction.
+ *
+ * @param direction Negative to check scrolling up, positive to check
+ * scrolling down.
+ * @return true if the list can be scrolled in the specified direction,
+ * false otherwise.
+ * @see #scrollListBy(int)
+ */
+ public boolean canScrollList(int direction) {
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ return false;
+ }
+
+ final int firstPosition = mFirstPosition;
+ final Rect listPadding = mListPadding;
+ if (direction > 0) {
+ final int lastBottom = getChildAt(childCount - 1).getBottom();
+ final int lastPosition = firstPosition + childCount;
+ return lastPosition < mItemCount || lastBottom > getHeight() - listPadding.bottom;
+ } else {
+ final int firstTop = getChildAt(0).getTop();
+ return firstPosition > 0 || firstTop < listPadding.top;
+ }
}
/**
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/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/VideoView.java b/core/java/android/widget/VideoView.java
index ebf9fe0..0ddc131 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -21,12 +21,14 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.media.AudioManager;
+import android.media.MediaFormat;
import android.media.MediaPlayer;
-import android.media.Metadata;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnInfoListener;
+import android.media.Metadata;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
@@ -40,7 +42,10 @@ import android.view.accessibility.AccessibilityNodeInfo;
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;
/**
* Displays a video file. The VideoView class
@@ -91,6 +96,15 @@ 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;
+
+ /**
+ * Listener for overlay layout changes. Invalidates the video view to ensure
+ * that captions are redrawn whenever their layout changes.
+ */
+ private OnLayoutChangeListener mOverlayLayoutListener;
+
public VideoView(Context context) {
super(context);
initVideoView();
@@ -194,6 +208,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
+ mPendingSubtitleTracks = 0;
mCurrentState = STATE_IDLE;
mTargetState = STATE_IDLE;
}
@@ -218,6 +233,47 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
invalidate();
}
+ /**
+ * Adds an external subtitle source file (from the provided input stream.)
+ *
+ * Note that a single external subtitle source may contain multiple or no
+ * supported tracks in it. If the source contained at least one track in
+ * it, one will receive an {@link MediaPlayer#MEDIA_INFO_METADATA_UPDATE}
+ * info message. Otherwise, if reading the source takes excessive time,
+ * one will receive a {@link MediaPlayer#MEDIA_INFO_SUBTITLE_TIMED_OUT}
+ * message. If the source contained no supported track (including an empty
+ * source file or null input stream), one will receive a {@link
+ * MediaPlayer#MEDIA_INFO_UNSUPPORTED_SUBTITLE} message. One can find the
+ * total number of available tracks using {@link MediaPlayer#getTrackInfo()}
+ * to see what additional tracks become available after this method call.
+ *
+ * @param is input stream containing the subtitle data. It will be
+ * closed by the media framework.
+ * @param format the format of the subtitle track(s). Must contain at least
+ * the mime type ({@link MediaFormat#KEY_MIME}) and the
+ * language ({@link MediaFormat#KEY_LANGUAGE}) of the file.
+ * If the file itself contains the language information,
+ * 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;
+ } else {
+ mInfoListener.onInfo(
+ mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+ }
+ }
+
+ private int mPendingSubtitleTracks;
+
public void stopPlayback() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
@@ -253,7 +309,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.setOnVideoSizeChangedListener(mSizeChangedListener);
mMediaPlayer.setOnCompletionListener(mCompletionListener);
mMediaPlayer.setOnErrorListener(mErrorListener);
- mMediaPlayer.setOnInfoListener(mOnInfoListener);
+ mMediaPlayer.setOnInfoListener(mInfoListener);
mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
mCurrentBufferPercentage = 0;
mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
@@ -261,6 +317,12 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.prepareAsync();
+
+ for (int ix = 0; ix < mPendingSubtitleTracks; ix++) {
+ mInfoListener.onInfo(
+ mMediaPlayer, MediaPlayer.MEDIA_INFO_UNSUPPORTED_SUBTITLE, 0);
+ }
+
// we don't set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
@@ -277,6 +339,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mTargetState = STATE_ERROR;
mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
return;
+ } finally {
+ mPendingSubtitleTracks = 0;
}
}
@@ -386,6 +450,16 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
}
};
+ private MediaPlayer.OnInfoListener mInfoListener =
+ new MediaPlayer.OnInfoListener() {
+ public boolean onInfo(MediaPlayer mp, int arg1, int arg2) {
+ if (mOnInfoListener != null) {
+ mOnInfoListener.onInfo(mp, arg1, arg2);
+ }
+ return true;
+ }
+ };
+
private MediaPlayer.OnErrorListener mErrorListener =
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int framework_err, int impl_err) {
@@ -530,6 +604,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
+ mPendingSubtitleTracks = 0;
mCurrentState = STATE_IDLE;
if (cleartargetstate) {
mTargetState = STATE_IDLE;
@@ -702,4 +777,101 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
}
return mAudioSession;
}
+
+ @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();
+ }
+ }
+
+ @Override
+ 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);
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @param overlay the view to overlay
+ * @see #removeOverlay(View)
+ */
+ private void addOverlay(View overlay) {
+ if (mOverlays == null) {
+ mOverlays = new ArrayList<View>(1);
+ }
+
+ 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();
+ }
+ };
+ }
+
+ if (mOverlays.isEmpty()) {
+ setWillNotDraw(false);
+ }
+
+ mOverlays.add(overlay);
+ overlay.addOnLayoutChangeListener(mOverlayLayoutListener);
+ measureAndLayoutOverlays();
+ }
+
+ /**
+ * 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;
+ }
+
+ overlay.removeOnLayoutChangeListener(mOverlayLayoutListener);
+ mOverlays.remove(overlay);
+
+ if (mOverlays.isEmpty()) {
+ 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);
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ab81a37..8819237 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -287,102 +287,104 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
}
protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
- // Build a reasonable intent filter, based on what matched.
- IntentFilter filter = new IntentFilter();
+ if (mAlwaysUseOption) {
+ // Build a reasonable intent filter, based on what matched.
+ IntentFilter filter = new IntentFilter();
- if (intent.getAction() != null) {
- filter.addAction(intent.getAction());
- }
- Set<String> categories = intent.getCategories();
- if (categories != null) {
- for (String cat : categories) {
- filter.addCategory(cat);
+ if (intent.getAction() != null) {
+ filter.addAction(intent.getAction());
}
- }
- filter.addCategory(Intent.CATEGORY_DEFAULT);
-
- int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
- Uri data = intent.getData();
- if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
- String mimeType = intent.resolveType(this);
- if (mimeType != null) {
- try {
- filter.addDataType(mimeType);
- } catch (IntentFilter.MalformedMimeTypeException e) {
- Log.w("ResolverActivity", e);
- filter = null;
+ Set<String> categories = intent.getCategories();
+ if (categories != null) {
+ for (String cat : categories) {
+ filter.addCategory(cat);
}
}
- }
- if (data != null && data.getScheme() != null) {
- // We need the data specification if there was no type,
- // OR if the scheme is not one of our magical "file:"
- // or "content:" schemes (see IntentFilter for the reason).
- if (cat != IntentFilter.MATCH_CATEGORY_TYPE
- || (!"file".equals(data.getScheme())
- && !"content".equals(data.getScheme()))) {
- filter.addDataScheme(data.getScheme());
-
- // Look through the resolved filter to determine which part
- // of it matched the original Intent.
- Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
- if (pIt != null) {
- String ssp = data.getSchemeSpecificPart();
- while (ssp != null && pIt.hasNext()) {
- PatternMatcher p = pIt.next();
- if (p.match(ssp)) {
- filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
- break;
- }
+ filter.addCategory(Intent.CATEGORY_DEFAULT);
+
+ int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
+ Uri data = intent.getData();
+ if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
+ String mimeType = intent.resolveType(this);
+ if (mimeType != null) {
+ try {
+ filter.addDataType(mimeType);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ Log.w("ResolverActivity", e);
+ filter = null;
}
}
- Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
- if (aIt != null) {
- while (aIt.hasNext()) {
- IntentFilter.AuthorityEntry a = aIt.next();
- if (a.match(data) >= 0) {
- int port = a.getPort();
- filter.addDataAuthority(a.getHost(),
- port >= 0 ? Integer.toString(port) : null);
- break;
+ }
+ if (data != null && data.getScheme() != null) {
+ // We need the data specification if there was no type,
+ // OR if the scheme is not one of our magical "file:"
+ // or "content:" schemes (see IntentFilter for the reason).
+ if (cat != IntentFilter.MATCH_CATEGORY_TYPE
+ || (!"file".equals(data.getScheme())
+ && !"content".equals(data.getScheme()))) {
+ filter.addDataScheme(data.getScheme());
+
+ // Look through the resolved filter to determine which part
+ // of it matched the original Intent.
+ Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
+ if (pIt != null) {
+ String ssp = data.getSchemeSpecificPart();
+ while (ssp != null && pIt.hasNext()) {
+ PatternMatcher p = pIt.next();
+ if (p.match(ssp)) {
+ filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
+ break;
+ }
}
}
- }
- pIt = ri.filter.pathsIterator();
- if (pIt != null) {
- String path = data.getPath();
- while (path != null && pIt.hasNext()) {
- PatternMatcher p = pIt.next();
- if (p.match(path)) {
- filter.addDataPath(p.getPath(), p.getType());
- break;
+ Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
+ if (aIt != null) {
+ while (aIt.hasNext()) {
+ IntentFilter.AuthorityEntry a = aIt.next();
+ if (a.match(data) >= 0) {
+ int port = a.getPort();
+ filter.addDataAuthority(a.getHost(),
+ port >= 0 ? Integer.toString(port) : null);
+ break;
+ }
+ }
+ }
+ pIt = ri.filter.pathsIterator();
+ if (pIt != null) {
+ String path = data.getPath();
+ while (path != null && pIt.hasNext()) {
+ PatternMatcher p = pIt.next();
+ if (p.match(path)) {
+ filter.addDataPath(p.getPath(), p.getType());
+ break;
+ }
}
}
}
}
- }
- if (filter != null) {
- final int N = mAdapter.mList.size();
- ComponentName[] set = new ComponentName[N];
- int bestMatch = 0;
- for (int i=0; i<N; i++) {
- ResolveInfo r = mAdapter.mList.get(i).ri;
- set[i] = new ComponentName(r.activityInfo.packageName,
- r.activityInfo.name);
- if (r.match > bestMatch) bestMatch = r.match;
- }
- if (alwaysCheck) {
- getPackageManager().addPreferredActivity(filter, bestMatch, set,
- intent.getComponent());
- } else {
- try {
- AppGlobals.getPackageManager().setLastChosenActivity(intent,
- intent.resolveTypeIfNeeded(getContentResolver()),
- PackageManager.MATCH_DEFAULT_ONLY,
- filter, bestMatch, intent.getComponent());
- } catch (RemoteException re) {
- Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
+ if (filter != null) {
+ final int N = mAdapter.mList.size();
+ ComponentName[] set = new ComponentName[N];
+ int bestMatch = 0;
+ for (int i=0; i<N; i++) {
+ ResolveInfo r = mAdapter.mList.get(i).ri;
+ set[i] = new ComponentName(r.activityInfo.packageName,
+ r.activityInfo.name);
+ if (r.match > bestMatch) bestMatch = r.match;
+ }
+ if (alwaysCheck) {
+ getPackageManager().addPreferredActivity(filter, bestMatch, set,
+ intent.getComponent());
+ } else {
+ try {
+ AppGlobals.getPackageManager().setLastChosenActivity(intent,
+ intent.resolveTypeIfNeeded(getContentResolver()),
+ PackageManager.MATCH_DEFAULT_ONLY,
+ filter, bestMatch, intent.getComponent());
+ } catch (RemoteException re) {
+ Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
+ }
}
}
}
diff --git a/core/java/com/android/internal/app/RestrictionsPinActivity.java b/core/java/com/android/internal/app/RestrictionsPinActivity.java
index f8ce108..2112474 100644
--- a/core/java/com/android/internal/app/RestrictionsPinActivity.java
+++ b/core/java/com/android/internal/app/RestrictionsPinActivity.java
@@ -16,9 +16,7 @@
package com.android.internal.app;
-import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.os.Bundle;
import android.os.UserManager;
import android.text.Editable;
@@ -26,7 +24,8 @@ import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.WindowManager;
+import android.view.View.OnClickListener;
+import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -38,14 +37,15 @@ import com.android.internal.R;
* challenge for an existing PIN. The PIN is maintained by UserManager.
*/
public class RestrictionsPinActivity extends AlertActivity
- implements DialogInterface.OnClickListener, TextWatcher, OnEditorActionListener {
+ implements OnClickListener, TextWatcher, OnEditorActionListener {
protected UserManager mUserManager;
protected boolean mHasRestrictionsPin;
protected EditText mPinText;
protected TextView mPinErrorMessage;
- protected TextView mPinMessage;
+ private Button mOkButton;
+ private Button mCancelButton;
@Override
public void onCreate(Bundle icicle) {
@@ -59,19 +59,20 @@ public class RestrictionsPinActivity extends AlertActivity
protected void initUi() {
AlertController.AlertParams ap = mAlertParams;
- ap.mTitle = getString(R.string.restr_pin_enter_pin);
- ap.mPositiveButtonText = getString(R.string.ok);
- ap.mNegativeButtonText = getString(R.string.cancel);
- ap.mPositiveButtonListener = this;
- ap.mNegativeButtonListener = this;
+ ap.mTitle = getString(R.string.restr_pin_enter_admin_pin);
LayoutInflater inflater =
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ap.mView = inflater.inflate(R.layout.restrictions_pin_challenge, null);
- mPinMessage = (TextView) ap.mView.findViewById(R.id.pin_message);
- mPinText = (EditText) ap.mView.findViewById(R.id.pin_text);
mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message);
+ mPinText = (EditText) ap.mView.findViewById(R.id.pin_text);
+ mOkButton = (Button) ap.mView.findViewById(R.id.pin_ok_button);
+ mCancelButton = (Button) ap.mView.findViewById(R.id.pin_cancel_button);
+
mPinText.addTextChangedListener(this);
+
+ mOkButton.setOnClickListener(this);
+ mCancelButton.setOnClickListener(this);
}
protected boolean verifyingPin() {
@@ -84,8 +85,7 @@ public class RestrictionsPinActivity extends AlertActivity
setPositiveButtonState(false);
boolean hasPin = mUserManager.hasRestrictionsPin();
if (hasPin) {
- mPinMessage.setVisibility(View.GONE);
- mPinErrorMessage.setVisibility(View.GONE);
+ mPinErrorMessage.setVisibility(View.INVISIBLE);
mPinText.setOnEditorActionListener(this);
updatePinTimer(-1);
} else if (verifyingPin()) {
@@ -94,39 +94,37 @@ public class RestrictionsPinActivity extends AlertActivity
}
}
- private void setPositiveButtonState(boolean enabled) {
- mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(enabled);
+ protected void setPositiveButtonState(boolean enabled) {
+ mOkButton.setEnabled(enabled);
}
- private void updatePinTimer(int pinTimerMs) {
+ private boolean updatePinTimer(int pinTimerMs) {
if (pinTimerMs < 0) {
pinTimerMs = mUserManager.checkRestrictionsPin(null);
}
+ boolean enableInput;
if (pinTimerMs >= 200) {
- final int seconds = (pinTimerMs + 200) / 1000;
- final String formatString = getResources().getQuantityString(
- R.plurals.restr_pin_countdown,
- seconds);
- mPinErrorMessage.setText(String.format(formatString, seconds));
+ // Do the count down timer for less than a minute, otherwise just say try again later.
+ if (pinTimerMs <= 60000) {
+ final int seconds = (pinTimerMs + 200) / 1000;
+ final String formatString = getResources().getQuantityString(
+ R.plurals.restr_pin_countdown,
+ seconds);
+ mPinErrorMessage.setText(String.format(formatString, seconds));
+ } else {
+ mPinErrorMessage.setText(R.string.restr_pin_try_later);
+ }
+ enableInput = false;
mPinErrorMessage.setVisibility(View.VISIBLE);
- mPinText.setEnabled(false);
mPinText.setText("");
- setPositiveButtonState(false);
mPinText.postDelayed(mCountdownRunnable, Math.min(1000, pinTimerMs));
} else {
- mPinErrorMessage.setVisibility(View.INVISIBLE);
- mPinText.setEnabled(true);
- mPinText.setText("");
- }
- }
-
- public void onClick(DialogInterface dialog, int which) {
- setResult(RESULT_CANCELED);
- if (which == AlertDialog.BUTTON_POSITIVE) {
- performPositiveButtonAction();
- } else if (which == AlertDialog.BUTTON_NEGATIVE) {
- finish();
+ enableInput = true;
+ mPinErrorMessage.setText(R.string.restr_pin_incorrect);
}
+ mPinText.setEnabled(enableInput);
+ setPositiveButtonState(enableInput);
+ return enableInput;
}
protected void performPositiveButtonAction() {
@@ -135,7 +133,10 @@ public class RestrictionsPinActivity extends AlertActivity
setResult(RESULT_OK);
finish();
} else if (result >= 0) {
+ mPinErrorMessage.setText(R.string.restr_pin_incorrect);
+ mPinErrorMessage.setVisibility(View.VISIBLE);
updatePinTimer(result);
+ mPinText.setText("");
}
}
@@ -161,7 +162,20 @@ public class RestrictionsPinActivity extends AlertActivity
private Runnable mCountdownRunnable = new Runnable() {
public void run() {
- updatePinTimer(-1);
+ if (updatePinTimer(-1)) {
+ // If we are no longer counting down, clear the message.
+ mPinErrorMessage.setVisibility(View.INVISIBLE);
+ }
}
};
+
+ @Override
+ public void onClick(View v) {
+ if (v == mOkButton) {
+ performPositiveButtonAction();
+ } else if (v == mCancelButton) {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java b/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java
index 1d09292..f7fc6c6 100644
--- a/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java
+++ b/core/java/com/android/internal/app/RestrictionsPinSetupActivity.java
@@ -16,9 +16,7 @@
package com.android.internal.app;
-import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
import android.os.UserManager;
import android.text.Editable;
import android.text.TextUtils;
@@ -44,17 +42,13 @@ public class RestrictionsPinSetupActivity extends RestrictionsPinActivity {
ap.mTitle = getString(R.string.restr_pin_enter_pin);
ap.mPositiveButtonText = getString(R.string.ok);
ap.mNegativeButtonText = getString(R.string.cancel);
- ap.mPositiveButtonListener = this;
- ap.mNegativeButtonListener = this;
LayoutInflater inflater =
(LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ap.mView = inflater.inflate(R.layout.restrictions_pin_setup, null);
mPinText = (EditText) ap.mView.findViewById(R.id.pin_text);
- mPinMessage = (TextView) ap.mView.findViewById(R.id.pin_message);
mNewPinText = (EditText) ap.mView.findViewById(R.id.pin_new_text);
mConfirmPinText = (EditText) ap.mView.findViewById(R.id.pin_confirm_text);
- mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message);
mNewPinText.addTextChangedListener(this);
mConfirmPinText.addTextChangedListener(this);
@@ -72,19 +66,7 @@ public class RestrictionsPinSetupActivity extends RestrictionsPinActivity {
return false;
}
- private void setPositiveButtonState(boolean enabled) {
- mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(enabled);
- }
-
- public void onClick(DialogInterface dialog, int which) {
- setResult(RESULT_CANCELED);
- if (which == AlertDialog.BUTTON_POSITIVE) {
- performPositiveButtonAction();
- } else if (which == AlertDialog.BUTTON_NEGATIVE) {
- finish();
- }
- }
-
+ @Override
protected void performPositiveButtonAction() {
if (mHasRestrictionsPin) {
int result = mUserManager.checkRestrictionsPin(mPinText.getText().toString());
@@ -115,7 +97,6 @@ public class RestrictionsPinSetupActivity extends RestrictionsPinActivity {
boolean showError = !TextUtils.isEmpty(pin1) && !TextUtils.isEmpty(pin2);
// TODO: Check recovery email address as well
setPositiveButtonState(match);
- mPinErrorMessage.setVisibility((match || !showError) ? View.INVISIBLE : View.VISIBLE);
}
@Override