summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/ContextImpl.java17
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java16
-rw-r--r--core/java/android/bluetooth/BluetoothHeadsetClientCall.java25
-rw-r--r--core/java/android/content/Context.java15
-rw-r--r--core/java/android/hardware/camera2/params/LensShadingMap.java45
-rw-r--r--core/java/android/midi/IMidiListener.aidl26
-rw-r--r--core/java/android/midi/IMidiManager.aidl47
-rw-r--r--core/java/android/midi/MidiDevice.aidl19
-rw-r--r--core/java/android/midi/MidiDevice.java331
-rw-r--r--core/java/android/midi/MidiDeviceInfo.aidl19
-rw-r--r--core/java/android/midi/MidiDeviceInfo.java223
-rw-r--r--core/java/android/midi/MidiInputPort.java53
-rw-r--r--core/java/android/midi/MidiManager.java158
-rw-r--r--core/java/android/midi/MidiOutputPort.java42
-rw-r--r--core/java/android/midi/MidiPort.java43
-rw-r--r--core/java/android/midi/MidiReceiver.java30
-rw-r--r--core/java/android/midi/MidiSender.java28
-rw-r--r--core/java/android/midi/MidiUtils.java63
-rw-r--r--core/java/android/net/ConnectivityManager.java2
-rw-r--r--core/java/android/os/Debug.java3
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java18
-rw-r--r--core/java/android/provider/Settings.java2
-rw-r--r--core/java/android/speech/tts/ITextToSpeechCallback.aidl2
-rw-r--r--core/java/android/speech/tts/TextToSpeech.java4
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java79
-rw-r--r--core/java/android/speech/tts/UtteranceProgressListener.java19
-rw-r--r--core/java/android/text/StaticLayout.java364
-rw-r--r--core/java/android/util/Spline.java2
-rw-r--r--core/java/android/view/GLES20Canvas.java92
-rw-r--r--core/java/android/view/HardwareCanvas.java17
-rw-r--r--core/java/android/view/HardwareLayer.java2
-rw-r--r--core/java/android/view/RenderNode.java2
-rw-r--r--core/java/android/view/Surface.java1
-rw-r--r--core/java/android/view/View.java4
-rw-r--r--core/java/android/view/inputmethod/InputMethodSubtypeArray.java59
-rw-r--r--core/java/android/webkit/WebResourceResponse.java18
-rw-r--r--core/java/android/webkit/WebViewFactory.java8
-rw-r--r--core/java/android/widget/Editor.java2
38 files changed, 1518 insertions, 382 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2df35df..eadf5e9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -80,6 +80,8 @@ import android.media.projection.MediaProjectionManager;
import android.media.session.MediaSessionManager;
import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager;
+import android.midi.IMidiManager;
+import android.midi.MidiManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.EthernetManager;
@@ -92,6 +94,8 @@ import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
+import android.net.wifi.passpoint.IWifiPasspointManager;
+import android.net.wifi.passpoint.WifiPasspointManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.IWifiScanner;
@@ -603,6 +607,13 @@ class ContextImpl extends Context {
return new WifiManager(ctx.getOuterContext(), service);
}});
+ registerService(WIFI_PASSPOINT_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(WIFI_PASSPOINT_SERVICE);
+ IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
+ return new WifiPasspointManager(ctx.getOuterContext(), service);
+ }});
+
registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(WIFI_P2P_SERVICE);
@@ -768,6 +779,12 @@ class ContextImpl extends Context {
IBinder b = ServiceManager.getService(APPWIDGET_SERVICE);
return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
}});
+
+ registerService(MIDI_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ IBinder b = ServiceManager.getService(MIDI_SERVICE);
+ return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
+ }});
}
static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ead89b3..df6cc73 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -52,11 +52,15 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
+import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -1934,13 +1938,15 @@ public class DevicePolicyManager {
String alias) {
try {
final byte[] pemCert = Credentials.convertToPem(cert);
- return mService.installKeyPair(who, privKey.getEncoded(), pemCert, alias);
- } catch (CertificateException e) {
- Log.w(TAG, "Error encoding certificate", e);
- } catch (IOException e) {
- Log.w(TAG, "Error writing certificate", e);
+ final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm())
+ .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
+ return mService.installKeyPair(who, pkcs8Key, pemCert, alias);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ Log.w(TAG, "Failed to obtain private key material", e);
+ } catch (CertificateException | IOException e) {
+ Log.w(TAG, "Could not pem-encode certificate", e);
}
return false;
}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index a15bd97..7b5a045 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -61,6 +61,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
*/
public static final int CALL_STATE_TERMINATED = 7;
+ private final BluetoothDevice mDevice;
private final int mId;
private int mState;
private String mNumber;
@@ -70,8 +71,9 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
/**
* Creates BluetoothHeadsetClientCall instance.
*/
- public BluetoothHeadsetClientCall(int id, int state, String number, boolean multiParty,
- boolean outgoing) {
+ public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number,
+ boolean multiParty, boolean outgoing) {
+ mDevice = device;
mId = id;
mState = state;
mNumber = number != null ? number : "";
@@ -114,6 +116,15 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
}
/**
+ * Gets call's device.
+ *
+ * @return call device.
+ */
+ public BluetoothDevice getDevice() {
+ return mDevice;
+ }
+
+ /**
* Gets call's Id.
*
* @return call id.
@@ -161,7 +172,9 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
}
public String toString() {
- StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mId: ");
+ StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: ");
+ builder.append(mDevice);
+ builder.append(", mId: ");
builder.append(mId);
builder.append(", mState: ");
switch (mState) {
@@ -192,8 +205,9 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
new Parcelable.Creator<BluetoothHeadsetClientCall>() {
@Override
public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
- return new BluetoothHeadsetClientCall(in.readInt(), in.readInt(),
- in.readString(), in.readInt() == 1, in.readInt() == 1);
+ return new BluetoothHeadsetClientCall((BluetoothDevice)in.readParcelable(null),
+ in.readInt(), in.readInt(), in.readString(),
+ in.readInt() == 1, in.readInt() == 1);
}
@Override
@@ -204,6 +218,7 @@ public final class BluetoothHeadsetClientCall implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(mDevice, 0);
out.writeInt(mId);
out.writeInt(mState);
out.writeString(mNumber);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e6bb09f..015e1ec 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -146,12 +146,13 @@ public abstract class Context {
@IntDef(flag = true,
value = {
BIND_AUTO_CREATE,
- BIND_AUTO_CREATE,
BIND_DEBUG_UNBIND,
BIND_NOT_FOREGROUND,
BIND_ABOVE_CLIENT,
BIND_ALLOW_OOM_MANAGEMENT,
- BIND_WAIVE_PRIORITY
+ BIND_WAIVE_PRIORITY,
+ BIND_IMPORTANT,
+ BIND_ADJUST_WITH_ACTIVITY
})
@Retention(RetentionPolicy.SOURCE)
public @interface BindServiceFlags {}
@@ -2142,6 +2143,7 @@ public abstract class Context {
MEDIA_SESSION_SERVICE,
BATTERY_SERVICE,
JOB_SCHEDULER_SERVICE,
+ MIDI_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -2915,6 +2917,15 @@ public abstract class Context {
public static final String MEDIA_PROJECTION_SERVICE = "media_projection";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.midi.MidiManager} for accessing the MIDI service.
+ *
+ * @see #getSystemService
+ * @hide
+ */
+ public static final String MIDI_SERVICE = "midi";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/hardware/camera2/params/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
index 9bbc33a..13929b1 100644
--- a/core/java/android/hardware/camera2/params/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -238,6 +238,51 @@ public final class LensShadingMap {
return HashCodeHelpers.hashCode(mRows, mColumns, elemsHash);
}
+ /**
+ * Return the LensShadingMap as a string representation.
+ *
+ * <p> {@code "LensShadingMap{R:([%f, %f, ... %f], ... [%f, %f, ... %f]), G_even:([%f, %f, ...
+ * %f], ... [%f, %f, ... %f]), G_odd:([%f, %f, ... %f], ... [%f, %f, ... %f]), B:([%f, %f, ...
+ * %f], ... [%f, %f, ... %f])}"},
+ * where each {@code %f} represents one gain factor and each {@code [%f, %f, ... %f]} represents
+ * a row of the lens shading map</p>
+ *
+ * @return string representation of {@link LensShadingMap}
+ */
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ str.append("LensShadingMap{");
+
+ final String channelPrefix[] = {"R:(", "G_even:(", "G_odd:(", "B:("};
+
+ for (int ch = 0; ch < COUNT; ch++) {
+ str.append(channelPrefix[ch]);
+
+ for (int r = 0; r < mRows; r++) {
+ str.append("[");
+ for (int c = 0; c < mColumns; c++) {
+ float gain = getGainFactor(ch, c, r);
+ str.append(gain);
+ if (c < mColumns - 1) {
+ str.append(", ");
+ }
+ }
+ str.append("]");
+ if (r < mRows - 1) {
+ str.append(", ");
+ }
+ }
+
+ str.append(")");
+ if (ch < COUNT - 1) {
+ str.append(", ");
+ }
+ }
+
+ str.append("}");
+ return str.toString();
+ }
private final int mRows;
private final int mColumns;
diff --git a/core/java/android/midi/IMidiListener.aidl b/core/java/android/midi/IMidiListener.aidl
new file mode 100644
index 0000000..b650593
--- /dev/null
+++ b/core/java/android/midi/IMidiListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import android.midi.MidiDeviceInfo;
+
+/** @hide */
+oneway interface IMidiListener
+{
+ void onDeviceAdded(in MidiDeviceInfo device);
+ void onDeviceRemoved(in MidiDeviceInfo device);
+}
diff --git a/core/java/android/midi/IMidiManager.aidl b/core/java/android/midi/IMidiManager.aidl
new file mode 100644
index 0000000..7a9f887
--- /dev/null
+++ b/core/java/android/midi/IMidiManager.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import android.hardware.usb.UsbDevice;
+import android.midi.IMidiListener;
+import android.midi.MidiDevice;
+import android.midi.MidiDeviceInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface IMidiManager
+{
+ MidiDeviceInfo[] getDeviceList();
+
+ // for device creation & removal notifications
+ void registerListener(IBinder token, in IMidiListener listener);
+ void unregisterListener(IBinder token, in IMidiListener listener);
+
+ // for communicating with MIDI devices
+ ParcelFileDescriptor openDevice(IBinder token, in MidiDeviceInfo device);
+
+ // for implementing virtual MIDI devices
+ MidiDevice registerVirtualDevice(IBinder token, int numInputPorts, int numOutputPorts,
+ in Bundle properties);
+ void unregisterVirtualDevice(IBinder token, in MidiDeviceInfo device);
+
+ // for use by UsbAudioManager
+ void alsaDeviceAdded(int card, int device, in UsbDevice usbDevice);
+ void alsaDeviceRemoved(in UsbDevice usbDevice);
+}
diff --git a/core/java/android/midi/MidiDevice.aidl b/core/java/android/midi/MidiDevice.aidl
new file mode 100644
index 0000000..11bb497
--- /dev/null
+++ b/core/java/android/midi/MidiDevice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014, 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.midi;
+
+parcelable MidiDevice;
diff --git a/core/java/android/midi/MidiDevice.java b/core/java/android/midi/MidiDevice.java
new file mode 100644
index 0000000..e704ea0
--- /dev/null
+++ b/core/java/android/midi/MidiDevice.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * This class is used for sending and receiving data to and from an MIDI device
+ * Instances of this class are created by {@link MidiManager#openDevice}.
+ * This class can also be used to provide the implementation for a virtual device.
+ *
+ * This class implements Parcelable so it can be returned from MidiService when creating
+ * virtual MIDI devices.
+ *
+ * @hide
+ */
+public final class MidiDevice implements Parcelable {
+ private static final String TAG = "MidiDevice";
+
+ private final MidiDeviceInfo mDeviceInfo;
+ private ParcelFileDescriptor mParcelFileDescriptor;
+ private FileInputStream mInputStream;
+ private FileOutputStream mOutputStream;
+
+ // lazily populated lists of ports
+ private final MidiInputPort[] mInputPorts;
+ private final MidiOutputPort[] mOutputPorts;
+
+ // array of receiver lists, indexed by port number
+ private final ArrayList<MidiReceiver>[] mReceivers;
+
+ private int mReceiverCount; // total number of receivers for all ports
+
+ /**
+ * Minimum size of packed message as sent through our ParcelFileDescriptor
+ * 8 bytes for timestamp, 1 byte for port number and 1 to 3 bytes for message
+ * @hide
+ */
+ public static final int MIN_PACKED_MESSAGE_SIZE = 10;
+
+ /**
+ * Maximum size of packed message as sent through our ParcelFileDescriptor
+ * 8 bytes for timestamp, 1 byte for port number and 1 to 3 bytes for message
+ * @hide
+ */
+ public static final int MAX_PACKED_MESSAGE_SIZE = 12;
+
+ // This thread reads MIDI events from a socket and distributes them to the list of
+ // MidiReceivers attached to this device.
+ private final Thread mThread = new Thread() {
+ @Override
+ public void run() {
+ byte[] buffer = new byte[MAX_PACKED_MESSAGE_SIZE];
+ ArrayList<MidiReceiver> deadReceivers = new ArrayList<MidiReceiver>();
+
+ try {
+ while (true) {
+ // read next event
+ int count = mInputStream.read(buffer);
+ if (count < MIN_PACKED_MESSAGE_SIZE || count > MAX_PACKED_MESSAGE_SIZE) {
+ Log.e(TAG, "Number of bytes read out of range: " + count);
+ break;
+ }
+
+ int offset = getMessageOffset(buffer, count);
+ int size = getMessageSize(buffer, count);
+ long timestamp = getMessageTimeStamp(buffer, count);
+ int port = getMessagePortNumber(buffer, count);
+
+ synchronized (mReceivers) {
+ ArrayList<MidiReceiver> receivers = mReceivers[port];
+ if (receivers != null) {
+ for (int i = 0; i < receivers.size(); i++) {
+ MidiReceiver receiver = receivers.get(i);
+ try {
+ receivers.get(i).onPost(buffer, offset, size, timestamp);
+ } catch (IOException e) {
+ Log.e(TAG, "post failed");
+ deadReceivers.add(receiver);
+ }
+ }
+ // remove any receivers that failed
+ if (deadReceivers.size() > 0) {
+ for (MidiReceiver receiver: deadReceivers) {
+ receivers.remove(receiver);
+ mReceiverCount--;
+ }
+ deadReceivers.clear();
+ }
+ if (receivers.size() == 0) {
+ mReceivers[port] = null;
+ }
+ // exit if we have no receivers left
+ if (mReceiverCount == 0) {
+ break;
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "read failed");
+ }
+ }
+ };
+
+ /**
+ * MidiDevice should only be instantiated by MidiManager or MidiService
+ * @hide
+ */
+ public MidiDevice(MidiDeviceInfo deviceInfo, ParcelFileDescriptor pfd) {
+ mDeviceInfo = deviceInfo;
+ mParcelFileDescriptor = pfd;
+ int inputPorts = deviceInfo.getInputPortCount();
+ int outputPorts = deviceInfo.getOutputPortCount();
+ mInputPorts = new MidiInputPort[inputPorts];
+ mOutputPorts = new MidiOutputPort[outputPorts];
+ mReceivers = new ArrayList[outputPorts];
+ }
+
+ public MidiInputPort openInputPort(int portNumber) {
+ if (portNumber < 0 || portNumber >= mDeviceInfo.getInputPortCount()) {
+ throw new IllegalArgumentException("input port number out of range");
+ }
+ synchronized (mInputPorts) {
+ if (mInputPorts[portNumber] == null) {
+ mInputPorts[portNumber] = new MidiInputPort(mOutputStream, portNumber);
+ }
+ return mInputPorts[portNumber];
+ }
+ }
+
+ public MidiOutputPort openOutputPort(int portNumber) {
+ if (portNumber < 0 || portNumber >= mDeviceInfo.getOutputPortCount()) {
+ throw new IllegalArgumentException("output port number out of range");
+ }
+ synchronized (mOutputPorts) {
+ if (mOutputPorts[portNumber] == null) {
+ mOutputPorts[portNumber] = new MidiOutputPort(this, portNumber);
+ }
+ return mOutputPorts[portNumber];
+ }
+ }
+
+ /* package */ void connect(MidiReceiver receiver, int portNumber) {
+ synchronized (mReceivers) {
+ if (mReceivers[portNumber] == null) {
+ mReceivers[portNumber] = new ArrayList<MidiReceiver>();
+ }
+ mReceivers[portNumber].add(receiver);
+ if (mReceiverCount++ == 0) {
+ mThread.start();
+ }
+ }
+ }
+
+ /* package */ void disconnect(MidiReceiver receiver, int portNumber) {
+ synchronized (mReceivers) {
+ ArrayList<MidiReceiver> receivers = mReceivers[portNumber];
+ if (receivers != null && receivers.remove(receiver)) {
+ mReceiverCount--;
+ }
+ }
+ }
+
+ /* package */ boolean open() {
+ FileDescriptor fd = mParcelFileDescriptor.getFileDescriptor();
+ try {
+ mInputStream = new FileInputStream(fd);
+ } catch (Exception e) {
+ Log.e(TAG, "could not create mInputStream", e);
+ return false;
+ }
+
+ try {
+ mOutputStream = new FileOutputStream(fd);
+ } catch (Exception e) {
+ Log.e(TAG, "could not create mOutputStream", e);
+ return false;
+ }
+ return true;
+ }
+
+ void close() {
+ try {
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
+ if (mOutputStream != null) {
+ mOutputStream.close();
+ }
+ mParcelFileDescriptor.close();
+ } catch (IOException e) {
+ }
+ }
+
+ // returns our MidiDeviceInfo object, which describes this device
+ public MidiDeviceInfo getInfo() {
+ return mDeviceInfo;
+ }
+
+ @Override
+ public String toString() {
+ return ("MidiDevice: " + mDeviceInfo.toString() + " fd: " + mParcelFileDescriptor);
+ }
+
+ public static final Parcelable.Creator<MidiDevice> CREATOR =
+ new Parcelable.Creator<MidiDevice>() {
+ public MidiDevice createFromParcel(Parcel in) {
+ MidiDeviceInfo deviceInfo = (MidiDeviceInfo)in.readParcelable(null);
+ ParcelFileDescriptor pfd = (ParcelFileDescriptor)in.readParcelable(null);
+ return new MidiDevice(deviceInfo, pfd);
+ }
+
+ public MidiDevice[] newArray(int size) {
+ return new MidiDevice[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mDeviceInfo, flags);
+ parcel.writeParcelable(mParcelFileDescriptor, flags);
+ }
+
+ /**
+ * Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor
+ *
+ * message byte array contains variable length MIDI message.
+ * messageSize is size of variable length MIDI message
+ * timestamp is message timestamp to pack
+ * dest is buffer to pack into
+ * returns size of packed message
+ *
+ * @hide
+ */
+ public static int packMessage(byte[] message, int offset, int size, long timestamp,
+ int portNumber, byte[] dest) {
+ // pack variable length message first
+ System.arraycopy(message, offset, dest, 0, size);
+ int destOffset = size;
+ // timestamp takes 8 bytes
+ for (int i = 0; i < 8; i++) {
+ dest[destOffset++] = (byte)timestamp;
+ timestamp >>= 8;
+ }
+ // portNumber is last
+ dest[destOffset++] = (byte)portNumber;
+
+ return destOffset;
+ }
+
+ /**
+ * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * returns the offet of of MIDI message in packed buffer
+ *
+ * @hide
+ */
+ public static int getMessageOffset(byte[] buffer, int bufferLength) {
+ // message is at start of buffer
+ return 0;
+ }
+
+ /**
+ * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * returns size of MIDI message in packed buffer
+ *
+ * @hide
+ */
+ public static int getMessageSize(byte[] buffer, int bufferLength) {
+ // message length is total buffer length minus size of the timestamp and port number
+ return bufferLength - 9 /* (sizeof(timestamp) + sizeof(portNumber)) */;
+ }
+
+ /**
+ * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * unpacks timestamp from packed buffer
+ *
+ * @hide
+ */
+ public static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+ long timestamp = 0;
+
+ // timestamp follows variable length message data
+ int dataLength = getMessageSize(buffer, bufferLength);
+ for (int i = dataLength + 7; i >= dataLength; i--) {
+ // why can't Java deal with unsigned ints?
+ int b = buffer[i];
+ if (b < 0) b += 256;
+ timestamp = (timestamp << 8) | b;
+ }
+ return timestamp;
+ }
+
+ /**
+ * Utility function for unpacking a MIDI message to be sent through our ParcelFileDescriptor
+ * unpacks port number from packed buffer
+ *
+ * @hide
+ */
+ public static int getMessagePortNumber(byte[] buffer, int bufferLength) {
+ // timestamp follows variable length message data and timestamp
+ int dataLength = getMessageSize(buffer, bufferLength);
+ return buffer[dataLength + 8 /* sizeof(timestamp) */];
+ }
+}
diff --git a/core/java/android/midi/MidiDeviceInfo.aidl b/core/java/android/midi/MidiDeviceInfo.aidl
new file mode 100644
index 0000000..59be059
--- /dev/null
+++ b/core/java/android/midi/MidiDeviceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014, 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.midi;
+
+parcelable MidiDeviceInfo;
diff --git a/core/java/android/midi/MidiDeviceInfo.java b/core/java/android/midi/MidiDeviceInfo.java
new file mode 100644
index 0000000..239481b
--- /dev/null
+++ b/core/java/android/midi/MidiDeviceInfo.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information to describe a MIDI device.
+ * For now we only have information that can be retrieved easily for USB devices,
+ * but we will probably expand this in the future.
+ *
+ * This class is just an immutable object to encapsulate the MIDI device description.
+ * Use the MidiDevice class to actually communicate with devices.
+ *
+ * @hide
+ */
+public class MidiDeviceInfo implements Parcelable {
+
+ private static final String TAG = "MidiDeviceInfo";
+
+ public static final int TYPE_USB = 1;
+ public static final int TYPE_VIRTUAL = 2;
+
+ private final int mType; // USB or virtual
+ private final int mId; // unique ID generated by MidiService
+ private final int mInputPortCount;
+ private final int mOutputPortCount;
+ private final Bundle mProperties;
+
+ // used for USB devices only
+ private final int mAlsaCard;
+ private final int mAlsaDevice;
+
+ /**
+ * Bundle key for the device's manufacturer name property.
+ * Used with the {@link android.os.Bundle} returned by {@link #getProperties}.
+ * Matches the USB device manufacturer name string for USB MIDI devices.
+ */
+ public static final String PROPERTY_MANUFACTURER = "manufacturer";
+
+ /**
+ * Bundle key for the device's model name property.
+ * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+ * Matches the USB device product name string for USB MIDI devices.
+ */
+ public static final String PROPERTY_MODEL = "model";
+
+ /**
+ * Bundle key for the device's serial number property.
+ * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+ * Matches the USB device serial number for USB MIDI devices.
+ */
+ public static final String PROPERTY_SERIAL_NUMBER = "serial_number";
+
+ /**
+ * Bundle key for the device's {@link android.hardware.usb.UsbDevice}.
+ * Only set for USB MIDI devices.
+ * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+ */
+ public static final String PROPERTY_USB_DEVICE = "usb_device";
+
+ /**
+ * MidiDeviceInfo should only be instantiated by MidiService implementation
+ * @hide
+ */
+ public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
+ Bundle properties) {
+ mType = type;
+ mId = id;
+ mInputPortCount = numInputPorts;
+ mOutputPortCount = numOutputPorts;
+ mProperties = properties;
+ mAlsaCard = -1;
+ mAlsaDevice = -1;
+ }
+
+ /**
+ * MidiDeviceInfo should only be instantiated by MidiService implementation
+ * @hide
+ */
+ public MidiDeviceInfo(int type, int id, int numInputPorts, int numOutputPorts,
+ Bundle properties, int alsaCard, int alsaDevice) {
+ mType = type;
+ mId = id;
+ mInputPortCount = numInputPorts;
+ mOutputPortCount = numOutputPorts;
+ mProperties = properties;
+ mAlsaCard = alsaCard;
+ mAlsaDevice = alsaDevice;
+ }
+
+ /**
+ * Returns the type of the device.
+ *
+ * @return the device's type
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Returns the ID of the device.
+ * This ID is generated by the MIDI service and is not persistent across device unplugs.
+ *
+ * @return the device's ID
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Returns the device's number of input ports.
+ *
+ * @return the number of input ports
+ */
+ public int getInputPortCount() {
+ return mInputPortCount;
+ }
+
+ /**
+ * Returns the device's number of output ports.
+ *
+ * @return the number of output ports
+ */
+ public int getOutputPortCount() {
+ return mOutputPortCount;
+ }
+
+ /**
+ * Returns the {@link android.os.Bundle} containing the device's properties.
+ *
+ * @return the device's properties
+ */
+ public Bundle getProperties() {
+ return mProperties;
+ }
+
+ /**
+ * @hide
+ */
+ public int getAlsaCard() {
+ return mAlsaCard;
+ }
+
+ /**
+ * @hide
+ */
+ public int getAlsaDevice() {
+ return mAlsaDevice;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof MidiDeviceInfo) {
+ return (((MidiDeviceInfo)o).mId == mId);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return mId;
+ }
+
+ @Override
+ public String toString() {
+ return ("MidiDeviceInfo[mType=" + mType +
+ ",mInputPortCount=" + mInputPortCount +
+ ",mOutputPortCount=" + mOutputPortCount +
+ ",mProperties=" + mProperties +
+ ",mAlsaCard=" + mAlsaCard +
+ ",mAlsaDevice=" + mAlsaDevice);
+ }
+
+ public static final Parcelable.Creator<MidiDeviceInfo> CREATOR =
+ new Parcelable.Creator<MidiDeviceInfo>() {
+ public MidiDeviceInfo createFromParcel(Parcel in) {
+ int type = in.readInt();
+ int id = in.readInt();
+ int inputPorts = in.readInt();
+ int outputPorts = in.readInt();
+ Bundle properties = in.readBundle();
+ int card = in.readInt();
+ int device = in.readInt();
+ return new MidiDeviceInfo(type, id, inputPorts, outputPorts, properties, card, device);
+ }
+
+ public MidiDeviceInfo[] newArray(int size) {
+ return new MidiDeviceInfo[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mType);
+ parcel.writeInt(mId);
+ parcel.writeInt(mInputPortCount);
+ parcel.writeInt(mOutputPortCount);
+ parcel.writeBundle(mProperties);
+ parcel.writeInt(mAlsaCard);
+ parcel.writeInt(mAlsaDevice);
+ }
+}
diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java
new file mode 100644
index 0000000..583c367
--- /dev/null
+++ b/core/java/android/midi/MidiInputPort.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * This class is used for sending data to a port on a MIDI device
+ *
+ * @hide
+ */
+public final class MidiInputPort extends MidiPort implements MidiReceiver {
+
+ private final FileOutputStream mOutputStream;
+ // buffer to use for sending messages out our output stream
+ private final byte[] mBuffer = new byte[MidiDevice.MAX_PACKED_MESSAGE_SIZE];
+
+ /* package */ MidiInputPort(FileOutputStream outputStream, int portNumber) {
+ super(portNumber);
+ mOutputStream = outputStream;
+ }
+
+ /**
+ * Writes a MIDI message to the input port
+ *
+ * @param msg message bytes
+ * @param offset offset of first byte of the message in msg array
+ * @param count size of the message in bytes
+ * @param timestamp future time to post the message
+ */
+ public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ synchronized (mBuffer) {
+ int length = MidiDevice.packMessage(msg, offset, count, timestamp, mPortNumber,
+ mBuffer);
+ mOutputStream.write(mBuffer, 0, length);
+ }
+ }
+}
diff --git a/core/java/android/midi/MidiManager.java b/core/java/android/midi/MidiManager.java
new file mode 100644
index 0000000..f4d1918
--- /dev/null
+++ b/core/java/android/midi/MidiManager.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * This class is the public application interface to the MIDI service.
+ *
+ * <p>You can obtain an instance of this class by calling
+ * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
+ *
+ * {@samplecode
+ * MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);}
+ * @hide
+ */
+public class MidiManager {
+ private static final String TAG = "MidiManager";
+
+ private final Context mContext;
+ private final IMidiManager mService;
+ private final IBinder mToken = new Binder();
+
+ private HashMap<DeviceCallback,DeviceListener> mDeviceListeners =
+ new HashMap<DeviceCallback,DeviceListener>();
+
+ // Binder stub for receiving device notifications from MidiService
+ private class DeviceListener extends IMidiListener.Stub {
+ private DeviceCallback mCallback;
+
+ public DeviceListener(DeviceCallback callback) {
+ mCallback = callback;
+ }
+
+ public void onDeviceAdded(MidiDeviceInfo device) {
+ mCallback.onDeviceAdded(device);
+ }
+
+ public void onDeviceRemoved(MidiDeviceInfo device) {
+ mCallback.onDeviceRemoved(device);
+ }
+ }
+
+ // Callback interface clients to receive Device added and removed notifications
+ public interface DeviceCallback {
+ void onDeviceAdded(MidiDeviceInfo device);
+ void onDeviceRemoved(MidiDeviceInfo device);
+ }
+
+ /**
+ * @hide
+ */
+ public MidiManager(Context context, IMidiManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ // Used by clients to register for Device added and removed notifications
+ public void registerDeviceCallback(DeviceCallback callback) {
+ DeviceListener deviceListener = new DeviceListener(callback);
+ try {
+ mService.registerListener(mToken, deviceListener);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in registerDeviceListener");
+ return;
+ }
+ mDeviceListeners.put(callback, deviceListener);
+ }
+
+ // Used by clients to unregister for device added and removed notifications
+ public void unregisterDeviceCallback(DeviceCallback callback) {
+ DeviceListener deviceListener = mDeviceListeners.remove(callback);
+ if (deviceListener != null) {
+ try {
+ mService.unregisterListener(mToken, deviceListener);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in unregisterDeviceListener");
+ }
+ }
+ }
+
+ public MidiDeviceInfo[] getDeviceList() {
+ try {
+ return mService.getDeviceList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getDeviceList");
+ return new MidiDeviceInfo[0];
+ }
+ }
+
+ // Use this if you want to communicate with a MIDI device.
+ public MidiDevice openDevice(MidiDeviceInfo deviceInfo) {
+ try {
+ ParcelFileDescriptor pfd = mService.openDevice(mToken, deviceInfo);
+ if (pfd == null) {
+ Log.e(TAG, "could not open device " + deviceInfo);
+ return null;
+ }
+ MidiDevice device = new MidiDevice(deviceInfo, pfd);
+ if (device.open()) {
+ Log.d(TAG, "openDevice returning " + device);
+ return device;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openDevice");
+ }
+ return null;
+ }
+
+ // Use this if you want to register and implement a virtual device.
+ // The MidiDevice returned by this method is the proxy you use to implement the device.
+ public MidiDevice createVirtualDevice(int numInputPorts, int numOutputPorts,
+ Bundle properties) {
+ try {
+ MidiDevice device = mService.registerVirtualDevice(mToken,
+ numInputPorts, numOutputPorts, properties);
+ if (device != null && !device.open()) {
+ device = null;
+ }
+ return device;
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in createVirtualDevice");
+ return null;
+ }
+ }
+
+ public void closeVirtualDevice(MidiDevice device) {
+ try {
+ device.close();
+ mService.unregisterVirtualDevice(mToken, device.getInfo());
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in unregisterVirtualDevice");
+ }
+ }
+}
diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java
new file mode 100644
index 0000000..69a33cb
--- /dev/null
+++ b/core/java/android/midi/MidiOutputPort.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import java.io.FileInputStream;
+
+/**
+ * This class is used for receiving data to a port on a MIDI device
+ *
+ * @hide
+ */
+public final class MidiOutputPort extends MidiPort implements MidiSender {
+
+ private final MidiDevice mDevice;
+
+ /* package */ MidiOutputPort(MidiDevice device, int portNumber) {
+ super(portNumber);
+ mDevice = device;
+ }
+
+ public void connect(MidiReceiver receiver) {
+ mDevice.connect(receiver, mPortNumber);
+ }
+
+ public void disconnect(MidiReceiver receiver) {
+ mDevice.disconnect(receiver, mPortNumber);
+ }
+}
diff --git a/core/java/android/midi/MidiPort.java b/core/java/android/midi/MidiPort.java
new file mode 100644
index 0000000..e94f62d
--- /dev/null
+++ b/core/java/android/midi/MidiPort.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * This class represents a MIDI input or output port
+ *
+ * @hide
+ */
+public class MidiPort {
+
+ protected final int mPortNumber;
+
+ /* package */ MidiPort(int portNumber) {
+ mPortNumber = portNumber;
+ }
+
+ /**
+ * Returns the port number of this port
+ *
+ * @return the port's port number
+ */
+ public int getPortNumber() {
+ return mPortNumber;
+ }
+}
diff --git a/core/java/android/midi/MidiReceiver.java b/core/java/android/midi/MidiReceiver.java
new file mode 100644
index 0000000..1101105
--- /dev/null
+++ b/core/java/android/midi/MidiReceiver.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import java.io.IOException;
+
+/**
+ * Interface for receiving events from a MIDI device.
+ *
+ * @hide
+ */
+public interface MidiReceiver {
+ // NOTE: the msg array is only valid within the context of this call.
+ // the byte array may get reused by the MIDI device for the next message.
+ public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException;
+}
diff --git a/core/java/android/midi/MidiSender.java b/core/java/android/midi/MidiSender.java
new file mode 100644
index 0000000..cba7079
--- /dev/null
+++ b/core/java/android/midi/MidiSender.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+/**
+ * Interface provided by a device to allow attaching
+ * MidiReceivers to a MIDI device.
+ *
+ * @hide
+ */
+public interface MidiSender {
+ public void connect(MidiReceiver receiver);
+ public void disconnect(MidiReceiver receiver);
+}
diff --git a/core/java/android/midi/MidiUtils.java b/core/java/android/midi/MidiUtils.java
new file mode 100644
index 0000000..f80e83a
--- /dev/null
+++ b/core/java/android/midi/MidiUtils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 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.midi;
+
+import android.util.Log;
+
+/**
+ * Class containing miscellaneous MIDI utilities.
+ *
+ * @hide
+ */
+public final class MidiUtils {
+ private static final String TAG = "MidiUtils";
+
+ /**
+ * Returns data size of a MIDI message based on the message's command byte
+ * @param b the message command byte
+ * @return the message's data length
+ */
+ public static int getMessageDataSize(byte b) {
+ switch (b & 0xF0) {
+ case 0x80:
+ case 0x90:
+ case 0xA0:
+ case 0xB0:
+ case 0xE0:
+ return 2;
+ case 0xC0:
+ case 0xD0:
+ return 1;
+ case 0xF0:
+ switch (b & 0x0F) {
+ case 0x00:
+ Log.e(TAG, "System Exclusive not supported yet");
+ return -1;
+ case 0x01:
+ case 0x03:
+ return 1;
+ case 0x02:
+ return 2;
+ default:
+ return 0;
+ }
+ default:
+ Log.e(TAG, "unknown MIDI command " + b);
+ return -1;
+ }
+ }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 17ee494..865e4a5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -504,6 +504,8 @@ public class ConnectivityManager {
return "MOBILE_EMERGENCY";
case TYPE_PROXY:
return "PROXY";
+ case TYPE_VPN:
+ return "VPN";
default:
return Integer.toString(type);
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index b8178b4..e5f0153 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1286,7 +1286,10 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* + icount.globalMethodInvocations());
* }
* </pre>
+ *
+ * @deprecated Instruction counting is no longer supported.
*/
+ @Deprecated
public static class InstructionCount {
private static final int NUM_INSTR =
OpcodeInfo.MAXIMUM_PACKED_VALUE + 1;
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index c6b2151..4e8ec89 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -395,10 +395,17 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
* connected to each other. The two sockets are indistinguishable.
*/
public static ParcelFileDescriptor[] createSocketPair() throws IOException {
+ return createSocketPair(SOCK_STREAM);
+ }
+
+ /**
+ * @hide
+ */
+ public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
try {
final FileDescriptor fd0 = new FileDescriptor();
final FileDescriptor fd1 = new FileDescriptor();
- Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fd0),
new ParcelFileDescriptor(fd1) };
@@ -417,11 +424,18 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
* This can also be used to detect remote crashes.
*/
public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
+ return createReliableSocketPair(SOCK_STREAM);
+ }
+
+ /**
+ * @hide
+ */
+ public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
try {
final FileDescriptor[] comm = createCommSocketPair();
final FileDescriptor fd0 = new FileDescriptor();
final FileDescriptor fd1 = new FileDescriptor();
- Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ Os.socketpair(AF_UNIX, type, 0, fd0, fd1);
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fd0, comm[0]),
new ParcelFileDescriptor(fd1, comm[1]) };
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 555f64c..df2196e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -308,7 +308,7 @@ public final class Settings {
/**
* Activity Action: Show settings to allow configuration of
- * cast endpoints.
+ * {@link android.media.routing.MediaRouteService media route providers}.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
* safeguard against this.
diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index 899515f..d785c3f 100644
--- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -40,7 +40,7 @@ oneway interface ITextToSpeechCallback {
*
* @param utteranceId Unique id identifying synthesis request.
*/
- void onStop(String utteranceId);
+ void onStop(String utteranceId, boolean isStarted);
/**
* Tells the client that the synthesis has failed.
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index c59ca8a..06e9ce0 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -2066,10 +2066,10 @@ public class TextToSpeech {
private boolean mEstablished;
private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
- public void onStop(String utteranceId) throws RemoteException {
+ public void onStop(String utteranceId, boolean isStarted) throws RemoteException {
UtteranceProgressListener listener = mUtteranceProgressListener;
if (listener != null) {
- listener.onDone(utteranceId);
+ listener.onStop(utteranceId, isStarted);
}
};
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 9bb7f02..02c9a36 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -455,10 +455,37 @@ public abstract class TextToSpeechService extends Service {
private class SynthHandler extends Handler {
private SpeechItem mCurrentSpeechItem = null;
+ private ArrayList<Object> mFlushedObjects = new ArrayList<Object>();
+ private boolean mFlushAll;
+
public SynthHandler(Looper looper) {
super(looper);
}
+ private void startFlushingSpeechItems(Object callerIdentity) {
+ synchronized (mFlushedObjects) {
+ if (callerIdentity == null) {
+ mFlushAll = true;
+ } else {
+ mFlushedObjects.add(callerIdentity);
+ }
+ }
+ }
+ private void endFlushingSpeechItems(Object callerIdentity) {
+ synchronized (mFlushedObjects) {
+ if (callerIdentity == null) {
+ mFlushAll = false;
+ } else {
+ mFlushedObjects.remove(callerIdentity);
+ }
+ }
+ }
+ private boolean isFlushed(SpeechItem speechItem) {
+ synchronized (mFlushedObjects) {
+ return mFlushAll || mFlushedObjects.contains(speechItem.getCallerIdentity());
+ }
+ }
+
private synchronized SpeechItem getCurrentSpeechItem() {
return mCurrentSpeechItem;
}
@@ -522,9 +549,13 @@ public abstract class TextToSpeechService extends Service {
Runnable runnable = new Runnable() {
@Override
public void run() {
- setCurrentSpeechItem(speechItem);
- speechItem.play();
- setCurrentSpeechItem(null);
+ if (isFlushed(speechItem)) {
+ speechItem.stop();
+ } else {
+ setCurrentSpeechItem(speechItem);
+ speechItem.play();
+ setCurrentSpeechItem(null);
+ }
}
};
Message msg = Message.obtain(this, runnable);
@@ -552,12 +583,14 @@ public abstract class TextToSpeechService extends Service {
*
* Called on a service binder thread.
*/
- public int stopForApp(Object callerIdentity) {
+ public int stopForApp(final Object callerIdentity) {
if (callerIdentity == null) {
return TextToSpeech.ERROR;
}
- removeCallbacksAndMessages(callerIdentity);
+ // Flush pending messages from callerIdentity
+ startFlushingSpeechItems(callerIdentity);
+
// This stops writing data to the file / or publishing
// items to the audio playback handler.
//
@@ -573,20 +606,39 @@ public abstract class TextToSpeechService extends Service {
// Remove any enqueued audio too.
mAudioPlaybackHandler.stopForApp(callerIdentity);
+ // Stop flushing pending messages
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ endFlushingSpeechItems(callerIdentity);
+ }
+ };
+ sendMessage(Message.obtain(this, runnable));
return TextToSpeech.SUCCESS;
}
public int stopAll() {
+ // Order to flush pending messages
+ startFlushingSpeechItems(null);
+
// Stop the current speech item unconditionally .
SpeechItem current = setCurrentSpeechItem(null);
if (current != null) {
current.stop();
}
- // Remove all other items from the queue.
- removeCallbacksAndMessages(null);
// Remove all pending playback as well.
mAudioPlaybackHandler.stop();
+ // Message to stop flushing pending messages
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ endFlushingSpeechItems(null);
+ }
+ };
+ sendMessage(Message.obtain(this, runnable));
+
+
return TextToSpeech.SUCCESS;
}
}
@@ -698,7 +750,6 @@ public abstract class TextToSpeechService extends Service {
return mCallerIdentity;
}
-
public int getCallerUid() {
return mCallerUid;
}
@@ -752,6 +803,10 @@ public abstract class TextToSpeechService extends Service {
protected synchronized boolean isStopped() {
return mStopped;
}
+
+ protected synchronized boolean isStarted() {
+ return mStarted;
+ }
}
/**
@@ -777,7 +832,7 @@ public abstract class TextToSpeechService extends Service {
public void dispatchOnStop() {
final String utteranceId = getUtteranceId();
if (utteranceId != null) {
- mCallbacks.dispatchOnStop(getCallerIdentity(), utteranceId);
+ mCallbacks.dispatchOnStop(getCallerIdentity(), utteranceId, isStarted());
}
}
@@ -940,6 +995,8 @@ public abstract class TextToSpeechService extends Service {
// turn implies that synthesis would not have started.
synthesisCallback.stop();
TextToSpeechService.this.onStop();
+ } else {
+ dispatchOnStop();
}
}
@@ -1345,11 +1402,11 @@ public abstract class TextToSpeechService extends Service {
}
}
- public void dispatchOnStop(Object callerIdentity, String utteranceId) {
+ public void dispatchOnStop(Object callerIdentity, String utteranceId, boolean started) {
ITextToSpeechCallback cb = getCallbackFor(callerIdentity);
if (cb == null) return;
try {
- cb.onStop(utteranceId);
+ cb.onStop(utteranceId, started);
} catch (RemoteException e) {
Log.e(TAG, "Callback onStop failed: " + e);
}
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
index 6769794..9eb22ef 100644
--- a/core/java/android/speech/tts/UtteranceProgressListener.java
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -60,6 +60,20 @@ public abstract class UtteranceProgressListener {
}
/**
+ * Called when an utterance has been stopped while in progress or flushed from the
+ * synthesis queue. This can happen if client calls {@link TextToSpeech#stop()}
+ * or use {@link TextToSpeech#QUEUE_FLUSH} as an argument in
+ * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
+ *
+ * @param utteranceId the utterance ID of the utterance.
+ * @param isStarted If true, then utterance was interrupted while being synthesized
+ * and it's output is incomplete. If it's false, then utterance was flushed
+ * before the synthesis started.
+ */
+ public void onStop(String utteranceId, boolean isStarted) {
+ }
+
+ /**
* Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
* progress listener.
*
@@ -83,6 +97,11 @@ public abstract class UtteranceProgressListener {
// Left unimplemented, has no equivalent in the old
// API.
}
+
+ @Override
+ public void onStop(String utteranceId, boolean isStarted) {
+ listener.onUtteranceCompleted(utteranceId);
+ }
};
}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 74b7b69..9fdf88d 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -28,6 +28,8 @@ import android.util.Log;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
+import java.util.Arrays;
+
/**
* StaticLayout is a Layout for text that will not be edited after it
* is laid out. Use {@link DynamicLayout} for text that may change.
@@ -161,7 +163,12 @@ public class StaticLayout extends Layout {
float spacingadd, boolean includepad,
boolean trackpad, float ellipsizedWidth,
TextUtils.TruncateAt ellipsize) {
- int[] breakOpp = null;
+ LineBreaks lineBreaks = new LineBreaks();
+ // store span end locations
+ int[] spanEndCache = new int[4];
+ // store fontMetrics per span range
+ // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
+ int[] fmCache = new int[4 * 4];
final String localeLanguageTag = paint.getTextLocale().toLanguageTag();
mLineCount = 0;
@@ -186,7 +193,7 @@ public class StaticLayout extends Layout {
else
paraEnd++;
- int firstWidthLineLimit = mLineCount + 1;
+ int firstWidthLineCount = 1;
int firstWidth = outerWidth;
int restWidth = outerWidth;
@@ -204,9 +211,8 @@ public class StaticLayout extends Layout {
// leading margin spans, not just this particular one
if (lms instanceof LeadingMarginSpan2) {
LeadingMarginSpan2 lms2 = (LeadingMarginSpan2) lms;
- int lmsFirstLine = getLineForOffset(spanned.getSpanStart(lms2));
- firstWidthLineLimit = Math.max(firstWidthLineLimit,
- lmsFirstLine + lms2.getLeadingMarginLineCount());
+ firstWidthLineCount = Math.max(firstWidthLineCount,
+ lms2.getLeadingMarginLineCount());
}
}
@@ -242,34 +248,23 @@ public class StaticLayout extends Layout {
int dir = measured.mDir;
boolean easy = measured.mEasy;
- breakOpp = nLineBreakOpportunities(localeLanguageTag, chs, paraEnd - paraStart, breakOpp);
- int breakOppIndex = 0;
-
- int width = firstWidth;
-
- float w = 0;
- // here is the offset of the starting character of the line we are currently measuring
- int here = paraStart;
-
- // ok is a character offset located after a word separator (space, tab, number...) where
- // we would prefer to cut the current line. Equals to here when no such break was found.
- int ok = paraStart;
- float okWidth = w;
- int okAscent = 0, okDescent = 0, okTop = 0, okBottom = 0;
-
- // fit is a character offset such that the [here, fit[ range fits in the allowed width.
- // We will cut the line there if no ok position is found.
- int fit = paraStart;
- float fitWidth = w;
- int fitAscent = 0, fitDescent = 0, fitTop = 0, fitBottom = 0;
- // same as fitWidth but not including any trailing whitespace
- float fitWidthGraphing = w;
-
- boolean hasTabOrEmoji = false;
- boolean hasTab = false;
- TabStops tabStops = null;
-
+ // measurement has to be done before performing line breaking
+ // but we don't want to recompute fontmetrics or span ranges the
+ // second time, so we cache those and then use those stored values
+ int fmCacheCount = 0;
+ int spanEndCacheCount = 0;
for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
+ if (fmCacheCount * 4 >= fmCache.length) {
+ int[] grow = new int[fmCacheCount * 4 * 2];
+ System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
+ fmCache = grow;
+ }
+
+ if (spanEndCacheCount >= spanEndCache.length) {
+ int[] grow = new int[spanEndCacheCount * 2];
+ System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
+ spanEndCache = grow;
+ }
if (spanned == null) {
spanEnd = paraEnd;
@@ -285,201 +280,106 @@ public class StaticLayout extends Layout {
measured.addStyleRun(paint, spans, spanLen, fm);
}
- int fmTop = fm.top;
- int fmBottom = fm.bottom;
- int fmAscent = fm.ascent;
- int fmDescent = fm.descent;
-
- for (int j = spanStart; j < spanEnd; j++) {
- char c = chs[j - paraStart];
-
- if (c == CHAR_NEW_LINE) {
- // intentionally left empty
- } else if (c == CHAR_TAB) {
- if (hasTab == false) {
- hasTab = true;
- hasTabOrEmoji = true;
- if (spanned != null) {
- // First tab this para, check for tabstops
- TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
- paraEnd, TabStopSpan.class);
- if (spans.length > 0) {
- tabStops = new TabStops(TAB_INCREMENT, spans);
- }
- }
- }
- if (tabStops != null) {
- w = tabStops.nextTab(w);
- } else {
- w = TabStops.nextDefaultStop(w, TAB_INCREMENT);
- }
- } else if (c >= CHAR_FIRST_HIGH_SURROGATE && c <= CHAR_LAST_LOW_SURROGATE
- && j + 1 < spanEnd) {
- int emoji = Character.codePointAt(chs, j - paraStart);
-
- if (emoji >= MIN_EMOJI && emoji <= MAX_EMOJI) {
- Bitmap bm = EMOJI_FACTORY.getBitmapFromAndroidPua(emoji);
-
- if (bm != null) {
- Paint whichPaint;
-
- if (spanned == null) {
- whichPaint = paint;
- } else {
- whichPaint = mWorkPaint;
- }
-
- float wid = bm.getWidth() * -whichPaint.ascent() / bm.getHeight();
-
- w += wid;
- hasTabOrEmoji = true;
- j++;
- } else {
- w += widths[j - paraStart];
- }
- } else {
- w += widths[j - paraStart];
- }
- } else {
- w += widths[j - paraStart];
+ // the order of storage here (top, bottom, ascent, descent) has to match the code below
+ // where these values are retrieved
+ fmCache[fmCacheCount * 4 + 0] = fm.top;
+ fmCache[fmCacheCount * 4 + 1] = fm.bottom;
+ fmCache[fmCacheCount * 4 + 2] = fm.ascent;
+ fmCache[fmCacheCount * 4 + 3] = fm.descent;
+ fmCacheCount++;
+
+ spanEndCache[spanEndCacheCount] = spanEnd;
+ spanEndCacheCount++;
+ }
+
+ // tab stop locations
+ int[] variableTabStops = null;
+ if (spanned != null) {
+ TabStopSpan[] spans = getParagraphSpans(spanned, paraStart,
+ paraEnd, TabStopSpan.class);
+ if (spans.length > 0) {
+ int[] stops = new int[spans.length];
+ for (int i = 0; i < spans.length; i++) {
+ stops[i] = spans[i].getTabStop();
}
+ Arrays.sort(stops, 0, stops.length);
+ variableTabStops = stops;
+ }
+ }
- boolean isSpaceOrTab = c == CHAR_SPACE || c == CHAR_TAB || c == CHAR_ZWSP;
+ int breakCount = nComputeLineBreaks(localeLanguageTag, chs, widths, paraEnd - paraStart, firstWidth,
+ firstWidthLineCount, restWidth, variableTabStops, TAB_INCREMENT, false, lineBreaks,
+ lineBreaks.breaks, lineBreaks.widths, lineBreaks.flags, lineBreaks.breaks.length);
- if (w <= width || isSpaceOrTab) {
- fitWidth = w;
- if (!isSpaceOrTab) {
- fitWidthGraphing = w;
- }
- fit = j + 1;
-
- if (fmTop < fitTop)
- fitTop = fmTop;
- if (fmAscent < fitAscent)
- fitAscent = fmAscent;
- if (fmDescent > fitDescent)
- fitDescent = fmDescent;
- if (fmBottom > fitBottom)
- fitBottom = fmBottom;
-
- while (breakOpp[breakOppIndex] != -1
- && breakOpp[breakOppIndex] < j - paraStart + 1) {
- breakOppIndex++;
- }
- boolean isLineBreak = breakOppIndex < breakOpp.length &&
- breakOpp[breakOppIndex] == j - paraStart + 1;
-
- if (isLineBreak) {
- okWidth = fitWidthGraphing;
- ok = j + 1;
-
- if (fitTop < okTop)
- okTop = fitTop;
- if (fitAscent < okAscent)
- okAscent = fitAscent;
- if (fitDescent > okDescent)
- okDescent = fitDescent;
- if (fitBottom > okBottom)
- okBottom = fitBottom;
- }
- } else {
- int endPos;
- int above, below, top, bottom;
- float currentTextWidth;
-
- if (ok != here) {
- endPos = ok;
- above = okAscent;
- below = okDescent;
- top = okTop;
- bottom = okBottom;
- currentTextWidth = okWidth;
- } else if (fit != here) {
- endPos = fit;
- above = fitAscent;
- below = fitDescent;
- top = fitTop;
- bottom = fitBottom;
- currentTextWidth = fitWidth;
- } else {
- // must make progress, so take next character
- endPos = here + 1;
- // but to deal properly with clusters
- // take all zero width characters following that
- while (endPos < spanEnd && widths[endPos - paraStart] == 0) {
- endPos++;
- }
- above = fmAscent;
- below = fmDescent;
- top = fmTop;
- bottom = fmBottom;
- currentTextWidth = widths[here - paraStart];
- }
+ int[] breaks = lineBreaks.breaks;
+ float[] lineWidths = lineBreaks.widths;
+ boolean[] flags = lineBreaks.flags;
- int ellipseEnd = endPos;
- if (mMaximumVisibleLineCount == 1 && ellipsize == TextUtils.TruncateAt.MIDDLE) {
- ellipseEnd = paraEnd;
- }
- v = out(source, here, ellipseEnd,
- above, below, top, bottom,
- v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, hasTabOrEmoji,
- needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
- chs, widths, paraStart, ellipsize, ellipsizedWidth,
- currentTextWidth, paint, true);
-
- here = endPos;
- j = here - 1; // restart j-span loop from here, compensating for the j++
- ok = fit = here;
- w = 0;
- fitWidthGraphing = w;
- fitAscent = fitDescent = fitTop = fitBottom = 0;
- okAscent = okDescent = okTop = okBottom = 0;
-
- if (--firstWidthLineLimit <= 0) {
- width = restWidth;
- }
+ // here is the offset of the starting character of the line we are currently measuring
+ int here = paraStart;
- if (here < spanStart) {
- // The text was cut before the beginning of the current span range.
- // Exit the span loop, and get spanStart to start over from here.
- measured.setPos(here);
- spanEnd = here;
- break;
- }
+ int fmTop = 0, fmBottom = 0, fmAscent = 0, fmDescent = 0;
+ int fmCacheIndex = 0;
+ int spanEndCacheIndex = 0;
+ int breakIndex = 0;
+ for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
+ // retrieve end of span
+ spanEnd = spanEndCache[spanEndCacheIndex++];
+
+ // retrieve cached metrics, order matches above
+ fm.top = fmCache[fmCacheIndex * 4 + 0];
+ fm.bottom = fmCache[fmCacheIndex * 4 + 1];
+ fm.ascent = fmCache[fmCacheIndex * 4 + 2];
+ fm.descent = fmCache[fmCacheIndex * 4 + 3];
+ fmCacheIndex++;
+
+ if (fm.top < fmTop) {
+ fmTop = fm.top;
+ }
+ if (fm.ascent < fmAscent) {
+ fmAscent = fm.ascent;
+ }
+ if (fm.descent > fmDescent) {
+ fmDescent = fm.descent;
+ }
+ if (fm.bottom > fmBottom) {
+ fmBottom = fm.bottom;
+ }
- if (mLineCount >= mMaximumVisibleLineCount) {
- return;
- }
- }
+ // skip breaks ending before current span range
+ while (breakIndex < breakCount && paraStart + breaks[breakIndex] < spanStart) {
+ breakIndex++;
}
- }
- if (paraEnd != here && mLineCount < mMaximumVisibleLineCount) {
- if ((fitTop | fitBottom | fitDescent | fitAscent) == 0) {
- paint.getFontMetricsInt(fm);
+ while (breakIndex < breakCount && paraStart + breaks[breakIndex] <= spanEnd) {
+ int endPos = paraStart + breaks[breakIndex];
+
+ v = out(source, here, endPos,
+ fmAscent, fmDescent, fmTop, fmBottom,
+ v, spacingmult, spacingadd, chooseHt,chooseHtv, fm, flags[breakIndex],
+ needMultiply, chdirs, dir, easy, bufEnd, includepad, trackpad,
+ chs, widths, paraStart, ellipsize, ellipsizedWidth,
+ lineWidths[breakIndex], paint, true);
+
+ if (endPos < spanEnd) {
+ // preserve metrics for current span
+ fmTop = fm.top;
+ fmBottom = fm.bottom;
+ fmAscent = fm.ascent;
+ fmDescent = fm.descent;
+ } else {
+ fmTop = fmBottom = fmAscent = fmDescent = 0;
+ }
- fitTop = fm.top;
- fitBottom = fm.bottom;
- fitAscent = fm.ascent;
- fitDescent = fm.descent;
- }
+ here = endPos;
+ breakIndex++;
- // Log.e("text", "output rest " + here + " to " + end);
-
- v = out(source,
- here, paraEnd, fitAscent, fitDescent,
- fitTop, fitBottom,
- v,
- spacingmult, spacingadd, chooseHt,
- chooseHtv, fm, hasTabOrEmoji,
- needMultiply, chdirs, dir, easy, bufEnd,
- includepad, trackpad, chs,
- widths, paraStart, ellipsize,
- ellipsizedWidth, w, paint, paraEnd != bufEnd);
+ if (mLineCount >= mMaximumVisibleLineCount) {
+ return;
+ }
+ }
}
- paraStart = paraEnd;
-
if (paraEnd == bufEnd)
break;
}
@@ -488,7 +388,7 @@ public class StaticLayout extends Layout {
mLineCount < mMaximumVisibleLineCount) {
// Log.e("text", "output last " + bufEnd);
- measured.setPara(source, bufStart, bufEnd, textDir);
+ measured.setPara(source, bufEnd, bufEnd, textDir);
paint.getFontMetricsInt(fm);
@@ -848,15 +748,20 @@ public class StaticLayout extends Layout {
void prepare() {
mMeasured = MeasuredText.obtain();
}
-
+
void finish() {
mMeasured = MeasuredText.recycle(mMeasured);
}
- // returns an array with terminal sentinel value -1 to indicate end
- // this is so that arrays can be recycled instead of allocating new arrays
- // every time
- private static native int[] nLineBreakOpportunities(String locale, char[] text, int length, int[] recycle);
+ // populates LineBreaks and returns the number of breaks found
+ //
+ // the arrays inside the LineBreaks objects are passed in as well
+ // to reduce the number of JNI calls in the common case where the
+ // arrays do not have to be resized
+ private static native int nComputeLineBreaks(String locale, char[] text, float[] widths,
+ int length, float firstWidth, int firstWidthLineCount, float restWidth,
+ int[] variableTabStops, int defaultTabStop, boolean optimize, LineBreaks recycle,
+ int[] recycleBreaks, float[] recycleWidths, boolean[] recycleFlags, int recycleLength);
private int mLineCount;
private int mTopPadding, mBottomPadding;
@@ -884,18 +789,23 @@ public class StaticLayout extends Layout {
private static final int TAB_INCREMENT = 20; // same as Layout, but that's private
private static final char CHAR_NEW_LINE = '\n';
- private static final char CHAR_TAB = '\t';
- private static final char CHAR_SPACE = ' ';
- private static final char CHAR_ZWSP = '\u200B';
private static final double EXTRA_ROUNDING = 0.5;
- private static final int CHAR_FIRST_HIGH_SURROGATE = 0xD800;
- private static final int CHAR_LAST_LOW_SURROGATE = 0xDFFF;
-
/*
* This is reused across calls to generate()
*/
private MeasuredText mMeasured;
private Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
+
+ // This is used to return three arrays from a single JNI call when
+ // performing line breaking
+ /*package*/ static class LineBreaks {
+ private static final int INITIAL_SIZE = 16;
+ public int[] breaks = new int[INITIAL_SIZE];
+ public float[] widths = new float[INITIAL_SIZE];
+ public boolean[] flags = new boolean[INITIAL_SIZE]; // hasTabOrEmoji
+ // breaks, widths, and flags should all have the same length
+ }
+
}
diff --git a/core/java/android/util/Spline.java b/core/java/android/util/Spline.java
index 41a2e5d..bed3a60 100644
--- a/core/java/android/util/Spline.java
+++ b/core/java/android/util/Spline.java
@@ -165,7 +165,7 @@ public abstract class Spline {
throw new IllegalArgumentException("The control points must have "
+ "monotonic Y values.");
}
- float h = FloatMath.hypot(a, b);
+ float h = (float) Math.hypot(a, b);
if (h > 9f) {
float t = 3f / h;
m[i] = t * a * d[i];
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 60a489b..eaea4d4 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -191,17 +191,17 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
@Override
- public int onPreDraw(Rect dirty) {
+ public void onPreDraw(Rect dirty) {
if (dirty != null) {
- return nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom,
+ nPrepareDirty(mRenderer, dirty.left, dirty.top, dirty.right, dirty.bottom,
mOpaque);
} else {
- return nPrepare(mRenderer, mOpaque);
+ nPrepare(mRenderer, mOpaque);
}
}
- private static native int nPrepare(long renderer, boolean opaque);
- private static native int nPrepareDirty(long renderer, int left, int top, int right, int bottom,
+ private static native void nPrepare(long renderer, boolean opaque);
+ private static native void nPrepareDirty(long renderer, int left, int top, int right, int bottom,
boolean opaque);
@Override
@@ -216,11 +216,11 @@ class GLES20Canvas extends HardwareCanvas {
///////////////////////////////////////////////////////////////////////////
@Override
- public int callDrawGLFunction2(long drawGLFunction) {
- return nCallDrawGLFunction(mRenderer, drawGLFunction);
+ public void callDrawGLFunction2(long drawGLFunction) {
+ nCallDrawGLFunction(mRenderer, drawGLFunction);
}
- private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
+ private static native void nCallDrawGLFunction(long renderer, long drawGLFunction);
///////////////////////////////////////////////////////////////////////////
// Display list
@@ -229,12 +229,12 @@ class GLES20Canvas extends HardwareCanvas {
protected static native long nFinishRecording(long renderer);
@Override
- public int drawRenderNode(RenderNode renderNode, Rect dirty, int flags) {
- return nDrawRenderNode(mRenderer, renderNode.getNativeDisplayList(), dirty, flags);
+ public void drawRenderNode(RenderNode renderNode, int flags) {
+ nDrawRenderNode(mRenderer, renderNode.getNativeDisplayList(), flags);
}
- private static native int nDrawRenderNode(long renderer, long renderNode,
- Rect dirty, int flags);
+ private static native void nDrawRenderNode(long renderer, long renderNode,
+ int flags);
///////////////////////////////////////////////////////////////////////////
// Hardware layer
@@ -447,7 +447,7 @@ class GLES20Canvas extends HardwareCanvas {
return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
}
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
return nSaveLayer(mRenderer, nativePaint, saveFlags);
}
@@ -457,7 +457,7 @@ class GLES20Canvas extends HardwareCanvas {
public int saveLayer(float left, float top, float right, float bottom, Paint paint,
int saveFlags) {
if (left < right && top < bottom) {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
return nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
}
return save(saveFlags);
@@ -517,16 +517,10 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void setDrawFilter(DrawFilter filter) {
mFilter = filter;
- if (filter == null) {
- nResetPaintFilter(mRenderer);
- } else if (filter instanceof PaintFlagsDrawFilter) {
- PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter;
- nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits);
- }
+ nSetDrawFilter(mRenderer, (filter != null) ? filter.mNativeInt : 0);
}
- private static native void nResetPaintFilter(long renderer);
- private static native void nSetupPaintFilter(long renderer, int clearBits, int setBits);
+ private static native void nSetDrawFilter(long renderer, long nativeFilter);
@Override
public DrawFilter getDrawFilter() {
@@ -541,7 +535,7 @@ class GLES20Canvas extends HardwareCanvas {
public void drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, boolean useCenter, Paint paint) {
nDrawArc(mRenderer, left, top, right, bottom,
- startAngle, sweepAngle, useCenter, paint.mNativePaint);
+ startAngle, sweepAngle, useCenter, paint.getNativeInstance());
}
private static native void nDrawArc(long renderer, float left, float top,
@@ -557,7 +551,7 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@@ -566,7 +560,7 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
nDrawPatch(mRenderer, bitmap.mNativeBitmap, patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@@ -577,7 +571,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
}
@@ -587,7 +581,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
}
@@ -597,7 +591,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
int left, top, right, bottom;
if (src == null) {
@@ -618,7 +612,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
throwIfCannotDraw(bitmap);
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
float left, top, right, bottom;
if (src == null) {
@@ -663,7 +657,7 @@ class GLES20Canvas extends HardwareCanvas {
throw new ArrayIndexOutOfBoundsException();
}
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
nDrawBitmap(mRenderer, colors, offset, stride, x, y,
width, height, hasAlpha, nativePaint);
}
@@ -696,7 +690,7 @@ class GLES20Canvas extends HardwareCanvas {
checkRange(colors.length, colorOffset, count);
}
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, meshWidth, meshHeight,
verts, vertOffset, colors, colorOffset, nativePaint);
}
@@ -707,7 +701,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawCircle(float cx, float cy, float radius, Paint paint) {
- nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
+ nDrawCircle(mRenderer, cx, cy, radius, paint.getNativeInstance());
}
private static native void nDrawCircle(long renderer, float cx, float cy,
@@ -765,7 +759,7 @@ class GLES20Canvas extends HardwareCanvas {
if ((offset | count) < 0 || offset + count > pts.length) {
throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
}
- nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
+ nDrawLines(mRenderer, pts, offset, count, paint.getNativeInstance());
}
private static native void nDrawLines(long renderer, float[] points,
@@ -778,7 +772,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawOval(float left, float top, float right, float bottom, Paint paint) {
- nDrawOval(mRenderer, left, top, right, bottom, paint.mNativePaint);
+ nDrawOval(mRenderer, left, top, right, bottom, paint.getNativeInstance());
}
private static native void nDrawOval(long renderer, float left, float top,
@@ -795,10 +789,10 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPath(Path path, Paint paint) {
if (path.isSimplePath) {
if (path.rects != null) {
- nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
+ nDrawRects(mRenderer, path.rects.mNativeRegion, paint.getNativeInstance());
}
} else {
- nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
+ nDrawPath(mRenderer, path.mNativePath, paint.getNativeInstance());
}
}
@@ -828,7 +822,7 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPoints(float[] pts, int offset, int count, Paint paint) {
if (count < 2) return;
- nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
+ nDrawPoints(mRenderer, pts, offset, count, paint.getNativeInstance());
}
private static native void nDrawPoints(long renderer, float[] points,
@@ -839,7 +833,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawRect(float left, float top, float right, float bottom, Paint paint) {
if (left == right || top == bottom) return;
- nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
+ nDrawRect(mRenderer, left, top, right, bottom, paint.getNativeInstance());
}
private static native void nDrawRect(long renderer, float left, float top,
@@ -863,7 +857,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
Paint paint) {
- nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
+ nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.getNativeInstance());
}
private static native void nDrawRoundRect(long renderer, float left, float top,
@@ -876,7 +870,7 @@ class GLES20Canvas extends HardwareCanvas {
}
nDrawText(mRenderer, text, index, count, x, y,
- paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+ paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
}
private static native void nDrawText(long renderer, char[] text, int index, int count,
@@ -890,14 +884,14 @@ class GLES20Canvas extends HardwareCanvas {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
- paint.mNativePaint, paint.mNativeTypeface);
+ paint.getNativeInstance(), paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
nDrawText(mRenderer, buf, 0, end - start, x, y,
- paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+ paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
}
@@ -909,7 +903,7 @@ class GLES20Canvas extends HardwareCanvas {
}
nDrawText(mRenderer, text, start, end, x, y,
- paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+ paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
}
private static native void nDrawText(long renderer, String text, int start, int end,
@@ -918,7 +912,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawText(String text, float x, float y, Paint paint) {
nDrawText(mRenderer, text, 0, text.length(), x, y,
- paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+ paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
}
@Override
@@ -929,7 +923,7 @@ class GLES20Canvas extends HardwareCanvas {
}
nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
- paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+ paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
}
private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
@@ -941,7 +935,7 @@ class GLES20Canvas extends HardwareCanvas {
if (text.length() == 0) return;
nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
- paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+ paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
}
private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
@@ -956,7 +950,7 @@ class GLES20Canvas extends HardwareCanvas {
}
nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, isRtl,
- paint.mNativePaint, paint.mNativeTypeface);
+ paint.getNativeInstance(), paint.mNativeTypeface);
}
private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
@@ -972,7 +966,7 @@ class GLES20Canvas extends HardwareCanvas {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
- contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
+ contextEnd, x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
contextStart, contextEnd, x, y, isRtl, paint);
@@ -982,7 +976,7 @@ class GLES20Canvas extends HardwareCanvas {
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
- x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
+ x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 18accb8..98e3927 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -43,12 +43,10 @@ public abstract class HardwareCanvas extends Canvas {
* Invoked before any drawing operation is performed in this canvas.
*
* @param dirty The dirty rectangle to update, can be null.
- * @return {@link RenderNode#STATUS_DREW} if anything was drawn (such as a call to clear
- * the canvas).
*
* @hide
*/
- public abstract int onPreDraw(Rect dirty);
+ public abstract void onPreDraw(Rect dirty);
/**
* Invoked after all drawing operation have been performed.
@@ -64,7 +62,7 @@ public abstract class HardwareCanvas extends Canvas {
* @param renderNode The RenderNode to replay.
*/
public void drawRenderNode(RenderNode renderNode) {
- drawRenderNode(renderNode, null, RenderNode.FLAG_CLIP_CHILDREN);
+ drawRenderNode(renderNode, RenderNode.FLAG_CLIP_CHILDREN);
}
/**
@@ -75,12 +73,9 @@ public abstract class HardwareCanvas extends Canvas {
* @param flags Optional flags about drawing, see {@link RenderNode} for
* the possible flags.
*
- * @return One of {@link RenderNode#STATUS_DONE} or {@link RenderNode#STATUS_DREW}
- * if anything was drawn.
- *
* @hide
*/
- public abstract int drawRenderNode(RenderNode renderNode, Rect dirty, int flags);
+ public abstract void drawRenderNode(RenderNode renderNode, int flags);
/**
* Draws the specified layer onto this canvas.
@@ -101,11 +96,11 @@ public abstract class HardwareCanvas extends Canvas {
*
* @param drawGLFunction A native function pointer
*
- * @return {@link RenderNode#STATUS_DONE}
- *
* @hide
*/
- public abstract int callDrawGLFunction2(long drawGLFunction);
+ public void callDrawGLFunction2(long drawGLFunction) {
+ // Noop - this is done in the display list recorder subclass
+ }
public abstract void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
CanvasProperty<Float> radius, CanvasProperty<Paint> paint);
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index a130bda..65ae8a6 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -52,7 +52,7 @@ final class HardwareLayer {
* @see View#setLayerPaint(android.graphics.Paint)
*/
public void setLayerPaint(Paint paint) {
- nSetLayerPaint(mFinalizer.get(), paint.mNativePaint);
+ nSetLayerPaint(mFinalizer.get(), paint.getNativeInstance());
mRenderer.pushLayerUpdate(this);
}
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 47f72a8..09eb486 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -305,7 +305,7 @@ public class RenderNode {
}
public boolean setLayerPaint(Paint paint) {
- return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0);
+ return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.getNativeInstance() : 0);
}
public boolean setClipBounds(@Nullable Rect rect) {
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 33ce517..83b8100 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -322,7 +322,6 @@ public class Surface implements Parcelable {
* @return A canvas for drawing into the surface.
*
* @throws IllegalStateException If the canvas cannot be locked.
- * @hide
*/
public Canvas lockHardwareCanvas() {
synchronized (mLock) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2bb1ebc..753a4e7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15219,7 +15219,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
} else {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- ((HardwareCanvas) canvas).drawRenderNode(renderNode, null, flags);
+ ((HardwareCanvas) canvas).drawRenderNode(renderNode, flags);
}
}
} else if (cache != null) {
@@ -17347,7 +17347,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*
* The specified key should be an id declared in the resources of the
* application to ensure it is unique (see the <a
- * href={@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>).
+ * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>).
* Keys identified as belonging to
* the Android framework or not associated with any package will cause
* an {@link IllegalArgumentException} to be thrown.
diff --git a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
index 5bef71f..3ff099a 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtypeArray.java
@@ -203,43 +203,20 @@ public class InputMethodSubtypeArray {
}
private static byte[] compress(final byte[] data) {
- ByteArrayOutputStream resultStream = null;
- GZIPOutputStream zipper = null;
- try {
- resultStream = new ByteArrayOutputStream();
- zipper = new GZIPOutputStream(resultStream);
+ try (final ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
+ final GZIPOutputStream zipper = new GZIPOutputStream(resultStream)) {
zipper.write(data);
- } catch(IOException e) {
+ zipper.finish();
+ return resultStream.toByteArray();
+ } catch(Exception e) {
+ Slog.e(TAG, "Failed to compress the data.", e);
return null;
- } finally {
- try {
- if (zipper != null) {
- zipper.close();
- }
- } catch (IOException e) {
- zipper = null;
- Slog.e(TAG, "Failed to close the stream.", e);
- // swallowed, not propagated back to the caller
- }
- try {
- if (resultStream != null) {
- resultStream.close();
- }
- } catch (IOException e) {
- resultStream = null;
- Slog.e(TAG, "Failed to close the stream.", e);
- // swallowed, not propagated back to the caller
- }
}
- return resultStream != null ? resultStream.toByteArray() : null;
}
private static byte[] decompress(final byte[] data, final int expectedSize) {
- ByteArrayInputStream inputStream = null;
- GZIPInputStream unzipper = null;
- try {
- inputStream = new ByteArrayInputStream(data);
- unzipper = new GZIPInputStream(inputStream);
+ try (final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ final GZIPInputStream unzipper = new GZIPInputStream(inputStream)) {
final byte [] result = new byte[expectedSize];
int totalReadBytes = 0;
while (totalReadBytes < result.length) {
@@ -254,25 +231,9 @@ public class InputMethodSubtypeArray {
return null;
}
return result;
- } catch(IOException e) {
+ } catch(Exception e) {
+ Slog.e(TAG, "Failed to decompress the data.", e);
return null;
- } finally {
- try {
- if (unzipper != null) {
- unzipper.close();
- }
- } catch (IOException e) {
- Slog.e(TAG, "Failed to close the stream.", e);
- // swallowed, not propagated back to the caller
- }
- try {
- if (inputStream != null) {
- inputStream.close();
- }
- } catch (IOException e) {
- Slog.e(TAG, "Failed to close the stream.", e);
- // swallowed, not propagated back to the caller
- }
}
}
}
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index ad6e9aa..f487a4e 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -17,6 +17,7 @@
package android.webkit;
import java.io.InputStream;
+import java.io.StringBufferInputStream;
import java.util.Map;
/**
@@ -40,13 +41,14 @@ public class WebResourceResponse {
*
* @param mimeType the resource response's MIME type, for example text/html
* @param encoding the resource response's encoding
- * @param data the input stream that provides the resource response's data
+ * @param data the input stream that provides the resource response's data. Must not be a
+ * StringBufferInputStream.
*/
public WebResourceResponse(String mimeType, String encoding,
InputStream data) {
mMimeType = mimeType;
mEncoding = encoding;
- mInputStream = data;
+ setData(data);
}
/**
@@ -62,7 +64,8 @@ public class WebResourceResponse {
* and not empty.
* @param responseHeaders the resource response's headers represented as a mapping of header
* name -> header value.
- * @param data the input stream that provides the resource response's data
+ * @param data the input stream that provides the resource response's data. Must not be a
+ * StringBufferInputStream.
*/
public WebResourceResponse(String mimeType, String encoding, int statusCode,
String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
@@ -178,9 +181,16 @@ public class WebResourceResponse {
* Sets the input stream that provides the resource response's data. Callers
* must implement {@link InputStream#read(byte[]) InputStream.read(byte[])}.
*
- * @param data the input stream that provides the resource response's data
+ * @param data the input stream that provides the resource response's data. Must not be a
+ * StringBufferInputStream.
*/
public void setData(InputStream data) {
+ // If data is (or is a subclass of) StringBufferInputStream
+ if (data != null && StringBufferInputStream.class.isAssignableFrom(data.getClass())) {
+ throw new IllegalArgumentException("StringBufferInputStream is deprecated and must " +
+ "not be passed to a WebResourceResponse");
+ }
+
mInputStream = data;
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 474ef42..cafe053 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -117,12 +117,8 @@ public final class WebViewFactory {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
try {
- try {
- sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
- .newInstance(new WebViewDelegate());
- } catch (Exception e) {
- sProviderInstance = providerClass.newInstance();
- }
+ sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
+ .newInstance(new WebViewDelegate());
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 936da32..d5166f3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1402,7 +1402,7 @@ public class Editor {
blockDisplayList.setLeftTopRightBottom(left, top, right, bottom);
}
- ((HardwareCanvas) canvas).drawRenderNode(blockDisplayList, null,
+ ((HardwareCanvas) canvas).drawRenderNode(blockDisplayList,
0 /* no child clipping, our TextView parent enforces it */);
endOfPreviousBlock = blockEndLine;