diff options
69 files changed, 1217 insertions, 1960 deletions
diff --git a/api/current.txt b/api/current.txt index 29fc7b1..2094c7c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4019,10 +4019,12 @@ package android.app { ctor public AssistContent(); method public android.content.ClipData getClipData(); method public android.os.Bundle getExtras(); + method public java.lang.String getStructuredData(); method public android.net.Uri getWebUri(); method public boolean isAppProvidedIntent(); method public void setClipData(android.content.ClipData); method public void setIntent(android.content.Intent); + method public void setStructuredData(java.lang.String); method public void setWebUri(android.net.Uri); } @@ -26562,7 +26564,6 @@ package android.provider { field public static final java.lang.String DEBUG_APP = "debug_app"; field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"; field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned"; - field public static final java.lang.String HIDE_CARRIER_NETWORK_SETTINGS = "hide_carrier_network_settings"; field public static final java.lang.String HTTP_PROXY = "http_proxy"; field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; field public static final java.lang.String MODE_RINGER = "mode_ringer"; diff --git a/api/system-current.txt b/api/system-current.txt index 4b4a77c..9386c50 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4114,10 +4114,12 @@ package android.app { ctor public AssistContent(); method public android.content.ClipData getClipData(); method public android.os.Bundle getExtras(); + method public java.lang.String getStructuredData(); method public android.net.Uri getWebUri(); method public boolean isAppProvidedIntent(); method public void setClipData(android.content.ClipData); method public void setIntent(android.content.Intent); + method public void setStructuredData(java.lang.String); method public void setWebUri(android.net.Uri); } @@ -28598,7 +28600,6 @@ package android.provider { field public static final java.lang.String DEBUG_APP = "debug_app"; field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled"; field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned"; - field public static final java.lang.String HIDE_CARRIER_NETWORK_SETTINGS = "hide_carrier_network_settings"; field public static final java.lang.String HTTP_PROXY = "http_proxy"; field public static final deprecated java.lang.String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; field public static final java.lang.String MODE_RINGER = "mode_ringer"; diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 21dc1e2..fba462b 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -530,7 +530,7 @@ bool BootAnimation::movie() if (leaf.size() > 0) { for (size_t j=0 ; j<pcount ; j++) { if (path == animation.parts[j].path) { - int method; + uint16_t method; // supports only stored png files if (mZip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) { if (method == ZipFileRO::kCompressStored) { diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp index 16532b8..41395f1 100644 --- a/cmds/idmap/create.cpp +++ b/cmds/idmap/create.cpp @@ -23,7 +23,7 @@ namespace { if (entry == NULL) { return -1; } - if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, reinterpret_cast<long*>(crc))) { + if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, crc)) { return -1; } zip->releaseEntry(entry); diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp index 84158d3..612a7eb 100644 --- a/cmds/idmap/scan.cpp +++ b/cmds/idmap/scan.cpp @@ -1,4 +1,5 @@ #include <dirent.h> +#include <inttypes.h> #include <sys/stat.h> #include "idmap.h" @@ -130,14 +131,14 @@ namespace { ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__); return -1; } - size_t uncompLen = 0; - int method; + uint32_t uncompLen = 0; + uint16_t method; if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) { ALOGW("%s: failed to read entry info\n", __FUNCTION__); return -1; } if (method != ZipFileRO::kCompressDeflated) { - ALOGW("%s: cannot handle zip compression method %d\n", __FUNCTION__, method); + ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method); return -1; } FileMap *dataMap = zip->createEntryFileMap(entry); @@ -147,19 +148,19 @@ namespace { } char *buf = new char[uncompLen]; if (NULL == buf) { - ALOGW("%s: failed to allocate %zd byte\n", __FUNCTION__, uncompLen); + ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen); delete dataMap; return -1; } StreamingZipInflater inflater(dataMap, uncompLen); if (inflater.read(buf, uncompLen) < 0) { - ALOGW("%s: failed to inflate %zd byte\n", __FUNCTION__, uncompLen); + ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen); delete[] buf; delete dataMap; return -1; } - int priority = parse_manifest(buf, uncompLen, target_package_name); + int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name); delete[] buf; delete dataMap; return priority; diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java index 0df9ce5..ad2ba39 100644 --- a/core/java/android/app/AssistContent.java +++ b/core/java/android/app/AssistContent.java @@ -33,6 +33,7 @@ import android.os.Parcelable; public class AssistContent { private boolean mIsAppProvidedIntent = false; private Intent mIntent; + private String mStructuredData; private ClipData mClipData; private Uri mUri; private final Bundle mExtras; @@ -125,6 +126,22 @@ public class AssistContent { } /** + * Sets optional structured data regarding the content being viewed. The provided data + * must be a string represented with <a href="http://json-ld.org/">JSON-LD</a> using the + * <a href="http://schema.org/">schema.org</a> vocabulary. + */ + public void setStructuredData(String structuredData) { + mStructuredData = structuredData; + } + + /** + * Returns the current {@link #setStructuredData}. + */ + public String getStructuredData() { + return mStructuredData; + } + + /** * Set a web URI associated with the current data being shown to the user. * This URI could be opened in a web browser, or in the app as an * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently @@ -163,6 +180,9 @@ public class AssistContent { if (in.readInt() != 0) { mUri = Uri.CREATOR.createFromParcel(in); } + if (in.readInt() != 0) { + mStructuredData = in.readString(); + } mIsAppProvidedIntent = in.readInt() == 1; mExtras = in.readBundle(); } @@ -187,6 +207,12 @@ public class AssistContent { } else { dest.writeInt(0); } + if (mStructuredData != null) { + dest.writeInt(1); + dest.writeString(mStructuredData); + } else { + dest.writeInt(0); + } dest.writeInt(mIsAppProvidedIntent ? 1 : 0); dest.writeBundle(mExtras); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 634f116..ed20086 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -403,8 +403,9 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download - * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. + * A String extra holding the URL-safe base64 encoded SHA-256 or SHA-1 hash (see notes below) of + * the file at download location specified in + * {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. * * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM} should be * present. The provided checksum should match the checksum of the file at the download @@ -413,12 +414,17 @@ public class DevicePolicyManager { * * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner * provisioning via an NFC bump. + * + * <p><strong>Note:</strong> for devices running {@link android.os.Build.VERSION_CODES#LOLLIPOP} + * and {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} only SHA-1 hash is supported. + * Starting from {@link android.os.Build.VERSION_CODES#MNC}, this parameter accepts SHA-256 in + * addition to SHA-1. Support for SHA-1 is likely to be removed in future OS releases. */ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the + * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the * android package archive at the download location specified in {@link * #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. * @@ -510,7 +516,7 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download + * A String extra holding the URL-safe base64 encoded SHA-256 checksum of the file at download * location specified in * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. * @@ -526,7 +532,7 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM"; /** - * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any signature of the + * A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the * android package archive at the download location specified in {@link * #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. * diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index c92c256..287e0c5 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4024,7 +4024,7 @@ public class PackageParser { public static final PublicKey parsePublicKey(final String encodedPublicKey) { if (encodedPublicKey == null) { - Slog.i(TAG, "Could not parse null public key"); + Slog.w(TAG, "Could not parse null public key"); return null; } @@ -4033,7 +4033,7 @@ public class PackageParser { final byte[] encoded = Base64.decode(encodedPublicKey, Base64.DEFAULT); keySpec = new X509EncodedKeySpec(encoded); } catch (IllegalArgumentException e) { - Slog.i(TAG, "Could not parse verifier public key; invalid Base64"); + Slog.w(TAG, "Could not parse verifier public key; invalid Base64"); return null; } @@ -4042,23 +4042,32 @@ public class PackageParser { final KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { - Log.wtf(TAG, "Could not parse public key because RSA isn't included in build"); - return null; + Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build"); } catch (InvalidKeySpecException e) { // Not a RSA public key. } + /* Now try it as a ECDSA key. */ + try { + final KeyFactory keyFactory = KeyFactory.getInstance("EC"); + return keyFactory.generatePublic(keySpec); + } catch (NoSuchAlgorithmException e) { + Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build"); + } catch (InvalidKeySpecException e) { + // Not a ECDSA public key. + } + /* Now try it as a DSA key. */ try { final KeyFactory keyFactory = KeyFactory.getInstance("DSA"); return keyFactory.generatePublic(keySpec); } catch (NoSuchAlgorithmException e) { - Log.wtf(TAG, "Could not parse public key because DSA isn't included in build"); - return null; + Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build"); } catch (InvalidKeySpecException e) { // Not a DSA public key. } + /* Not a supported key type */ return null; } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 152bc22..27d14b3 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1093,14 +1093,28 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity * (depth) in pixel coordinates.</p> + * <p>Note that the coordinate system for this transform is the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} system, + * where <code>(0,0)</code> is the top-left of the + * preCorrectionActiveArraySize rectangle. Once the pose and + * intrinsic calibration transforms have been applied to a + * world point, then the android.lens.radialDistortion + * transform needs to be applied, and the result adjusted to + * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate + * system (where <code>(0, 0)</code> is the top-left of the + * activeArraySize rectangle), to determine the final pixel + * coordinate of the world point for processed (non-RAW) + * output buffers.</p> * <p><b>Units</b>: - * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate - * system.</p> + * Pixels in the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * coordinate system.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<float[]> LENS_INTRINSIC_CALIBRATION = @@ -2006,19 +2020,19 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}:</p> * <ol> * <li>Choose a pixel (x', y') within the active array region of the raw buffer given in - * android.sensor.info.preCorrectedActiveArraySize, otherwise this pixel is considered + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize}, otherwise this pixel is considered * to be outside of the FOV, and will not be shown in the processed output image.</li> * <li>Apply geometric distortion correction to get the post-distortion pixel coordinate, * (x_i, y_i). When applying geometric correction metadata, note that metadata for raw * buffers is defined relative to the top, left of the - * android.sensor.info.preCorrectedActiveArraySize rectangle.</li> + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} rectangle.</li> * <li>If the resulting corrected pixel coordinate is within the region given in * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}, then the position of this pixel in the * processed output image buffer is <code>(x_i - activeArray.left, y_i - activeArray.top)</code>, * when the top, left coordinate of that buffer is treated as (0, 0).</li> * </ol> * <p>Thus, for pixel x',y' = (25, 25) on a sensor where {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize} - * is (100,100), android.sensor.info.preCorrectedActiveArraySize is (10, 10, 100, 100), + * is (100,100), {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} is (10, 10, 100, 100), * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} is (20, 20, 80, 80), and the geometric distortion * correction doesn't change the pixel coordinate, the resulting pixel selected in * pixel coordinates would be x,y = (25, 25) relative to the top,left of the raw buffer @@ -2042,6 +2056,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<android.graphics.Rect> SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE = diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 479583c..da216aa 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2655,14 +2655,28 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity * (depth) in pixel coordinates.</p> + * <p>Note that the coordinate system for this transform is the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} system, + * where <code>(0,0)</code> is the top-left of the + * preCorrectionActiveArraySize rectangle. Once the pose and + * intrinsic calibration transforms have been applied to a + * world point, then the android.lens.radialDistortion + * transform needs to be applied, and the result adjusted to + * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate + * system (where <code>(0, 0)</code> is the top-left of the + * activeArraySize rectangle), to determine the final pixel + * coordinate of the world point for processed (non-RAW) + * output buffers.</p> * <p><b>Units</b>: - * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate - * system.</p> + * Pixels in the + * {@link CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE android.sensor.info.preCorrectionActiveArraySize} + * coordinate system.</p> * <p><b>Optional</b> - This value may be {@code null} on some devices.</p> * * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE */ @PublicKey public static final Key<float[]> LENS_INTRINSIC_CALIBRATION = diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index dfd72c2..3e9c9de 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7232,13 +7232,6 @@ public final class Settings { "preferred_network_mode"; /** - * Setting to 1 will hide carrier network settings. - * Default is 0. - */ - public static final String HIDE_CARRIER_NETWORK_SETTINGS = - "hide_carrier_network_settings"; - - /** * Name of an application package to be debugged. */ public static final String DEBUG_APP = "debug_app"; diff --git a/core/java/android/speech/srec/MicrophoneInputStream.java b/core/java/android/speech/srec/MicrophoneInputStream.java deleted file mode 100644 index 94db176..0000000 --- a/core/java/android/speech/srec/MicrophoneInputStream.java +++ /dev/null @@ -1,110 +0,0 @@ -/*---------------------------------------------------------------------------* - * MicrophoneInputStream.java * - * * - * Copyright 2007 Nuance Communciations, Inc. * - * * - * 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.speech.srec; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.IllegalStateException; - - -/** - * PCM input stream from the microphone, 16 bits per sample. - */ -public final class MicrophoneInputStream extends InputStream { - static { - System.loadLibrary("srec_jni"); - } - - private final static String TAG = "MicrophoneInputStream"; - private long mAudioRecord = 0; - private byte[] mOneByte = new byte[1]; - - /** - * MicrophoneInputStream constructor. - * @param sampleRate sample rate of the microphone, typically 11025 or 8000. - * @param fifoDepth depth of the real time fifo, measured in sampleRate clock ticks. - * This determines how long an application may delay before losing data. - */ - public MicrophoneInputStream(int sampleRate, int fifoDepth) throws IOException { - mAudioRecord = AudioRecordNew(sampleRate, fifoDepth); - if (mAudioRecord == 0) throw new IOException("AudioRecord constructor failed - busy?"); - int status = AudioRecordStart(mAudioRecord); - if (status != 0) { - close(); - throw new IOException("AudioRecord start failed: " + status); - } - } - - @Override - public int read() throws IOException { - if (mAudioRecord == 0) throw new IllegalStateException("not open"); - int rtn = AudioRecordRead(mAudioRecord, mOneByte, 0, 1); - return rtn == 1 ? ((int)mOneByte[0] & 0xff) : -1; - } - - @Override - public int read(byte[] b) throws IOException { - if (mAudioRecord == 0) throw new IllegalStateException("not open"); - return AudioRecordRead(mAudioRecord, b, 0, b.length); - } - - @Override - public int read(byte[] b, int offset, int length) throws IOException { - if (mAudioRecord == 0) throw new IllegalStateException("not open"); - // TODO: should we force all reads to be a multiple of the sample size? - return AudioRecordRead(mAudioRecord, b, offset, length); - } - - /** - * Closes this stream. - */ - @Override - public void close() throws IOException { - if (mAudioRecord != 0) { - try { - AudioRecordStop(mAudioRecord); - } finally { - try { - AudioRecordDelete(mAudioRecord); - } finally { - mAudioRecord = 0; - } - } - } - } - - @Override - protected void finalize() throws Throwable { - if (mAudioRecord != 0) { - close(); - throw new IOException("someone forgot to close MicrophoneInputStream"); - } - } - - // - // AudioRecord JNI interface - // - private static native long AudioRecordNew(int sampleRate, int fifoDepth); - private static native int AudioRecordStart(long audioRecord); - private static native int AudioRecordRead(long audioRecord, byte[] b, int offset, int length) throws IOException; - private static native void AudioRecordStop(long audioRecord) throws IOException; - private static native void AudioRecordDelete(long audioRecord) throws IOException; -} diff --git a/core/java/android/speech/srec/Recognizer.java b/core/java/android/speech/srec/Recognizer.java deleted file mode 100644 index 6c491a0..0000000 --- a/core/java/android/speech/srec/Recognizer.java +++ /dev/null @@ -1,716 +0,0 @@ -/* - * --------------------------------------------------------------------------- - * Recognizer.java - * - * Copyright 2007 Nuance Communciations, Inc. - * - * 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.speech.srec; - -import java.io.File; -import java.io.InputStream; -import java.io.IOException; -import java.util.Locale; - -/** - * Simple, synchronous speech recognizer, using the Nuance SREC package. - * Usages proceeds as follows: - * - * <ul> - * <li>Create a <code>Recognizer</code>. - * <li>Create a <code>Recognizer.Grammar</code>. - * <li>Setup the <code>Recognizer.Grammar</code>. - * <li>Reset the <code>Recognizer.Grammar</code> slots, if needed. - * <li>Fill the <code>Recognizer.Grammar</code> slots, if needed. - * <li>Compile the <code>Recognizer.Grammar</code>, if needed. - * <li>Save the filled <code>Recognizer.Grammar</code>, if needed. - * <li>Start the <code>Recognizer</code>. - * <li>Loop over <code>advance</code> and <code>putAudio</code> until recognition complete. - * <li>Fetch and process results, or notify of failure. - * <li>Stop the <code>Recognizer</code>. - * <li>Destroy the <code>Recognizer</code>. - * </ul> - * - * <p>Below is example code</p> - * - * <pre class="prettyprint"> - * - * // create and start audio input - * InputStream audio = new MicrophoneInputStream(11025, 11025*5); - * // create a Recognizer - * String cdir = Recognizer.getConfigDir(null); - * Recognizer recognizer = new Recognizer(cdir + "/baseline11k.par"); - * // create and load a Grammar - * Recognizer.Grammar grammar = recognizer.new Grammar(cdir + "/grammars/VoiceDialer.g2g"); - * // setup the Grammar to work with the Recognizer - * grammar.setupRecognizer(); - * // fill the Grammar slots with names and save, if required - * grammar.resetAllSlots(); - * for (String name : names) grammar.addWordToSlot("@Names", name, null, 1, "V=1"); - * grammar.compile(); - * grammar.save(".../foo.g2g"); - * // start the Recognizer - * recognizer.start(); - * // loop over Recognizer events - * while (true) { - * switch (recognizer.advance()) { - * case Recognizer.EVENT_INCOMPLETE: - * case Recognizer.EVENT_STARTED: - * case Recognizer.EVENT_START_OF_VOICING: - * case Recognizer.EVENT_END_OF_VOICING: - * // let the Recognizer continue to run - * continue; - * case Recognizer.EVENT_RECOGNITION_RESULT: - * // success, so fetch results here! - * for (int i = 0; i < recognizer.getResultCount(); i++) { - * String result = recognizer.getResult(i, Recognizer.KEY_LITERAL); - * } - * break; - * case Recognizer.EVENT_NEED_MORE_AUDIO: - * // put more audio in the Recognizer - * recognizer.putAudio(audio); - * continue; - * default: - * notifyFailure(); - * break; - * } - * break; - * } - * // stop the Recognizer - * recognizer.stop(); - * // destroy the Recognizer - * recognizer.destroy(); - * // stop the audio device - * audio.close(); - * - * </pre> - */ -public final class Recognizer { - static { - System.loadLibrary("srec_jni"); - } - - private static String TAG = "Recognizer"; - - /** - * Result key corresponding to confidence score. - */ - public static final String KEY_CONFIDENCE = "conf"; - - /** - * Result key corresponding to literal text. - */ - public static final String KEY_LITERAL = "literal"; - - /** - * Result key corresponding to semantic meaning text. - */ - public static final String KEY_MEANING = "meaning"; - - // handle to SR_Vocabulary object - private long mVocabulary = 0; - - // handle to SR_Recognizer object - private long mRecognizer = 0; - - // Grammar currently associated with Recognizer via SR_GrammarSetupRecognizer - private Grammar mActiveGrammar = null; - - /** - * Get the pathname of the SREC configuration directory corresponding to the - * language indicated by the Locale. - * This directory contains dictionaries, speech models, - * configuration files, and other data needed by the Recognizer. - * @param locale <code>Locale</code> corresponding to the desired language, - * or null for default, currently <code>Locale.US</code>. - * @return Pathname of the configuration directory. - */ - public static String getConfigDir(Locale locale) { - if (locale == null) locale = Locale.US; - String dir = "/system/usr/srec/config/" + - locale.toString().replace('_', '.').toLowerCase(Locale.ROOT); - if ((new File(dir)).isDirectory()) return dir; - return null; - } - - /** - * Create an instance of a SREC speech recognizer. - * - * @param configFile pathname of the baseline*.par configuration file, - * which in turn contains references to dictionaries, speech models, - * and other data needed to configure and operate the recognizer. - * A separate config file is needed for each audio sample rate. - * Two files, baseline11k.par and baseline8k.par, which correspond to - * 11025 and 8000 hz, are present in the directory indicated by - * {@link #getConfigDir}. - * @throws IOException - */ - public Recognizer(String configFile) throws IOException { - PMemInit(); - SR_SessionCreate(configFile); - mRecognizer = SR_RecognizerCreate(); - SR_RecognizerSetup(mRecognizer); - mVocabulary = SR_VocabularyLoad(); - } - - /** - * Represents a grammar loaded into the Recognizer. - */ - public class Grammar { - private long mGrammar = 0; - - /** - * Create a <code>Grammar</code> instance. - * @param g2gFileName pathname of g2g file. - */ - public Grammar(String g2gFileName) throws IOException { - mGrammar = SR_GrammarLoad(g2gFileName); - SR_GrammarSetupVocabulary(mGrammar, mVocabulary); - } - - /** - * Reset all slots. - */ - public void resetAllSlots() { - SR_GrammarResetAllSlots(mGrammar); - } - - /** - * Add a word to a slot. - * - * @param slot slot name. - * @param word word to insert. - * @param pron pronunciation, or null to derive from word. - * @param weight weight to give the word. One is normal, 50 is low. - * @param tag semantic meaning tag string. - */ - public void addWordToSlot(String slot, String word, String pron, int weight, String tag) { - SR_GrammarAddWordToSlot(mGrammar, slot, word, pron, weight, tag); - } - - /** - * Compile all slots. - */ - public void compile() { - SR_GrammarCompile(mGrammar); - } - - /** - * Setup <code>Grammar</code> with <code>Recognizer</code>. - */ - public void setupRecognizer() { - SR_GrammarSetupRecognizer(mGrammar, mRecognizer); - mActiveGrammar = this; - } - - /** - * Save <code>Grammar</code> to g2g file. - * - * @param g2gFileName - * @throws IOException - */ - public void save(String g2gFileName) throws IOException { - SR_GrammarSave(mGrammar, g2gFileName); - } - - /** - * Release resources associated with this <code>Grammar</code>. - */ - public void destroy() { - // TODO: need to do cleanup and disassociation with Recognizer - if (mGrammar != 0) { - SR_GrammarDestroy(mGrammar); - mGrammar = 0; - } - } - - /** - * Clean up resources. - */ - protected void finalize() { - if (mGrammar != 0) { - destroy(); - throw new IllegalStateException("someone forgot to destroy Grammar"); - } - } - } - - /** - * Start recognition - */ - public void start() { - // TODO: shouldn't be here? - SR_RecognizerActivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash", 1); - SR_RecognizerStart(mRecognizer); - } - - /** - * Process some audio and return the current status. - * @return recognition event, one of: - * <ul> - * <li><code>EVENT_INVALID</code> - * <li><code>EVENT_NO_MATCH</code> - * <li><code>EVENT_INCOMPLETE</code> - * <li><code>EVENT_STARTED</code> - * <li><code>EVENT_STOPPED</code> - * <li><code>EVENT_START_OF_VOICING</code> - * <li><code>EVENT_END_OF_VOICING</code> - * <li><code>EVENT_SPOKE_TOO_SOON</code> - * <li><code>EVENT_RECOGNITION_RESULT</code> - * <li><code>EVENT_START_OF_UTTERANCE_TIMEOUT</code> - * <li><code>EVENT_RECOGNITION_TIMEOUT</code> - * <li><code>EVENT_NEED_MORE_AUDIO</code> - * <li><code>EVENT_MAX_SPEECH</code> - * </ul> - */ - public int advance() { - return SR_RecognizerAdvance(mRecognizer); - } - - /** - * Put audio samples into the <code>Recognizer</code>. - * @param buf holds the audio samples. - * @param offset offset of the first sample. - * @param length number of bytes containing samples. - * @param isLast indicates no more audio data, normally false. - * @return number of bytes accepted. - */ - public int putAudio(byte[] buf, int offset, int length, boolean isLast) { - return SR_RecognizerPutAudio(mRecognizer, buf, offset, length, isLast); - } - - /** - * Read audio samples from an <code>InputStream</code> and put them in the - * <code>Recognizer</code>. - * @param audio <code>InputStream</code> containing PCM audio samples. - */ - public void putAudio(InputStream audio) throws IOException { - // make sure the audio buffer is allocated - if (mPutAudioBuffer == null) mPutAudioBuffer = new byte[512]; - // read some data - int nbytes = audio.read(mPutAudioBuffer); - // eof, so signal Recognizer - if (nbytes == -1) { - SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, 0, true); - } - // put it into the Recognizer - else if (nbytes != SR_RecognizerPutAudio(mRecognizer, mPutAudioBuffer, 0, nbytes, false)) { - throw new IOException("SR_RecognizerPutAudio failed nbytes=" + nbytes); - } - } - - // audio buffer for putAudio(InputStream) - private byte[] mPutAudioBuffer = null; - - /** - * Get the number of recognition results. Must be called after - * <code>EVENT_RECOGNITION_RESULT</code> is returned by - * <code>advance</code>, but before <code>stop</code>. - * - * @return number of results in nbest list. - */ - public int getResultCount() { - return SR_RecognizerResultGetSize(mRecognizer); - } - - /** - * Get a set of keys for the result. Must be called after - * <code>EVENT_RECOGNITION_RESULT</code> is returned by - * <code>advance</code>, but before <code>stop</code>. - * - * @param index index of result. - * @return array of keys. - */ - public String[] getResultKeys(int index) { - return SR_RecognizerResultGetKeyList(mRecognizer, index); - } - - /** - * Get a result value. Must be called after - * <code>EVENT_RECOGNITION_RESULT</code> is returned by - * <code>advance</code>, but before <code>stop</code>. - * - * @param index index of the result. - * @param key key of the result. This is typically one of - * <code>KEY_CONFIDENCE</code>, <code>KEY_LITERAL</code>, or - * <code>KEY_MEANING</code>, but the user can also define their own keys - * in a grxml file, or in the <code>tag</code> slot of - * <code>Grammar.addWordToSlot</code>. - * @return the result. - */ - public String getResult(int index, String key) { - return SR_RecognizerResultGetValue(mRecognizer, index, key); - } - - /** - * Stop the <code>Recognizer</code>. - */ - public void stop() { - SR_RecognizerStop(mRecognizer); - SR_RecognizerDeactivateRule(mRecognizer, mActiveGrammar.mGrammar, "trash"); - } - - /** - * Reset the acoustic state vectorto it's default value. - * - * @hide - */ - public void resetAcousticState() { - SR_AcousticStateReset(mRecognizer); - } - - /** - * Set the acoustic state vector. - * @param state String containing the acoustic state vector. - * - * @hide - */ - public void setAcousticState(String state) { - SR_AcousticStateSet(mRecognizer, state); - } - - /** - * Get the acoustic state vector. - * @return String containing the acoustic state vector. - * - * @hide - */ - public String getAcousticState() { - return SR_AcousticStateGet(mRecognizer); - } - - /** - * Clean up resources. - */ - public void destroy() { - try { - if (mVocabulary != 0) SR_VocabularyDestroy(mVocabulary); - } finally { - mVocabulary = 0; - try { - if (mRecognizer != 0) SR_RecognizerUnsetup(mRecognizer); - } finally { - try { - if (mRecognizer != 0) SR_RecognizerDestroy(mRecognizer); - } finally { - mRecognizer = 0; - try { - SR_SessionDestroy(); - } finally { - PMemShutdown(); - } - } - } - } - } - - /** - * Clean up resources. - */ - protected void finalize() throws Throwable { - if (mVocabulary != 0 || mRecognizer != 0) { - destroy(); - throw new IllegalStateException("someone forgot to destroy Recognizer"); - } - } - - /* an example session captured, for reference - void doall() { - if (PMemInit ( ) - || lhs_audioinOpen ( WAVE_MAPPER, SREC_TEST_DEFAULT_AUDIO_FREQUENCY, &audio_in_handle ) - || srec_test_init_application_data ( &applicationData, argc, argv ) - || SR_SessionCreate ( "/system/usr/srec/config/en.us/baseline11k.par" ) - || SR_RecognizerCreate ( &applicationData.recognizer ) - || SR_RecognizerSetup ( applicationData.recognizer) - || ESR_SessionGetLCHAR ( L("cmdline.vocabulary"), filename, &flen ) - || SR_VocabularyLoad ( filename, &applicationData.vocabulary ) - || SR_VocabularyGetLanguage ( applicationData.vocabulary, &applicationData.locale ) - || (applicationData.nametag = NULL) - || SR_NametagsCreate ( &applicationData.nametags ) - || (LSTRCPY ( applicationData.grammars [0].grammar_path, "/system/usr/srec/config/en.us/grammars/VoiceDialer.g2g" ), 0) - || (LSTRCPY ( applicationData.grammars [0].grammarID, "BothTags" ), 0) - || (LSTRCPY ( applicationData.grammars [0].ruleName, "trash" ), 0) - || (applicationData.grammars [0].is_ve_grammar = ESR_FALSE, 0) - || SR_GrammarLoad (applicationData.grammars [0].grammar_path, &applicationData.grammars [applicationData.grammarCount].grammar ) - || SR_GrammarSetupVocabulary ( applicationData.grammars [0].grammar, applicationData.vocabulary ) - || SR_GrammarSetupRecognizer( applicationData.grammars [0].grammar, applicationData.recognizer ) - || SR_GrammarSetDispatchFunction ( applicationData.grammars [0].grammar, L("myDSMCallback"), NULL, myDSMCallback ) - || (applicationData.grammarCount++, 0) - || SR_RecognizerActivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, - applicationData.grammars [0].ruleName, 1 ) - || (applicationData.active_grammar_num = 0, 0) - || lhs_audioinStart ( audio_in_handle ) - || SR_RecognizerStart ( applicationData.recognizer ) - || strl ( applicationData.grammars [0].grammar, &applicationData, audio_in_handle, &recognition_count ) - || SR_RecognizerStop ( applicationData.recognizer ) - || lhs_audioinStop ( audio_in_handle ) - || SR_RecognizerDeactivateRule ( applicationData.recognizer, applicationData.grammars [0].grammar, applicationData.grammars [0].ruleName ) - || (applicationData.active_grammar_num = -1, 0) - || SR_GrammarDestroy ( applicationData.grammars [0].grammar ) - || (applicationData.grammarCount--, 0) - || SR_NametagsDestroy ( applicationData.nametags ) - || (applicationData.nametags = NULL, 0) - || SR_VocabularyDestroy ( applicationData.vocabulary ) - || (applicationData.vocabulary = NULL) - || SR_RecognizerUnsetup ( applicationData.recognizer) // releases acoustic models - || SR_RecognizerDestroy ( applicationData.recognizer ) - || (applicationData.recognizer = NULL) - || SR_SessionDestroy ( ) - || srec_test_shutdown_application_data ( &applicationData ) - || lhs_audioinClose ( &audio_in_handle ) - || PMemShutdown ( ) - } - */ - - - // - // PMem native methods - // - private static native void PMemInit(); - private static native void PMemShutdown(); - - - // - // SR_Session native methods - // - private static native void SR_SessionCreate(String filename); - private static native void SR_SessionDestroy(); - - - // - // SR_Recognizer native methods - // - - /** - * Reserved value. - */ - public final static int EVENT_INVALID = 0; - - /** - * <code>Recognizer</code> could not find a match for the utterance. - */ - public final static int EVENT_NO_MATCH = 1; - - /** - * <code>Recognizer</code> processed one frame of audio. - */ - public final static int EVENT_INCOMPLETE = 2; - - /** - * <code>Recognizer</code> has just been started. - */ - public final static int EVENT_STARTED = 3; - - /** - * <code>Recognizer</code> is stopped. - */ - public final static int EVENT_STOPPED = 4; - - /** - * Beginning of speech detected. - */ - public final static int EVENT_START_OF_VOICING = 5; - - /** - * End of speech detected. - */ - public final static int EVENT_END_OF_VOICING = 6; - - /** - * Beginning of utterance occured too soon. - */ - public final static int EVENT_SPOKE_TOO_SOON = 7; - - /** - * Recognition match detected. - */ - public final static int EVENT_RECOGNITION_RESULT = 8; - - /** - * Timeout occured before beginning of utterance. - */ - public final static int EVENT_START_OF_UTTERANCE_TIMEOUT = 9; - - /** - * Timeout occured before speech recognition could complete. - */ - public final static int EVENT_RECOGNITION_TIMEOUT = 10; - - /** - * Not enough samples to process one frame. - */ - public final static int EVENT_NEED_MORE_AUDIO = 11; - - /** - * More audio encountered than is allowed by 'swirec_max_speech_duration'. - */ - public final static int EVENT_MAX_SPEECH = 12; - - /** - * Produce a displayable string from an <code>advance</code> event. - * @param event - * @return String representing the event. - */ - public static String eventToString(int event) { - switch (event) { - case EVENT_INVALID: - return "EVENT_INVALID"; - case EVENT_NO_MATCH: - return "EVENT_NO_MATCH"; - case EVENT_INCOMPLETE: - return "EVENT_INCOMPLETE"; - case EVENT_STARTED: - return "EVENT_STARTED"; - case EVENT_STOPPED: - return "EVENT_STOPPED"; - case EVENT_START_OF_VOICING: - return "EVENT_START_OF_VOICING"; - case EVENT_END_OF_VOICING: - return "EVENT_END_OF_VOICING"; - case EVENT_SPOKE_TOO_SOON: - return "EVENT_SPOKE_TOO_SOON"; - case EVENT_RECOGNITION_RESULT: - return "EVENT_RECOGNITION_RESULT"; - case EVENT_START_OF_UTTERANCE_TIMEOUT: - return "EVENT_START_OF_UTTERANCE_TIMEOUT"; - case EVENT_RECOGNITION_TIMEOUT: - return "EVENT_RECOGNITION_TIMEOUT"; - case EVENT_NEED_MORE_AUDIO: - return "EVENT_NEED_MORE_AUDIO"; - case EVENT_MAX_SPEECH: - return "EVENT_MAX_SPEECH"; - } - return "EVENT_" + event; - } - - // - // SR_Recognizer methods - // - private static native void SR_RecognizerStart(long recognizer); - private static native void SR_RecognizerStop(long recognizer); - private static native long SR_RecognizerCreate(); - private static native void SR_RecognizerDestroy(long recognizer); - private static native void SR_RecognizerSetup(long recognizer); - private static native void SR_RecognizerUnsetup(long recognizer); - private static native boolean SR_RecognizerIsSetup(long recognizer); - private static native String SR_RecognizerGetParameter(long recognizer, String key); - private static native int SR_RecognizerGetSize_tParameter(long recognizer, String key); - private static native boolean SR_RecognizerGetBoolParameter(long recognizer, String key); - private static native void SR_RecognizerSetParameter(long recognizer, String key, String value); - private static native void SR_RecognizerSetSize_tParameter(long recognizer, - String key, int value); - private static native void SR_RecognizerSetBoolParameter(long recognizer, String key, - boolean value); - private static native void SR_RecognizerSetupRule(long recognizer, long grammar, - String ruleName); - private static native boolean SR_RecognizerHasSetupRules(long recognizer); - private static native void SR_RecognizerActivateRule(long recognizer, long grammar, - String ruleName, int weight); - private static native void SR_RecognizerDeactivateRule(long recognizer, long grammar, - String ruleName); - private static native void SR_RecognizerDeactivateAllRules(long recognizer); - private static native boolean SR_RecognizerIsActiveRule(long recognizer, long grammar, - String ruleName); - private static native boolean SR_RecognizerCheckGrammarConsistency(long recognizer, - long grammar); - private static native int SR_RecognizerPutAudio(long recognizer, byte[] buffer, int offset, - int length, boolean isLast); - private static native int SR_RecognizerAdvance(long recognizer); - // private static native void SR_RecognizerLoadUtterance(long recognizer, - // const LCHAR* filename); - // private static native void SR_RecognizerLoadWaveFile(long recognizer, - // const LCHAR* filename); - // private static native void SR_RecognizerSetLockFunction(long recognizer, - // SR_RecognizerLockFunction function, void* data); - private static native boolean SR_RecognizerIsSignalClipping(long recognizer); - private static native boolean SR_RecognizerIsSignalDCOffset(long recognizer); - private static native boolean SR_RecognizerIsSignalNoisy(long recognizer); - private static native boolean SR_RecognizerIsSignalTooQuiet(long recognizer); - private static native boolean SR_RecognizerIsSignalTooFewSamples(long recognizer); - private static native boolean SR_RecognizerIsSignalTooManySamples(long recognizer); - // private static native void SR_Recognizer_Change_Sample_Rate (size_t new_sample_rate); - - - // - // SR_AcousticState native methods - // - private static native void SR_AcousticStateReset(long recognizer); - private static native void SR_AcousticStateSet(long recognizer, String state); - private static native String SR_AcousticStateGet(long recognizer); - - - // - // SR_Grammar native methods - // - private static native void SR_GrammarCompile(long grammar); - private static native void SR_GrammarAddWordToSlot(long grammar, String slot, - String word, String pronunciation, int weight, String tag); - private static native void SR_GrammarResetAllSlots(long grammar); - // private static native void SR_GrammarAddNametagToSlot(long grammar, String slot, - // const struct SR_Nametag_t* nametag, int weight, String tag); - private static native void SR_GrammarSetupVocabulary(long grammar, long vocabulary); - // private static native void SR_GrammarSetupModels(long grammar, SR_AcousticModels* models); - private static native void SR_GrammarSetupRecognizer(long grammar, long recognizer); - private static native void SR_GrammarUnsetupRecognizer(long grammar); - // private static native void SR_GrammarGetModels(long grammar,SR_AcousticModels** models); - private static native long SR_GrammarCreate(); - private static native void SR_GrammarDestroy(long grammar); - private static native long SR_GrammarLoad(String filename); - private static native void SR_GrammarSave(long grammar, String filename); - // private static native void SR_GrammarSetDispatchFunction(long grammar, - // const LCHAR* name, void* userData, SR_GrammarDispatchFunction function); - // private static native void SR_GrammarSetParameter(long grammar, const - // LCHAR* key, void* value); - // private static native void SR_GrammarSetSize_tParameter(long grammar, - // const LCHAR* key, size_t value); - // private static native void SR_GrammarGetParameter(long grammar, const - // LCHAR* key, void** value); - // private static native void SR_GrammarGetSize_tParameter(long grammar, - // const LCHAR* key, size_t* value); - // private static native void SR_GrammarCheckParse(long grammar, const LCHAR* - // transcription, SR_SemanticResult** result, size_t* resultCount); - private static native void SR_GrammarAllowOnly(long grammar, String transcription); - private static native void SR_GrammarAllowAll(long grammar); - - - // - // SR_Vocabulary native methods - // - // private static native int SR_VocabularyCreate(); - private static native long SR_VocabularyLoad(); - // private static native void SR_VocabularySave(SR_Vocabulary* self, - // const LCHAR* filename); - // private static native void SR_VocabularyAddWord(SR_Vocabulary* self, - // const LCHAR* word); - // private static native void SR_VocabularyGetLanguage(SR_Vocabulary* self, - // ESR_Locale* locale); - private static native void SR_VocabularyDestroy(long vocabulary); - private static native String SR_VocabularyGetPronunciation(long vocabulary, String word); - - - // - // SR_RecognizerResult native methods - // - private static native byte[] SR_RecognizerResultGetWaveform(long recognizer); - private static native int SR_RecognizerResultGetSize(long recognizer); - private static native int SR_RecognizerResultGetKeyCount(long recognizer, int nbest); - private static native String[] SR_RecognizerResultGetKeyList(long recognizer, int nbest); - private static native String SR_RecognizerResultGetValue(long recognizer, - int nbest, String key); - // private static native void SR_RecognizerResultGetLocale(long recognizer, ESR_Locale* locale); -} diff --git a/core/java/android/speech/srec/UlawEncoderInputStream.java b/core/java/android/speech/srec/UlawEncoderInputStream.java deleted file mode 100644 index a488ead..0000000 --- a/core/java/android/speech/srec/UlawEncoderInputStream.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * --------------------------------------------------------------------------- - * UlawEncoderInputStream.java - * - * Copyright 2008 Nuance Communciations, Inc. - * - * 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.speech.srec; - -import java.io.IOException; -import java.io.InputStream; - -/** - * InputStream which transforms 16 bit pcm data to ulaw data. - * - * Not yet ready to be supported, so - * @hide - */ -public final class UlawEncoderInputStream extends InputStream { - private final static String TAG = "UlawEncoderInputStream"; - - private final static int MAX_ULAW = 8192; - private final static int SCALE_BITS = 16; - - private InputStream mIn; - - private int mMax = 0; - - private final byte[] mBuf = new byte[1024]; - private int mBufCount = 0; // should be 0 or 1 - - private final byte[] mOneByte = new byte[1]; - - - public static void encode(byte[] pcmBuf, int pcmOffset, - byte[] ulawBuf, int ulawOffset, int length, int max) { - - // from 'ulaw' in wikipedia - // +8191 to +8159 0x80 - // +8158 to +4063 in 16 intervals of 256 0x80 + interval number - // +4062 to +2015 in 16 intervals of 128 0x90 + interval number - // +2014 to +991 in 16 intervals of 64 0xA0 + interval number - // +990 to +479 in 16 intervals of 32 0xB0 + interval number - // +478 to +223 in 16 intervals of 16 0xC0 + interval number - // +222 to +95 in 16 intervals of 8 0xD0 + interval number - // +94 to +31 in 16 intervals of 4 0xE0 + interval number - // +30 to +1 in 15 intervals of 2 0xF0 + interval number - // 0 0xFF - - // -1 0x7F - // -31 to -2 in 15 intervals of 2 0x70 + interval number - // -95 to -32 in 16 intervals of 4 0x60 + interval number - // -223 to -96 in 16 intervals of 8 0x50 + interval number - // -479 to -224 in 16 intervals of 16 0x40 + interval number - // -991 to -480 in 16 intervals of 32 0x30 + interval number - // -2015 to -992 in 16 intervals of 64 0x20 + interval number - // -4063 to -2016 in 16 intervals of 128 0x10 + interval number - // -8159 to -4064 in 16 intervals of 256 0x00 + interval number - // -8192 to -8160 0x00 - - // set scale factors - if (max <= 0) max = MAX_ULAW; - - int coef = MAX_ULAW * (1 << SCALE_BITS) / max; - - for (int i = 0; i < length; i++) { - int pcm = (0xff & pcmBuf[pcmOffset++]) + (pcmBuf[pcmOffset++] << 8); - pcm = (pcm * coef) >> SCALE_BITS; - - int ulaw; - if (pcm >= 0) { - ulaw = pcm <= 0 ? 0xff : - pcm <= 30 ? 0xf0 + (( 30 - pcm) >> 1) : - pcm <= 94 ? 0xe0 + (( 94 - pcm) >> 2) : - pcm <= 222 ? 0xd0 + (( 222 - pcm) >> 3) : - pcm <= 478 ? 0xc0 + (( 478 - pcm) >> 4) : - pcm <= 990 ? 0xb0 + (( 990 - pcm) >> 5) : - pcm <= 2014 ? 0xa0 + ((2014 - pcm) >> 6) : - pcm <= 4062 ? 0x90 + ((4062 - pcm) >> 7) : - pcm <= 8158 ? 0x80 + ((8158 - pcm) >> 8) : - 0x80; - } else { - ulaw = -1 <= pcm ? 0x7f : - -31 <= pcm ? 0x70 + ((pcm - -31) >> 1) : - -95 <= pcm ? 0x60 + ((pcm - -95) >> 2) : - -223 <= pcm ? 0x50 + ((pcm - -223) >> 3) : - -479 <= pcm ? 0x40 + ((pcm - -479) >> 4) : - -991 <= pcm ? 0x30 + ((pcm - -991) >> 5) : - -2015 <= pcm ? 0x20 + ((pcm - -2015) >> 6) : - -4063 <= pcm ? 0x10 + ((pcm - -4063) >> 7) : - -8159 <= pcm ? 0x00 + ((pcm - -8159) >> 8) : - 0x00; - } - ulawBuf[ulawOffset++] = (byte)ulaw; - } - } - - /** - * Compute the maximum of the absolute value of the pcm samples. - * The return value can be used to set ulaw encoder scaling. - * @param pcmBuf array containing 16 bit pcm data. - * @param offset offset of start of 16 bit pcm data. - * @param length number of pcm samples (not number of input bytes) - * @return maximum abs of pcm data values - */ - public static int maxAbsPcm(byte[] pcmBuf, int offset, int length) { - int max = 0; - for (int i = 0; i < length; i++) { - int pcm = (0xff & pcmBuf[offset++]) + (pcmBuf[offset++] << 8); - if (pcm < 0) pcm = -pcm; - if (pcm > max) max = pcm; - } - return max; - } - - /** - * Create an InputStream which takes 16 bit pcm data and produces ulaw data. - * @param in InputStream containing 16 bit pcm data. - * @param max pcm value corresponding to maximum ulaw value. - */ - public UlawEncoderInputStream(InputStream in, int max) { - mIn = in; - mMax = max; - } - - @Override - public int read(byte[] buf, int offset, int length) throws IOException { - if (mIn == null) throw new IllegalStateException("not open"); - - // return at least one byte, but try to fill 'length' - while (mBufCount < 2) { - int n = mIn.read(mBuf, mBufCount, Math.min(length * 2, mBuf.length - mBufCount)); - if (n == -1) return -1; - mBufCount += n; - } - - // compand data - int n = Math.min(mBufCount / 2, length); - encode(mBuf, 0, buf, offset, n, mMax); - - // move data to bottom of mBuf - mBufCount -= n * 2; - for (int i = 0; i < mBufCount; i++) mBuf[i] = mBuf[i + n * 2]; - - return n; - } - - @Override - public int read(byte[] buf) throws IOException { - return read(buf, 0, buf.length); - } - - @Override - public int read() throws IOException { - int n = read(mOneByte, 0, 1); - if (n == -1) return -1; - return 0xff & (int)mOneByte[0]; - } - - @Override - public void close() throws IOException { - if (mIn != null) { - InputStream in = mIn; - mIn = null; - in.close(); - } - } - - @Override - public int available() throws IOException { - return (mIn.available() + mBufCount) / 2; - } -} diff --git a/core/java/android/speech/srec/WaveHeader.java b/core/java/android/speech/srec/WaveHeader.java deleted file mode 100644 index 4c3b172..0000000 --- a/core/java/android/speech/srec/WaveHeader.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.speech.srec; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * This class represents the header of a WAVE format audio file, which usually - * have a .wav suffix. The following integer valued fields are contained: - * <ul> - * <li> format - usually PCM, ALAW or ULAW. - * <li> numChannels - 1 for mono, 2 for stereo. - * <li> sampleRate - usually 8000, 11025, 16000, 22050, or 44100 hz. - * <li> bitsPerSample - usually 16 for PCM, 8 for ALAW, or 8 for ULAW. - * <li> numBytes - size of audio data after this header, in bytes. - * </ul> - * - * Not yet ready to be supported, so - * @hide - */ -public class WaveHeader { - - // follows WAVE format in http://ccrma.stanford.edu/courses/422/projects/WaveFormat - - private static final String TAG = "WaveHeader"; - - private static final int HEADER_LENGTH = 44; - - /** Indicates PCM format. */ - public static final short FORMAT_PCM = 1; - /** Indicates ALAW format. */ - public static final short FORMAT_ALAW = 6; - /** Indicates ULAW format. */ - public static final short FORMAT_ULAW = 7; - - private short mFormat; - private short mNumChannels; - private int mSampleRate; - private short mBitsPerSample; - private int mNumBytes; - - /** - * Construct a WaveHeader, with all fields defaulting to zero. - */ - public WaveHeader() { - } - - /** - * Construct a WaveHeader, with fields initialized. - * @param format format of audio data, - * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. - * @param numChannels 1 for mono, 2 for stereo. - * @param sampleRate typically 8000, 11025, 16000, 22050, or 44100 hz. - * @param bitsPerSample usually 16 for PCM, 8 for ULAW or 8 for ALAW. - * @param numBytes size of audio data after this header, in bytes. - */ - public WaveHeader(short format, short numChannels, int sampleRate, short bitsPerSample, int numBytes) { - mFormat = format; - mSampleRate = sampleRate; - mNumChannels = numChannels; - mBitsPerSample = bitsPerSample; - mNumBytes = numBytes; - } - - /** - * Get the format field. - * @return format field, - * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. - */ - public short getFormat() { - return mFormat; - } - - /** - * Set the format field. - * @param format - * one of {@link #FORMAT_PCM}, {@link #FORMAT_ULAW}, or {@link #FORMAT_ALAW}. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setFormat(short format) { - mFormat = format; - return this; - } - - /** - * Get the number of channels. - * @return number of channels, 1 for mono, 2 for stereo. - */ - public short getNumChannels() { - return mNumChannels; - } - - /** - * Set the number of channels. - * @param numChannels 1 for mono, 2 for stereo. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setNumChannels(short numChannels) { - mNumChannels = numChannels; - return this; - } - - /** - * Get the sample rate. - * @return sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz. - */ - public int getSampleRate() { - return mSampleRate; - } - - /** - * Set the sample rate. - * @param sampleRate sample rate, typically 8000, 11025, 16000, 22050, or 44100 hz. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setSampleRate(int sampleRate) { - mSampleRate = sampleRate; - return this; - } - - /** - * Get the number of bits per sample. - * @return number of bits per sample, - * usually 16 for PCM, 8 for ULAW or 8 for ALAW. - */ - public short getBitsPerSample() { - return mBitsPerSample; - } - - /** - * Set the number of bits per sample. - * @param bitsPerSample number of bits per sample, - * usually 16 for PCM, 8 for ULAW or 8 for ALAW. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setBitsPerSample(short bitsPerSample) { - mBitsPerSample = bitsPerSample; - return this; - } - - /** - * Get the size of audio data after this header, in bytes. - * @return size of audio data after this header, in bytes. - */ - public int getNumBytes() { - return mNumBytes; - } - - /** - * Set the size of audio data after this header, in bytes. - * @param numBytes size of audio data after this header, in bytes. - * @return reference to this WaveHeader instance. - */ - public WaveHeader setNumBytes(int numBytes) { - mNumBytes = numBytes; - return this; - } - - /** - * Read and initialize a WaveHeader. - * @param in {@link java.io.InputStream} to read from. - * @return number of bytes consumed. - * @throws IOException - */ - public int read(InputStream in) throws IOException { - /* RIFF header */ - readId(in, "RIFF"); - int numBytes = readInt(in) - 36; - readId(in, "WAVE"); - - /* fmt chunk */ - readId(in, "fmt "); - if (16 != readInt(in)) throw new IOException("fmt chunk length not 16"); - mFormat = readShort(in); - mNumChannels = readShort(in); - mSampleRate = readInt(in); - int byteRate = readInt(in); - short blockAlign = readShort(in); - mBitsPerSample = readShort(in); - if (byteRate != mNumChannels * mSampleRate * mBitsPerSample / 8) { - throw new IOException("fmt.ByteRate field inconsistent"); - } - if (blockAlign != mNumChannels * mBitsPerSample / 8) { - throw new IOException("fmt.BlockAlign field inconsistent"); - } - - /* data chunk */ - readId(in, "data"); - mNumBytes = readInt(in); - - return HEADER_LENGTH; - } - - private static void readId(InputStream in, String id) throws IOException { - for (int i = 0; i < id.length(); i++) { - if (id.charAt(i) != in.read()) throw new IOException( id + " tag not present"); - } - } - - private static int readInt(InputStream in) throws IOException { - return in.read() | (in.read() << 8) | (in.read() << 16) | (in.read() << 24); - } - - private static short readShort(InputStream in) throws IOException { - return (short)(in.read() | (in.read() << 8)); - } - - /** - * Write a WAVE file header. - * @param out {@link java.io.OutputStream} to receive the header. - * @return number of bytes written. - * @throws IOException - */ - public int write(OutputStream out) throws IOException { - /* RIFF header */ - writeId(out, "RIFF"); - writeInt(out, 36 + mNumBytes); - writeId(out, "WAVE"); - - /* fmt chunk */ - writeId(out, "fmt "); - writeInt(out, 16); - writeShort(out, mFormat); - writeShort(out, mNumChannels); - writeInt(out, mSampleRate); - writeInt(out, mNumChannels * mSampleRate * mBitsPerSample / 8); - writeShort(out, (short)(mNumChannels * mBitsPerSample / 8)); - writeShort(out, mBitsPerSample); - - /* data chunk */ - writeId(out, "data"); - writeInt(out, mNumBytes); - - return HEADER_LENGTH; - } - - private static void writeId(OutputStream out, String id) throws IOException { - for (int i = 0; i < id.length(); i++) out.write(id.charAt(i)); - } - - private static void writeInt(OutputStream out, int val) throws IOException { - out.write(val >> 0); - out.write(val >> 8); - out.write(val >> 16); - out.write(val >> 24); - } - - private static void writeShort(OutputStream out, short val) throws IOException { - out.write(val >> 0); - out.write(val >> 8); - } - - @Override - public String toString() { - return String.format( - "WaveHeader format=%d numChannels=%d sampleRate=%d bitsPerSample=%d numBytes=%d", - mFormat, mNumChannels, mSampleRate, mBitsPerSample, mNumBytes); - } - -} diff --git a/core/java/android/speech/srec/package.html b/core/java/android/speech/srec/package.html deleted file mode 100644 index 9a99df8..0000000 --- a/core/java/android/speech/srec/package.html +++ /dev/null @@ -1,6 +0,0 @@ -<HTML> -<BODY> -Simple, synchronous SREC speech recognition API. -@hide -</BODY> -</HTML> diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index bac668a..8b74a1e 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -557,7 +557,7 @@ public abstract class Visibility extends Transition { if (mIsForcedVisibility) { mView.setTransitionAlpha(0); } else { - mView.setTransitionVisibility(mFinalVisibility); + mView.setVisibility(mFinalVisibility); } } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 89743e5..73cfd8c 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2939,11 +2939,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - /** @hide */ @Override - public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { - super.onInitializeAccessibilityEventInternal(event); - event.setClassName(ViewGroup.class.getName()); + public CharSequence getAccessibilityClassName() { + return ViewGroup.class.getName(); } @Override diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java index 195a335..e77dc0d 100644 --- a/core/java/android/view/textservice/SpellCheckerSession.java +++ b/core/java/android/view/textservice/SpellCheckerSession.java @@ -28,9 +28,6 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.util.Log; -import android.view.textservice.SpellCheckerInfo; -import android.view.textservice.SuggestionsInfo; -import android.view.textservice.TextInfo; import java.util.LinkedList; import java.util.Queue; @@ -226,17 +223,44 @@ public class SpellCheckerSession { private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2; private static final int TASK_CLOSE = 3; private static final int TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE = 4; - private final Queue<SpellCheckerParams> mPendingTasks = - new LinkedList<SpellCheckerParams>(); + private static String taskToString(int task) { + switch (task) { + case TASK_CANCEL: + return "TASK_CANCEL"; + case TASK_GET_SUGGESTIONS_MULTIPLE: + return "TASK_GET_SUGGESTIONS_MULTIPLE"; + case TASK_CLOSE: + return "TASK_CLOSE"; + case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE: + return "TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE"; + default: + return "Unexpected task=" + task; + } + } + + private final Queue<SpellCheckerParams> mPendingTasks = new LinkedList<>(); private Handler mHandler; - private boolean mOpened; + private static final int STATE_WAIT_CONNECTION = 0; + private static final int STATE_CONNECTED = 1; + private static final int STATE_CLOSED_AFTER_CONNECTION = 2; + private static final int STATE_CLOSED_BEFORE_CONNECTION = 3; + private static String stateToString(int state) { + switch (state) { + case STATE_WAIT_CONNECTION: return "STATE_WAIT_CONNECTION"; + case STATE_CONNECTED: return "STATE_CONNECTED"; + case STATE_CLOSED_AFTER_CONNECTION: return "STATE_CLOSED_AFTER_CONNECTION"; + case STATE_CLOSED_BEFORE_CONNECTION: return "STATE_CLOSED_BEFORE_CONNECTION"; + default: return "Unexpected state=" + state; + } + } + private int mState = STATE_WAIT_CONNECTION; + private ISpellCheckerSession mISpellCheckerSession; private HandlerThread mThread; private Handler mAsyncHandler; public SpellCheckerSessionListenerImpl(Handler handler) { - mOpened = false; mHandler = handler; } @@ -257,12 +281,18 @@ public class SpellCheckerSession { private void processTask(ISpellCheckerSession session, SpellCheckerParams scp, boolean async) { + if (DBG) { + synchronized (this) { + Log.d(TAG, "entering processTask:" + + " session.hashCode()=#" + Integer.toHexString(session.hashCode()) + + " scp.mWhat=" + taskToString(scp.mWhat) + " async=" + async + + " mAsyncHandler=" + mAsyncHandler + + " mState=" + stateToString(mState)); + } + } if (async || mAsyncHandler == null) { switch (scp.mWhat) { case TASK_CANCEL: - if (DBG) { - Log.w(TAG, "Cancel spell checker tasks."); - } try { session.onCancel(); } catch (RemoteException e) { @@ -270,9 +300,6 @@ public class SpellCheckerSession { } break; case TASK_GET_SUGGESTIONS_MULTIPLE: - if (DBG) { - Log.w(TAG, "Get suggestions from the spell checker."); - } try { session.onGetSuggestionsMultiple(scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords); @@ -281,9 +308,6 @@ public class SpellCheckerSession { } break; case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE: - if (DBG) { - Log.w(TAG, "Get sentence suggestions from the spell checker."); - } try { session.onGetSentenceSuggestionsMultiple( scp.mTextInfos, scp.mSuggestionsLimit); @@ -292,9 +316,6 @@ public class SpellCheckerSession { } break; case TASK_CLOSE: - if (DBG) { - Log.w(TAG, "Close spell checker tasks."); - } try { session.onClose(); } catch (RemoteException e) { @@ -313,21 +334,62 @@ public class SpellCheckerSession { // If we are closing, we want to clean up our state now even // if it is pending as an async operation. synchronized (this) { - mISpellCheckerSession = null; - mHandler = null; - if (mThread != null) { - mThread.quit(); - } - mThread = null; - mAsyncHandler = null; + processCloseLocked(); } } } + private void processCloseLocked() { + if (DBG) Log.d(TAG, "entering processCloseLocked:" + + " session" + (mISpellCheckerSession != null ? ".hashCode()=#" + + Integer.toHexString(mISpellCheckerSession.hashCode()) : "=null") + + " mState=" + stateToString(mState)); + mISpellCheckerSession = null; + if (mThread != null) { + mThread.quit(); + } + mHandler = null; + mPendingTasks.clear(); + mThread = null; + mAsyncHandler = null; + switch (mState) { + case STATE_WAIT_CONNECTION: + mState = STATE_CLOSED_BEFORE_CONNECTION; + break; + case STATE_CONNECTED: + mState = STATE_CLOSED_AFTER_CONNECTION; + break; + default: + Log.e(TAG, "processCloseLocked is called unexpectedly. mState=" + + stateToString(mState)); + break; + } + } + public synchronized void onServiceConnected(ISpellCheckerSession session) { synchronized (this) { + switch (mState) { + case STATE_WAIT_CONNECTION: + // OK, go ahead. + break; + case STATE_CLOSED_BEFORE_CONNECTION: + // This is possible, and not an error. The client no longer is interested + // in this connection. OK to ignore. + if (DBG) Log.i(TAG, "ignoring onServiceConnected since the session is" + + " already closed."); + return; + default: + Log.e(TAG, "ignoring onServiceConnected due to unexpected mState=" + + stateToString(mState)); + return; + } + if (session == null) { + Log.e(TAG, "ignoring onServiceConnected due to session=null"); + return; + } mISpellCheckerSession = session; if (session.asBinder() instanceof Binder && mThread == null) { + if (DBG) Log.d(TAG, "starting HandlerThread in onServiceConnected."); // If this is a local object, we need to do our own threading // to make sure we handle it asynchronously. mThread = new HandlerThread("SpellCheckerSession", @@ -340,62 +402,65 @@ public class SpellCheckerSession { } }; } - mOpened = true; + mState = STATE_CONNECTED; + if (DBG) { + Log.d(TAG, "processed onServiceConnected: mISpellCheckerSession.hashCode()=#" + + Integer.toHexString(mISpellCheckerSession.hashCode()) + + " mPendingTasks.size()=" + mPendingTasks.size()); + } } - if (DBG) - Log.d(TAG, "onServiceConnected - Success"); while (!mPendingTasks.isEmpty()) { processTask(session, mPendingTasks.poll(), false); } } public void cancel() { - if (DBG) { - Log.w(TAG, "cancel"); - } processOrEnqueueTask(new SpellCheckerParams(TASK_CANCEL, null, 0, false)); } public void getSuggestionsMultiple( TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { - if (DBG) { - Log.w(TAG, "getSuggestionsMultiple"); - } processOrEnqueueTask( new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos, suggestionsLimit, sequentialWords)); } public void getSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) { - if (DBG) { - Log.w(TAG, "getSentenceSuggestionsMultiple"); - } processOrEnqueueTask( new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE, textInfos, suggestionsLimit, false)); } public void close() { - if (DBG) { - Log.w(TAG, "close"); - } processOrEnqueueTask(new SpellCheckerParams(TASK_CLOSE, null, 0, false)); } public boolean isDisconnected() { - return mOpened && mISpellCheckerSession == null; + synchronized (this) { + return mState != STATE_CONNECTED; + } } private void processOrEnqueueTask(SpellCheckerParams scp) { - if (DBG) { - Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession); - } ISpellCheckerSession session; synchronized (this) { - session = mISpellCheckerSession; - if (session == null) { + if (mState != STATE_WAIT_CONNECTION && mState != STATE_CONNECTED) { + Log.e(TAG, "ignoring processOrEnqueueTask due to unexpected mState=" + + taskToString(scp.mWhat) + + " scp.mWhat=" + taskToString(scp.mWhat)); + return; + } + + if (mState == STATE_WAIT_CONNECTION) { + // If we are still waiting for the connection. Need to pay special attention. + if (scp.mWhat == TASK_CLOSE) { + processCloseLocked(); + return; + } + // Enqueue the task to task queue. SpellCheckerParams closeTask = null; if (scp.mWhat == TASK_CANCEL) { + if (DBG) Log.d(TAG, "canceling pending tasks in processOrEnqueueTask."); while (!mPendingTasks.isEmpty()) { final SpellCheckerParams tmp = mPendingTasks.poll(); if (tmp.mWhat == TASK_CLOSE) { @@ -409,9 +474,15 @@ public class SpellCheckerSession { if (closeTask != null) { mPendingTasks.offer(closeTask); } + if (DBG) Log.d(TAG, "queueing tasks in processOrEnqueueTask since the" + + " connection is not established." + + " mPendingTasks.size()=" + mPendingTasks.size()); return; } + + session = mISpellCheckerSession; } + // session must never be null here. processTask(session, scp, false); } @@ -467,9 +538,6 @@ public class SpellCheckerSession { @Override public void onServiceConnected(ISpellCheckerSession session) { - if (DBG) { - Log.w(TAG, "SpellCheckerSession connected."); - } mParentSpellCheckerSessionListenerImpl.onServiceConnected(session); } } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index cf6a018..f89ee91 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -244,15 +244,6 @@ public class Editor { final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier(); - private final Runnable mHideFloatingToolbar = new Runnable() { - @Override - public void run() { - if (mTextActionMode != null) { - mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION); - } - } - }; - private final Runnable mShowFloatingToolbar = new Runnable() { @Override public void run() { @@ -389,7 +380,6 @@ public class Editor { mTextView.removeCallbacks(mInsertionActionModeRunnable); } - mTextView.removeCallbacks(mHideFloatingToolbar); mTextView.removeCallbacks(mShowFloatingToolbar); destroyDisplayListsData(); @@ -1248,14 +1238,12 @@ public class Editor { private void hideFloatingToolbar() { if (mTextActionMode != null) { mTextView.removeCallbacks(mShowFloatingToolbar); - // Delay the "hide" a little bit just in case a "show" will happen almost immediately. - mTextView.postDelayed(mHideFloatingToolbar, 100); + mTextActionMode.hide(ActionMode.DEFAULT_HIDE_DURATION); } } private void showFloatingToolbar() { if (mTextActionMode != null) { - mTextView.removeCallbacks(mHideFloatingToolbar); // Delay "show" so it doesn't interfere with click confirmations // or double-clicks that could "dismiss" the floating toolbar. int delay = ViewConfiguration.getDoubleTapTimeout(); diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 8ace0f3..2ea2667 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -26,7 +26,6 @@ import android.annotation.StyleRes; import android.app.ActionBar; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; @@ -148,6 +147,9 @@ public class Toolbar extends ViewGroup { // Clear me after use. private final ArrayList<View> mTempViews = new ArrayList<View>(); + // Used to hold views that will be removed while we have an expanded action view. + private final ArrayList<View> mHiddenViews = new ArrayList<>(); + private final int[] mTempMargins = new int[2]; private OnMenuItemClickListener mOnMenuItemClickListener; @@ -435,12 +437,12 @@ public class Toolbar extends ViewGroup { public void setLogo(Drawable drawable) { if (drawable != null) { ensureLogoView(); - if (mLogoView.getParent() == null) { - addSystemView(mLogoView); - updateChildVisibilityForExpandedActionView(mLogoView); + if (!isChildOrHidden(mLogoView)) { + addSystemView(mLogoView, true); } - } else if (mLogoView != null && mLogoView.getParent() != null) { + } else if (mLogoView != null && isChildOrHidden(mLogoView)) { removeView(mLogoView); + mHiddenViews.remove(mLogoView); } if (mLogoView != null) { mLogoView.setImageDrawable(drawable); @@ -577,12 +579,12 @@ public class Toolbar extends ViewGroup { mTitleTextView.setTextColor(mTitleTextColor); } } - if (mTitleTextView.getParent() == null) { - addSystemView(mTitleTextView); - updateChildVisibilityForExpandedActionView(mTitleTextView); + if (!isChildOrHidden(mTitleTextView)) { + addSystemView(mTitleTextView, true); } - } else if (mTitleTextView != null && mTitleTextView.getParent() != null) { + } else if (mTitleTextView != null && isChildOrHidden(mTitleTextView)) { removeView(mTitleTextView); + mHiddenViews.remove(mTitleTextView); } if (mTitleTextView != null) { mTitleTextView.setText(title); @@ -631,12 +633,12 @@ public class Toolbar extends ViewGroup { mSubtitleTextView.setTextColor(mSubtitleTextColor); } } - if (mSubtitleTextView.getParent() == null) { - addSystemView(mSubtitleTextView); - updateChildVisibilityForExpandedActionView(mSubtitleTextView); + if (!isChildOrHidden(mSubtitleTextView)) { + addSystemView(mSubtitleTextView, true); } - } else if (mSubtitleTextView != null && mSubtitleTextView.getParent() != null) { + } else if (mSubtitleTextView != null && isChildOrHidden(mSubtitleTextView)) { removeView(mSubtitleTextView); + mHiddenViews.remove(mSubtitleTextView); } if (mSubtitleTextView != null) { mSubtitleTextView.setText(subtitle); @@ -772,12 +774,12 @@ public class Toolbar extends ViewGroup { public void setNavigationIcon(@Nullable Drawable icon) { if (icon != null) { ensureNavButtonView(); - if (mNavButtonView.getParent() == null) { - addSystemView(mNavButtonView); - updateChildVisibilityForExpandedActionView(mNavButtonView); + if (!isChildOrHidden(mNavButtonView)) { + addSystemView(mNavButtonView, true); } - } else if (mNavButtonView != null && mNavButtonView.getParent() != null) { + } else if (mNavButtonView != null && isChildOrHidden(mNavButtonView)) { removeView(mNavButtonView); + mHiddenViews.remove(mNavButtonView); } if (mNavButtonView != null) { mNavButtonView.setImageDrawable(icon); @@ -866,7 +868,7 @@ public class Toolbar extends ViewGroup { final LayoutParams lp = generateDefaultLayoutParams(); lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK); mMenuView.setLayoutParams(lp); - addSystemView(mMenuView); + addSystemView(mMenuView, false); } } @@ -1041,7 +1043,7 @@ public class Toolbar extends ViewGroup { } } - private void addSystemView(View v) { + private void addSystemView(View v, boolean allowHide) { final ViewGroup.LayoutParams vlp = v.getLayoutParams(); final LayoutParams lp; if (vlp == null) { @@ -1052,7 +1054,13 @@ public class Toolbar extends ViewGroup { lp = (LayoutParams) vlp; } lp.mViewType = LayoutParams.SYSTEM; - addView(v, lp); + + if (allowHide && mExpandedActionView != null) { + v.setLayoutParams(lp); + mHiddenViews.add(v); + } else { + addView(v, lp); + } } @Override @@ -1741,22 +1749,30 @@ public class Toolbar extends ViewGroup { return mWrapper; } - private void setChildVisibilityForExpandedActionView(boolean expand) { + void removeChildrenForExpandedActionView() { final int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { + // Go backwards since we're removing from the list + for (int i = childCount - 1; i >= 0; i--) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) { - child.setVisibility(expand ? GONE : VISIBLE); + removeViewAt(i); + mHiddenViews.add(child); } } } - private void updateChildVisibilityForExpandedActionView(View child) { - final LayoutParams lp = (LayoutParams) child.getLayoutParams(); - if (lp.mViewType != LayoutParams.EXPANDED && child != mMenuView) { - child.setVisibility(mExpandedActionView != null ? GONE : VISIBLE); + void addChildrenForExpandedActionView() { + final int count = mHiddenViews.size(); + // Re-add in reverse order since we removed in reverse order + for (int i = count - 1; i >= 0; i--) { + addView(mHiddenViews.get(i)); } + mHiddenViews.clear(); + } + + private boolean isChildOrHidden(View child) { + return child.getParent() == this || mHiddenViews.contains(child); } /** @@ -1971,7 +1987,7 @@ public class Toolbar extends ViewGroup { addView(mExpandedActionView); } - setChildVisibilityForExpandedActionView(true); + removeChildrenForExpandedActionView(); requestLayout(); item.setActionViewExpanded(true); @@ -1994,7 +2010,7 @@ public class Toolbar extends ViewGroup { removeView(mCollapseButtonView); mExpandedActionView = null; - setChildVisibilityForExpandedActionView(false); + addChildrenForExpandedActionView(); mCurrentExpandedItem = null; requestLayout(); item.setActionViewExpanded(false); diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java index 34b9dcb..2b162af 100644 --- a/core/java/com/android/internal/app/ToolbarActionBar.java +++ b/core/java/com/android/internal/app/ToolbarActionBar.java @@ -83,7 +83,9 @@ public class ToolbarActionBar extends ActionBar { @Override public void setCustomView(View view, LayoutParams layoutParams) { - view.setLayoutParams(layoutParams); + if (view != null) { + view.setLayoutParams(layoutParams); + } mDecorToolbar.setCustomView(view); } diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 661dce1..99c1277 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -48,12 +48,14 @@ public class FloatingActionMode extends ActionMode { private final Runnable mMovingOff = new Runnable() { public void run() { mFloatingToolbarVisibilityHelper.setMoving(false); + mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); } }; private final Runnable mHideOff = new Runnable() { public void run() { mFloatingToolbarVisibilityHelper.setHideRequested(false); + mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); } }; @@ -87,6 +89,7 @@ public class FloatingActionMode extends ActionMode { } }); mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar); + mFloatingToolbarVisibilityHelper.activate(); } @Override @@ -108,8 +111,7 @@ public class FloatingActionMode extends ActionMode { public void invalidate() { checkToolbarInitialized(); mCallback.onPrepareActionMode(this, mMenu); - mFloatingToolbar.updateLayout(); - invalidateContentRect(); + invalidateContentRect(); // Will re-layout and show the toolbar if necessary. } @Override @@ -131,44 +133,43 @@ public class FloatingActionMode extends ActionMode { mContentRectOnWindow.set(mContentRect); mContentRectOnWindow.offset(mViewPosition[0], mViewPosition[1]); - // Make sure that content rect is not out of the view's visible bounds. - mContentRectOnWindow.set( - Math.max(mContentRectOnWindow.left, mViewRect.left), - Math.max(mContentRectOnWindow.top, mViewRect.top), - Math.min(mContentRectOnWindow.right, mViewRect.right), - Math.min(mContentRectOnWindow.bottom, mViewRect.bottom)); - - if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) { - if (!mPreviousContentRectOnWindow.isEmpty()) { - notifyContentRectMoving(); - } - mFloatingToolbar.setContentRect(mContentRectOnWindow); - mFloatingToolbar.updateLayout(); - } - mPreviousContentRectOnWindow.set(mContentRectOnWindow); if (isContentRectWithinBounds()) { mFloatingToolbarVisibilityHelper.setOutOfBounds(false); + // Make sure that content rect is not out of the view's visible bounds. + mContentRectOnWindow.set( + Math.max(mContentRectOnWindow.left, mViewRect.left), + Math.max(mContentRectOnWindow.top, mViewRect.top), + Math.min(mContentRectOnWindow.right, mViewRect.right), + Math.min(mContentRectOnWindow.bottom, mViewRect.bottom)); + + if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) { + // Content rect is moving. + mOriginatingView.removeCallbacks(mMovingOff); + mFloatingToolbarVisibilityHelper.setMoving(true); + mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY); + + mFloatingToolbar.setContentRect(mContentRectOnWindow); + mFloatingToolbar.updateLayout(); + } } else { mFloatingToolbarVisibilityHelper.setOutOfBounds(true); + mContentRectOnWindow.setEmpty(); } - } + mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); - private boolean isContentRectWithinBounds() { - mScreenRect.set( - 0, - 0, - mContext.getResources().getDisplayMetrics().widthPixels, - mContext.getResources().getDisplayMetrics().heightPixels); - - return Rect.intersects(mContentRectOnWindow, mScreenRect) - && Rect.intersects(mContentRectOnWindow, mViewRect); + mPreviousContentRectOnWindow.set(mContentRectOnWindow); } - private void notifyContentRectMoving() { - mOriginatingView.removeCallbacks(mMovingOff); - mFloatingToolbarVisibilityHelper.setMoving(true); - mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY); + private boolean isContentRectWithinBounds() { + mScreenRect.set( + 0, + 0, + mContext.getResources().getDisplayMetrics().widthPixels, + mContext.getResources().getDisplayMetrics().heightPixels); + + return Rect.intersects(mContentRectOnWindow, mScreenRect) + && Rect.intersects(mContentRectOnWindow, mViewRect); } @Override @@ -184,6 +185,7 @@ public class FloatingActionMode extends ActionMode { mHideOff.run(); } else { mFloatingToolbarVisibilityHelper.setHideRequested(true); + mFloatingToolbarVisibilityHelper.updateToolbarVisibility(); mOriginatingView.postDelayed(mHideOff, duration); } } @@ -221,7 +223,7 @@ public class FloatingActionMode extends ActionMode { } /** - * @throws IlllegalStateException + * @throws IllegalStateException */ private void checkToolbarInitialized() { Preconditions.checkState(mFloatingToolbar != null); @@ -229,13 +231,14 @@ public class FloatingActionMode extends ActionMode { } private void reset() { + mFloatingToolbarVisibilityHelper.deactivate(); mOriginatingView.removeCallbacks(mMovingOff); mOriginatingView.removeCallbacks(mHideOff); } /** - * A helper that shows/hides the floating toolbar depending on certain states. + * A helper for showing/hiding the floating toolbar depending on certain states. */ private static final class FloatingToolbarVisibilityHelper { @@ -245,29 +248,45 @@ public class FloatingActionMode extends ActionMode { private boolean mMoving; private boolean mOutOfBounds; + private boolean mActive; + public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) { mToolbar = Preconditions.checkNotNull(toolbar); } + public void activate() { + mHideRequested = false; + mMoving = false; + mOutOfBounds = false; + + mActive = true; + } + + public void deactivate() { + mActive = false; + mToolbar.dismiss(); + } + public void setHideRequested(boolean hide) { mHideRequested = hide; - updateToolbarVisibility(); } public void setMoving(boolean moving) { mMoving = moving; - updateToolbarVisibility(); } public void setOutOfBounds(boolean outOfBounds) { mOutOfBounds = outOfBounds; - updateToolbarVisibility(); } - private void updateToolbarVisibility() { + public void updateToolbarVisibility() { + if (!mActive) { + return; + } + if (mHideRequested || mMoving || mOutOfBounds) { mToolbar.hide(); - } else if (mToolbar.isHidden()) { + } else { mToolbar.show(); } } diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java index 3f4b980..c0215a8 100644 --- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java +++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java @@ -28,8 +28,6 @@ import android.app.backup.BackupHelper; import android.content.ContentResolver; import android.content.Context; import android.content.SyncAdapterType; -import android.content.SyncStatusObserver; -import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.util.Log; @@ -47,8 +45,6 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; /** * Helper for backing up account sync settings (whether or not a service should be synced). The @@ -270,6 +266,10 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper { // yet won't be restored. if (currentAccounts.contains(account)) { restoreExistingAccountSyncSettingsFromJSON(accountJSON); + } else { + // TODO: + // Stash the data to a file that the SyncManager can read from to restore + // settings at a later date. } } } finally { @@ -300,6 +300,31 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper { /** * Restore account sync settings using the given JSON. This function won't work if the account * doesn't exist yet. + * This function will only be called during Setup Wizard, where we are guaranteed that there + * are no active syncs. + * There are 2 pieces of data to restore - + * isSyncable (corresponds to {@link ContentResolver#getIsSyncable(Account, String)} + * syncEnabled (corresponds to {@link ContentResolver#getSyncAutomatically(Account, String)} + * <strong>The restore favours adapters that were enabled on the old device, and doesn't care + * about adapters that were disabled.</strong> + * + * syncEnabled=true in restore data. + * syncEnabled will be true on this device. isSyncable will be left as the default in order to + * give the enabled adapter the chance to run an initialization sync. + * + * syncEnabled=false in restore data. + * syncEnabled will be false on this device. isSyncable will be set to 2, unless it was 0 on the + * old device in which case it will be set to 0 on this device. This is because isSyncable=0 is + * a rare state and was probably set to 0 for good reason (historically isSyncable is a way by + * which adapters control their own sync state independently of sync settings which is + * toggleable by the user). + * isSyncable=2 is a new isSyncable state we introduced specifically to allow adapters that are + * disabled after a restore to run initialization logic when the adapter is later enabled. + * See com.android.server.content.SyncStorageEngine#setSyncAutomatically + * + * The end result is that an adapter that the user had on will be turned on and get an + * initialization sync, while an adapter that the user had off will be off until the user + * enables it on this device at which point it will get an initialization sync. */ private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON) throws JSONException { @@ -307,72 +332,27 @@ public class AccountSyncSettingsBackupHelper implements BackupHelper { JSONArray authorities = accountJSON.getJSONArray(KEY_ACCOUNT_AUTHORITIES); String accountName = accountJSON.getString(KEY_ACCOUNT_NAME); String accountType = accountJSON.getString(KEY_ACCOUNT_TYPE); + final Account account = new Account(accountName, accountType); for (int i = 0; i < authorities.length(); i++) { JSONObject authority = (JSONObject) authorities.get(i); final String authorityName = authority.getString(KEY_AUTHORITY_NAME); - boolean syncEnabled = authority.getBoolean(KEY_AUTHORITY_SYNC_ENABLED); - - // Cancel any active syncs. - if (ContentResolver.isSyncActive(account, authorityName)) { - ContentResolver.cancelSync(account, authorityName); - } - - boolean overwriteSync = true; - Bundle initializationExtras = createSyncInitializationBundle(); - int currentSyncState = ContentResolver.getIsSyncable(account, authorityName); - if (currentSyncState < 0) { - // Requesting a sync is an asynchronous operation, so we setup a countdown latch to - // wait for it to finish. Initialization syncs are generally very brief and - // shouldn't take too much time to finish. - final CountDownLatch latch = new CountDownLatch(1); - Object syncStatusObserverHandle = ContentResolver.addStatusChangeListener( - ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE, new SyncStatusObserver() { - @Override - public void onStatusChanged(int which) { - if (!ContentResolver.isSyncActive(account, authorityName)) { - latch.countDown(); - } - } - }); - - // If we set sync settings for a sync that hasn't been initialized yet, we run the - // risk of having our changes overwritten later on when the sync gets initialized. - // To prevent this from happening we will manually initiate the sync adapter. We - // also explicitly pass in a Bundle with SYNC_EXTRAS_INITIALIZE to prevent a data - // sync from running after the initialization sync. Two syncs will be scheduled, but - // the second one (data sync) will override the first one (initialization sync) and - // still behave as an initialization sync because of the Bundle. - ContentResolver.requestSync(account, authorityName, initializationExtras); - - boolean done = false; - try { - done = latch.await(SYNC_REQUEST_LATCH_TIMEOUT_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Log.e(TAG, "CountDownLatch interrupted\n" + e); - done = false; - } - if (!done) { - overwriteSync = false; - Log.i(TAG, "CountDownLatch timed out, skipping '" + authorityName - + "' authority."); - } - ContentResolver.removeStatusChangeListener(syncStatusObserverHandle); - } - - if (overwriteSync) { - ContentResolver.setSyncAutomatically(account, authorityName, syncEnabled); - Log.i(TAG, "Set sync automatically for '" + authorityName + "': " + syncEnabled); + boolean wasSyncEnabled = authority.getBoolean(KEY_AUTHORITY_SYNC_ENABLED); + int wasSyncable = authority.getInt(KEY_AUTHORITY_SYNC_STATE); + + ContentResolver.setSyncAutomaticallyAsUser( + account, authorityName, wasSyncEnabled, 0 /* user Id */); + + if (!wasSyncEnabled) { + ContentResolver.setIsSyncable( + account, + authorityName, + wasSyncable == 0 ? + 0 /* not syncable */ : 2 /* syncable but needs initialization */); } } } - private Bundle createSyncInitializationBundle() { - Bundle extras = new Bundle(); - extras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); - return extras; - } - @Override public void writeNewStateDescription(ParcelFileDescriptor newState) { diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index 2229071..7d8d151 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -371,8 +371,8 @@ ssize_t JniInputByteBuffer::read(uint8_t* buf, size_t offset, size_t count) { realCount = count; } - jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, mByteArray, 0, - realCount); + jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, + mByteArray, 0, realCount); mEnv->DeleteLocalRef(chainingBuf); if (mEnv->ExceptionCheck()) { @@ -630,8 +630,10 @@ static bool validateDngHeader(JNIEnv* env, TiffWriter* writer, jint width, jint bool hasThumbnail = writer->hasIfd(TIFF_IFD_SUB1); // TODO: handle lens shading map, etc. conversions for other raw buffer sizes. - uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, (hasThumbnail) ? TIFF_IFD_SUB1 : TIFF_IFD_0)->getData<uint32_t>()); - uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, (hasThumbnail) ? TIFF_IFD_SUB1 : TIFF_IFD_0)->getData<uint32_t>()); + uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, (hasThumbnail) ? TIFF_IFD_SUB1 : + TIFF_IFD_0)->getData<uint32_t>()); + uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, (hasThumbnail) ? TIFF_IFD_SUB1 : + TIFF_IFD_0)->getData<uint32_t>()); if (width < 0 || metadataWidth != static_cast<uint32_t>(width)) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ @@ -641,7 +643,8 @@ static bool validateDngHeader(JNIEnv* env, TiffWriter* writer, jint width, jint if (height < 0 || metadataHeight != static_cast<uint32_t>(height)) { jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", \ - "Metadata height %d doesn't match image height %d", metadataHeight, height); + "Metadata height %d doesn't match image height %d", + metadataHeight, height); return false; } @@ -1428,7 +1431,11 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt } { - // Setup opcode List 2 + // Set up opcode List 2 + OpcodeListBuilder builder; + status_t err = OK; + + // Set up lens shading map camera_metadata_entry entry1 = characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE); @@ -1444,34 +1451,71 @@ static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPt results.find(ANDROID_STATISTICS_LENS_SHADING_MAP); if (entry2.count > 0 && entry2.count == lsmWidth * lsmHeight * 4) { - - OpcodeListBuilder builder; - status_t err = builder.addGainMapsForMetadata(lsmWidth, - lsmHeight, - 0, - 0, - imageHeight, - imageWidth, - opcodeCfaLayout, - entry2.data.f); - if (err == OK) { - size_t listSize = builder.getSize(); - uint8_t opcodeListBuf[listSize]; - err = builder.buildOpList(opcodeListBuf); - if (err == OK) { - BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf, - TIFF_IFD_0), env, TAG_OPCODELIST2, writer); - } else { - ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__); - jniThrowRuntimeException(env, "failed to construct lens shading map opcode."); - } - } else { + err = builder.addGainMapsForMetadata(lsmWidth, + lsmHeight, + 0, + 0, + imageHeight, + imageWidth, + opcodeCfaLayout, + entry2.data.f); + if (err != OK) { ALOGE("%s: Could not add Lens shading map.", __FUNCTION__); jniThrowRuntimeException(env, "failed to add lens shading map."); + return; } + } + + size_t listSize = builder.getSize(); + uint8_t opcodeListBuf[listSize]; + err = builder.buildOpList(opcodeListBuf); + if (err == OK) { + BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf, + TIFF_IFD_0), env, TAG_OPCODELIST2, writer); } else { - ALOGW("%s: No lens shading map found in result metadata. Image quality may be reduced.", - __FUNCTION__); + ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" + "map.", __FUNCTION__); + jniThrowRuntimeException(env, "failed to construct opcode list for distortion" + " correction and lens shading map"); + return; + } + } + + { + // Set up opcode List 3 + OpcodeListBuilder builder; + status_t err = OK; + + // Set up rectilinear distortion correction + camera_metadata_entry entry3 = + results.find(ANDROID_LENS_RADIAL_DISTORTION); + camera_metadata_entry entry4 = + results.find(ANDROID_LENS_INTRINSIC_CALIBRATION); + + if (entry3.count == 6 && entry4.count == 5) { + float cx = entry4.data.f[/*c_x*/2]; + float cy = entry4.data.f[/*c_y*/3]; + err = builder.addWarpRectilinearForMetadata(entry3.data.f, imageWidth, imageHeight, cx, + cy); + if (err != OK) { + ALOGE("%s: Could not add distortion correction.", __FUNCTION__); + jniThrowRuntimeException(env, "failed to add distortion correction."); + return; + } + } + + size_t listSize = builder.getSize(); + uint8_t opcodeListBuf[listSize]; + err = builder.buildOpList(opcodeListBuf); + if (err == OK) { + BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST3, listSize, opcodeListBuf, + TIFF_IFD_0), env, TAG_OPCODELIST3, writer); + } else { + ALOGE("%s: Could not build list of opcodes for distortion correction and lens shading" + "map.", __FUNCTION__); + jniThrowRuntimeException(env, "failed to construct opcode list for distortion" + " correction and lens shading map"); + return; } } @@ -1693,6 +1737,7 @@ static void DngCreator_nativeSetThumbnail(JNIEnv* env, jobject thiz, jobject buf tagsToMove.add(TAG_DEFAULTCROPORIGIN); tagsToMove.add(TAG_DEFAULTCROPSIZE); tagsToMove.add(TAG_OPCODELIST2); + tagsToMove.add(TAG_OPCODELIST3); if (moveEntries(writer, TIFF_IFD_0, TIFF_IFD_SUB1, tagsToMove) != OK) { jniThrowException(env, "java/lang/IllegalStateException", "Failed to move entries"); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 1cd07d1..ac00532 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -677,13 +677,14 @@ static jint convertAudioPortConfigFromNative(JNIEnv *env, // constructed by java code with correct class type (device, mix etc...) // and reference to AudioPort instance in this client jAudioPort = env->NewObject(gAudioPortClass, gAudioPortCstor, - jHandle, - 0, - NULL, - NULL, - NULL, - NULL, - NULL); + jHandle, // handle + 0, // role + NULL, // name + NULL, // samplingRates + NULL, // channelMasks + NULL, // channelIndexMasks + NULL, // formats + NULL); // gains env->DeleteLocalRef(jHandle); if (jAudioPort == NULL) { return (jint)AUDIO_JAVA_ERROR; @@ -837,11 +838,14 @@ static jint convertAudioPortFromNative(JNIEnv *env, jint jStatus = (jint)AUDIO_JAVA_SUCCESS; jintArray jSamplingRates = NULL; jintArray jChannelMasks = NULL; + jintArray jChannelIndexMasks = NULL; jintArray jFormats = NULL; jobjectArray jGains = NULL; jobject jHandle = NULL; jstring jDeviceName = NULL; bool useInMask; + size_t numPositionMasks = 0; + size_t numIndexMasks = 0; ALOGV("convertAudioPortFromNative id %d role %d type %d name %s", nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name); @@ -856,23 +860,43 @@ static jint convertAudioPortFromNative(JNIEnv *env, (jint *)nAudioPort->sample_rates); } - jChannelMasks = env->NewIntArray(nAudioPort->num_channel_masks); + // count up how many masks are positional and indexed + for(size_t index = 0; index < nAudioPort->num_channel_masks; index++) { + const audio_channel_mask_t mask = nAudioPort->channel_masks[index]; + if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) { + numIndexMasks++; + } else { + numPositionMasks++; + } + } + + jChannelMasks = env->NewIntArray(numPositionMasks); if (jChannelMasks == NULL) { jStatus = (jint)AUDIO_JAVA_ERROR; goto exit; } + jChannelIndexMasks = env->NewIntArray(numIndexMasks); + if (jChannelIndexMasks == NULL) { + jStatus = (jint)AUDIO_JAVA_ERROR; + goto exit; + } useInMask = useInChannelMask(nAudioPort->type, nAudioPort->role); - jint jMask; - for (size_t j = 0; j < nAudioPort->num_channel_masks; j++) { - if (useInMask) { - jMask = inChannelMaskFromNative(nAudioPort->channel_masks[j]); + // put the masks in the output arrays + for (size_t maskIndex = 0, posMaskIndex = 0, indexedMaskIndex = 0; + maskIndex < nAudioPort->num_channel_masks; maskIndex++) { + const audio_channel_mask_t mask = nAudioPort->channel_masks[maskIndex]; + if (audio_channel_mask_get_representation(mask) == AUDIO_CHANNEL_REPRESENTATION_INDEX) { + jint jMask = audio_channel_mask_get_bits(mask); + env->SetIntArrayRegion(jChannelIndexMasks, indexedMaskIndex++, 1, &jMask); } else { - jMask = outChannelMaskFromNative(nAudioPort->channel_masks[j]); + jint jMask = useInMask ? inChannelMaskFromNative(mask) + : outChannelMaskFromNative(mask); + env->SetIntArrayRegion(jChannelMasks, posMaskIndex++, 1, &jMask); } - env->SetIntArrayRegion(jChannelMasks, j, 1, &jMask); } + // formats jFormats = env->NewIntArray(nAudioPort->num_formats); if (jFormats == NULL) { jStatus = (jint)AUDIO_JAVA_ERROR; @@ -883,14 +907,17 @@ static jint convertAudioPortFromNative(JNIEnv *env, env->SetIntArrayRegion(jFormats, j, 1, &jFormat); } + // gains jGains = env->NewObjectArray(nAudioPort->num_gains, gAudioGainClass, NULL); if (jGains == NULL) { jStatus = (jint)AUDIO_JAVA_ERROR; goto exit; } + for (size_t j = 0; j < nAudioPort->num_gains; j++) { audio_channel_mask_t nMask = nAudioPort->gains[j].channel_mask; + jint jMask; if (useInMask) { jMask = inChannelMaskFromNative(nMask); ALOGV("convertAudioPortConfigFromNative IN mask java %x native %x", jMask, nMask); @@ -931,7 +958,8 @@ static jint convertAudioPortFromNative(JNIEnv *env, jstring jAddress = env->NewStringUTF(nAudioPort->ext.device.address); *jAudioPort = env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor, jHandle, jDeviceName, - jSamplingRates, jChannelMasks, jFormats, jGains, + jSamplingRates, jChannelMasks, jChannelIndexMasks, + jFormats, jGains, nAudioPort->ext.device.type, jAddress); env->DeleteLocalRef(jAddress); } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) { @@ -939,7 +967,7 @@ static jint convertAudioPortFromNative(JNIEnv *env, *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor, jHandle, nAudioPort->ext.mix.handle, nAudioPort->role, jDeviceName, - jSamplingRates, jChannelMasks, + jSamplingRates, jChannelMasks, jChannelIndexMasks, jFormats, jGains); } else { ALOGE("convertAudioPortFromNative unknown nAudioPort type %d", nAudioPort->type); @@ -1634,7 +1662,7 @@ int register_android_media_AudioSystem(JNIEnv *env) jclass audioPortClass = FindClassOrDie(env, "android/media/AudioPort"); gAudioPortClass = MakeGlobalRefOrDie(env, audioPortClass); gAudioPortCstor = GetMethodIDOrDie(env, audioPortClass, "<init>", - "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V"); + "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V"); gAudioPortFields.mHandle = GetFieldIDOrDie(env, audioPortClass, "mHandle", "Landroid/media/AudioHandle;"); gAudioPortFields.mRole = GetFieldIDOrDie(env, audioPortClass, "mRole", "I"); @@ -1672,12 +1700,12 @@ int register_android_media_AudioSystem(JNIEnv *env) jclass audioDevicePortClass = FindClassOrDie(env, "android/media/AudioDevicePort"); gAudioDevicePortClass = MakeGlobalRefOrDie(env, audioDevicePortClass); gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>", - "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V"); + "(Landroid/media/AudioHandle;Ljava/lang/String;[I[I[I[I[Landroid/media/AudioGain;ILjava/lang/String;)V"); jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort"); gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass); gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>", - "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V"); + "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[I[Landroid/media/AudioGain;)V"); jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain"); gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass); diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp index 9a80f1d..2b1067b 100644 --- a/core/jni/android_util_Log.cpp +++ b/core/jni/android_util_Log.cpp @@ -41,32 +41,8 @@ struct levels_t { }; static levels_t levels; -static int toLevel(const char* value) -{ - switch (value[0]) { - case 'V': return levels.verbose; - case 'D': return levels.debug; - case 'I': return levels.info; - case 'W': return levels.warn; - case 'E': return levels.error; - case 'A': return levels.assert; - case 'S': return -1; // SUPPRESS - } - return levels.info; -} - static jboolean isLoggable(const char* tag, jint level) { - String8 key; - key.append(LOG_NAMESPACE); - key.append(tag); - - char buf[PROPERTY_VALUE_MAX]; - if (property_get(key.string(), buf, "") <= 0) { - buf[0] = '\0'; - } - - int logLevel = toLevel(buf); - return logLevel >= 0 && level >= logLevel; + return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO); } static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index 9307ff9..a526223 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -105,8 +105,8 @@ isFilenameSafe(const char* filename) } static bool -isFileDifferent(const char* filePath, size_t fileSize, time_t modifiedTime, - long zipCrc, struct stat64* st) +isFileDifferent(const char* filePath, uint32_t fileSize, time_t modifiedTime, + uint32_t zipCrc, struct stat64* st) { if (lstat64(filePath, st) < 0) { // File is not found or cannot be read. @@ -134,7 +134,9 @@ isFileDifferent(const char* filePath, size_t fileSize, time_t modifiedTime, return true; } - long crc = crc32(0L, Z_NULL, 0); + // uLong comes from zlib.h. It's a bit of a wart that they're + // potentially using a 64-bit type for a 32-bit CRC. + uLong crc = crc32(0L, Z_NULL, 0); unsigned char crcBuffer[16384]; ssize_t numBytes; while ((numBytes = TEMP_FAILURE_RETRY(read(fd, crcBuffer, sizeof(crcBuffer)))) > 0) { @@ -142,9 +144,9 @@ isFileDifferent(const char* filePath, size_t fileSize, time_t modifiedTime, } close(fd); - ALOGV("%s: crc = %lx, zipCrc = %lx\n", filePath, crc, zipCrc); + ALOGV("%s: crc = %lx, zipCrc = %" PRIu32 "\n", filePath, crc, zipCrc); - if (crc != zipCrc) { + if (crc != static_cast<uLong>(zipCrc)) { return true; } @@ -155,13 +157,13 @@ static install_status_t sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*) { size_t* total = (size_t*) arg; - size_t uncompLen; + uint32_t uncompLen; if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, NULL, NULL)) { return INSTALL_FAILED_INVALID_APK; } - *total += uncompLen; + *total += static_cast<size_t>(uncompLen); return INSTALL_SUCCEEDED; } @@ -181,12 +183,11 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr ScopedUtfChars nativeLibPath(env, *javaNativeLibPath); - size_t uncompLen; - long when; - long crc; - time_t modTime; + uint32_t uncompLen; + uint32_t when; + uint32_t crc; - int method; + uint16_t method; off64_t offset; if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) { @@ -233,7 +234,7 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr // Only copy out the native file if it's different. struct tm t; ZipUtils::zipTimeToTimespec(when, &t); - modTime = mktime(&t); + const time_t modTime = mktime(&t); struct stat64 st; if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) { return INSTALL_SUCCEEDED; diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index fb0455d..510f6a5 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1969,9 +1969,9 @@ <string name="lockscreen_access_pattern_start">Pattern started</string> <!-- Accessibility description sent when the pattern times out and is cleared. [CHAR LIMIT=NONE] --> <string name="lockscreen_access_pattern_cleared">Pattern cleared</string> - <!-- Accessibility description sent when user adds a cell to the pattern. [CHAR LIMIT=NONE] --> + <!-- Accessibility description sent when user adds a dot to the pattern. [CHAR LIMIT=NONE] --> <string name="lockscreen_access_pattern_cell_added">Cell added</string> - <!-- Accessibility description sent when user adds a cell to the pattern. Announces the + <!-- Accessibility description sent when user adds a dot to the pattern. Announces the actual cell when headphones are connected [CHAR LIMIT=NONE] --> <string name="lockscreen_access_pattern_cell_added_verbose"> Cell <xliff:g id="cell_index" example="3">%1$s</xliff:g> added</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d7b565c..5ba57c4 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2311,5 +2311,6 @@ <java-symbol type="string" name="ext_media_unsupported_notification_message" /> <java-symbol type="string" name="ext_media_unsupported_notification_title" /> <java-symbol type="plurals" name="selected_count" /> + <java-symbol type="drawable" name="ic_dialog_alert_material" /> </resources> diff --git a/docs/html/index.jd b/docs/html/index.jd index 3989b92..cd129d4 100644 --- a/docs/html/index.jd +++ b/docs/html/index.jd @@ -26,9 +26,9 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3 <p class="dac-hero-description">Get your apps ready for the next version of Android. Test on Nexus 5, 6, 9, and Player. </p> - <a class="dac-hero-cta" href="{@docRoot}preview/index.html"> + <a class="dac-hero-cta" href="{@docRoot}preview/overview.html"> <span class="dac-sprite dac-auto-chevron"></span> - Learn more + Get started </a> </div> </div> diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js index 82836e2..86089e6 100644 --- a/docs/html/jd_collections.js +++ b/docs/html/jd_collections.js @@ -1594,7 +1594,8 @@ var RESOURCE_COLLECTIONS = { "training/enterprise/app-restrictions.html", "https://www.youtube.com/watch?v=39NkpWkaH8M&index=2&list=PLOU2XLYxmsIKAK2Bhv19H2THwF-22O5WX", "samples/AppRestrictionSchema/index.html", - "samples/AppRestrictionEnforcer/index.html" + "samples/AppRestrictionEnforcer/index.html", + "https://www.youtube.com/watch?v=dH41OutAMNM" ] }, "training/work/admin": { diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd index eb18aa6..68186bd 100644 --- a/docs/html/preview/index.jd +++ b/docs/html/preview/index.jd @@ -26,7 +26,7 @@ footer.hide=1 <a class="dac-hero-cta" href="{@docRoot}preview/overview.html"> <span class="dac-sprite dac-auto-chevron"></span> - Get Started! + Get started </a><br> </div> </div> @@ -44,7 +44,7 @@ footer.hide=1 <div class="dac-section-subtitle"> Essential information to help you get your apps ready for Android M. </div> - + <div class="resource-widget resource-flow-layout col-16" data-query="collection:preview/landing/more" data-cardSizes="6x6" @@ -56,7 +56,7 @@ footer.hide=1 <span class="dac-sprite dac-auto-chevron"></span> Report Issues </a> - </li> + </li> <li class="dac-section-link"><a href="http://g.co/dev/AndroidMDevPreview"> <span class="dac-sprite dac-auto-chevron"></span> Join G+ Community diff --git a/docs/html/training/tv/discovery/searchable.jd b/docs/html/training/tv/discovery/searchable.jd index 27a1c33..4ca7abb 100644 --- a/docs/html/training/tv/discovery/searchable.jd +++ b/docs/html/training/tv/discovery/searchable.jd @@ -90,7 +90,7 @@ more important columns are described below.</p> <td>The production year of your content <strong>(required)</strong></td> </tr><tr> <td>{@code SUGGEST_COLUMN_DURATION}</td> - <td>The duration in milliseconds of your media</td> + <td>The duration in milliseconds of your media <strong>(required)</strong></td> </tr> </table> @@ -99,6 +99,7 @@ more important columns are described below.</p> <li>{@link android.app.SearchManager#SUGGEST_COLUMN_TEXT_1}</li> <li>{@link android.app.SearchManager#SUGGEST_COLUMN_CONTENT_TYPE}</li> <li>{@link android.app.SearchManager#SUGGEST_COLUMN_PRODUCTION_YEAR}</li> + <li>{@link android.app.SearchManager#SUGGEST_COLUMN_DURATION}</li> </ul> <p>When the values of these columns for your content match the values for the same content from other diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 82a592a..a0c407f 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -815,6 +815,9 @@ public class BitmapDrawable extends Drawable { if (tileModeY != TILE_MODE_UNDEFINED) { setTileModeY(parseTileMode(tileModeY)); } + + final int densityDpi = r.getDisplayMetrics().densityDpi; + state.mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } @Override @@ -977,7 +980,8 @@ public class BitmapDrawable extends Drawable { */ private void updateLocalState(Resources res) { if (res != null) { - mTargetDensity = res.getDisplayMetrics().densityDpi; + final int densityDpi = res.getDisplayMetrics().densityDpi; + mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } else { mTargetDensity = mBitmapState.mTargetDensity; } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 532c888..415af0d 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -1147,6 +1147,7 @@ public abstract class Drawable { * document, tries to create a Drawable from that tag. Returns {@code null} * if the tag is not a valid drawable. */ + @SuppressWarnings("deprecation") public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { final Drawable drawable; @@ -1202,16 +1203,10 @@ public abstract class Drawable { drawable = new InsetDrawable(); break; case "bitmap": - drawable = new BitmapDrawable(r); - if (r != null) { - ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); - } + drawable = new BitmapDrawable(); break; case "nine-patch": drawable = new NinePatchDrawable(); - if (r != null) { - ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); - } break; default: throw new XmlPullParserException(parser.getPositionDescription() + diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 91bbff7..0b7869b 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -482,6 +482,9 @@ public class NinePatchDrawable extends Drawable { if (tint != null) { state.mTint = tint; } + + final int densityDpi = r.getDisplayMetrics().densityDpi; + state.mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } @Override @@ -713,7 +716,8 @@ public class NinePatchDrawable extends Drawable { final NinePatchState state = mNinePatchState; if (res != null) { - mTargetDensity = res.getDisplayMetrics().densityDpi; + final int densityDpi = res.getDisplayMetrics().densityDpi; + mTargetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; } else { mTargetDensity = state.mTargetDensity; } diff --git a/include/androidfw/Asset.h b/include/androidfw/Asset.h index 1fe0e06..ee77e97 100644 --- a/include/androidfw/Asset.h +++ b/include/androidfw/Asset.h @@ -182,11 +182,11 @@ private: /* * Create the asset from a memory-mapped file segment with compressed - * data. "method" is a Zip archive compression method constant. + * data. * * The asset takes ownership of the FileMap. */ - static Asset* createFromCompressedMap(FileMap* dataMap, int method, + static Asset* createFromCompressedMap(FileMap* dataMap, size_t uncompressedLen, AccessMode mode); @@ -286,8 +286,7 @@ public: * * On success, the object takes ownership of "fd". */ - status_t openChunk(FileMap* dataMap, int compressionMethod, - size_t uncompressedLen); + status_t openChunk(FileMap* dataMap, size_t uncompressedLen); /* * Standard Asset interfaces. diff --git a/include/androidfw/ZipFileRO.h b/include/androidfw/ZipFileRO.h index ad5be12..1410d87 100644 --- a/include/androidfw/ZipFileRO.h +++ b/include/androidfw/ZipFileRO.h @@ -35,6 +35,7 @@ #include <utils/FileMap.h> #include <utils/threads.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -68,9 +69,9 @@ typedef void* ZipEntryRO; class ZipFileRO { public: /* Zip compression methods we support */ - enum { - kCompressStored = 0, // no compression - kCompressDeflated = 8, // standard deflate + enum : uint16_t { + kCompressStored = 0, + kCompressDeflated = 8 }; /* @@ -108,10 +109,10 @@ public: /* * Copy the filename into the supplied buffer. Returns 0 on success, - * -1 if "entry" is invalid, or the filename length if it didn't fit. The + * -1 if "entry" is invalid, or the filename length if it didn't fit. The * length, and the returned string, include the null-termination. */ - int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const; + int getEntryFileName(ZipEntryRO entry, char* buffer, size_t bufLen) const; /* * Get the vital stats for an entry. Pass in NULL pointers for anything @@ -122,8 +123,9 @@ public: * Returns "false" if "entry" is bogus or if the data in the Zip file * appears to be bad. */ - bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const; + bool getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, uint32_t* pUncompLen, + uint32_t* pCompLen, off64_t* pOffset, uint32_t* pModWhen, + uint32_t* pCrc32) const; /* * Create a new FileMap object that maps a subset of the archive. For diff --git a/include/androidfw/ZipUtils.h b/include/androidfw/ZipUtils.h index 6bea25a..094eaa8 100644 --- a/include/androidfw/ZipUtils.h +++ b/include/androidfw/ZipUtils.h @@ -20,6 +20,7 @@ #ifndef __LIBS_ZIPUTILS_H #define __LIBS_ZIPUTILS_H +#include <stdint.h> #include <stdio.h> #include <time.h> @@ -63,8 +64,8 @@ public: /* * Utility function to convert ZIP's time format to a timespec struct. */ - static inline void zipTimeToTimespec(long when, struct tm* timespec) { - const long date = when >> 16; + static inline void zipTimeToTimespec(uint32_t when, struct tm* timespec) { + const uint32_t date = when >> 16; timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980 timespec->tm_mon = (date >> 5) & 0x0F; timespec->tm_mday = date & 0x1F; diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 4c0631f..8d4bfcd 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -70,6 +70,8 @@ import javax.security.auth.x500.X500Principal; * <p>NOTE: The key material of the generated symmetric and private keys is not accessible. The key * material of the public keys is accessible. * + * <p>Instances of this class are immutable. + * * <p><h3>Example: Asymmetric key pair</h3> * The following example illustrates how to generate an EC key pair in the Android KeyStore system * under alias {@code key1} authorized to be used only for signing using SHA-256, SHA-384, @@ -79,11 +81,12 @@ import javax.security.auth.x500.X500Principal; * KeyProperties.KEY_ALGORITHM_EC, * "AndroidKeyStore"); * keyPairGenerator.initialize( - * new KeyGenParameterSpec.Builder("key1", + * new KeyGenParameterSpec.Builder( + * "key1", * KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) - * .setDigests(KeyProperties.DIGEST_SHA256 - * | KeyProperties.DIGEST_SHA384 - * | KeyProperties.DIGEST_SHA512) + * .setDigests(KeyProperties.DIGEST_SHA256, + * KeyProperties.DIGEST_SHA384, + * KeyProperties.DIGEST_SHA512) * // Only permit this key to be used if the user authenticated * // within the last five minutes. * .setUserAuthenticationRequired(true) @@ -100,16 +103,17 @@ import javax.security.auth.x500.X500Principal; * * <p><h3>Example: Symmetric key</h3> * The following example illustrates how to generate an AES key in the Android KeyStore system under - * alias {@code key2} authorized to be used only for encryption/decryption in CTR mode. + * alias {@code key2} authorized to be used only for encryption/decryption in CBC mode with PKCS#7 + * padding. * <pre> {@code * KeyGenerator keyGenerator = KeyGenerator.getInstance( - * KeyProperties.KEY_ALGORITHM_HMAC_SHA256, + * KeyProperties.KEY_ALGORITHM_AES, * "AndroidKeyStore"); * keyGenerator.initialize( * new KeyGenParameterSpec.Builder("key2", * KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - * .setBlockModes(KeyProperties.BLOCK_MODE_CTR) - * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + * .setBlockModes(KeyProperties.BLOCK_MODE_CBC) + * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) * .build()); * SecretKey key = keyGenerator.generateKey(); * @@ -169,10 +173,6 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { int userAuthenticationValidityDurationSeconds) { if (TextUtils.isEmpty(keyStoreAlias)) { throw new IllegalArgumentException("keyStoreAlias must not be empty"); - } else if ((userAuthenticationValidityDurationSeconds < 0) - && (userAuthenticationValidityDurationSeconds != -1)) { - throw new IllegalArgumentException( - "userAuthenticationValidityDurationSeconds must not be negative"); } if (certificateSubject == null) { @@ -197,11 +197,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { mSpec = spec; mCertificateSubject = certificateSubject; mCertificateSerialNumber = certificateSerialNumber; - mCertificateNotBefore = certificateNotBefore; - mCertificateNotAfter = certificateNotAfter; - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; + mCertificateNotBefore = Utils.cloneIfNotNull(certificateNotBefore); + mCertificateNotAfter = Utils.cloneIfNotNull(certificateNotAfter); + mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); mPurposes = purposes; mDigests = ArrayUtils.cloneIfNotEmpty(digests); mEncryptionPaddings = @@ -217,6 +217,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * Returns the alias that will be used in the {@code java.security.KeyStore} * in conjunction with the {@code AndroidKeyStore}. */ + @NonNull public String getKeystoreAlias() { return mKeystoreAlias; } @@ -231,10 +232,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Returns the {@link AlgorithmParameterSpec} that will be used for creation - * of the key pair. + * Returns the key algorithm-specific {@link AlgorithmParameterSpec} that will be used for + * creation of the key or {@code null} if algorithm-specific defaults should be used. */ - @NonNull + @Nullable public AlgorithmParameterSpec getAlgorithmParameterSpec() { return mSpec; } @@ -263,7 +264,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Date getCertificateNotBefore() { - return mCertificateNotBefore; + return Utils.cloneIfNotNull(mCertificateNotBefore); } /** @@ -272,7 +273,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Date getCertificateNotAfter() { - return mCertificateNotAfter; + return Utils.cloneIfNotNull(mCertificateNotAfter); } /** @@ -281,7 +282,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @Nullable public Date getKeyValidityStart() { - return mKeyValidityStart; + return Utils.cloneIfNotNull(mKeyValidityStart); } /** @@ -290,7 +291,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @Nullable public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; + return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd); } /** @@ -299,7 +300,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @Nullable public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; + return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd); } /** @@ -411,7 +412,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the - * key. + * key. * * @see #isUserAuthenticationRequired() */ @@ -447,7 +448,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * Creates a new instance of the {@code Builder}. * * @param keystoreAlias alias of the entry in which the generated key will appear in - * Android KeyStore. + * Android KeyStore. Must not be empty. * @param purposes set of purposes (e.g., encrypt, decrypt, sign) for which the key can be * used. Attempts to use the key for any other purpose will be rejected. * @@ -462,6 +463,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { public Builder(@NonNull String keystoreAlias, @KeyProperties.PurposeEnum int purposes) { if (keystoreAlias == null) { throw new NullPointerException("keystoreAlias == null"); + } else if (keystoreAlias.isEmpty()) { + throw new IllegalArgumentException("keystoreAlias must not be empty"); } mKeystoreAlias = keystoreAlias; mPurposes = purposes; @@ -488,7 +491,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { /** * Sets the algorithm-specific key generation parameters. For example, for RSA keys this may - * be an instance of {@link java.security.spec.RSAKeyGenParameterSpec}. + * be an instance of {@link java.security.spec.RSAKeyGenParameterSpec} whereas for EC keys + * this may be an instance of {@link java.security.spec.ECGenParameterSpec}. + * + * <p>These key generation parameters must match other explicitly set parameters (if any), + * such as key size. */ public Builder setAlgorithmParameterSpec(@NonNull AlgorithmParameterSpec spec) { if (spec == null) { @@ -537,7 +544,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { if (date == null) { throw new NullPointerException("date == null"); } - mCertificateNotBefore = date; + mCertificateNotBefore = Utils.cloneIfNotNull(date); return this; } @@ -552,7 +559,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { if (date == null) { throw new NullPointerException("date == null"); } - mCertificateNotAfter = date; + mCertificateNotAfter = Utils.cloneIfNotNull(date); return this; } @@ -565,7 +572,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Builder setKeyValidityStart(Date startDate) { - mKeyValidityStart = startDate; + mKeyValidityStart = Utils.cloneIfNotNull(startDate); return this; } @@ -594,7 +601,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Builder setKeyValidityForOriginationEnd(Date endDate) { - mKeyValidityForOriginationEnd = endDate; + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -608,7 +615,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Builder setKeyValidityForConsumptionEnd(Date endDate) { - mKeyValidityForConsumptionEnd = endDate; + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -768,14 +775,15 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { @NonNull public Builder setUserAuthenticationValidityDurationSeconds( @IntRange(from = -1) int seconds) { + if (seconds < -1) { + throw new IllegalArgumentException("seconds must be -1 or larger"); + } mUserAuthenticationValidityDurationSeconds = seconds; return this; } /** * Builds an instance of {@code KeyGenParameterSpec}. - * - * @throws IllegalArgumentException if a required field is missing */ @NonNull public KeyGenParameterSpec build() { diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java index e4f921e..03b4100 100644 --- a/keystore/java/android/security/keystore/KeyInfo.java +++ b/keystore/java/android/security/keystore/KeyInfo.java @@ -33,6 +33,8 @@ import javax.crypto.SecretKey; * is authorized for (e.g., only in {@code CBC} mode, or signing only), whether the key should be * encrypted at rest, the key's and validity start and end dates. * + * <p>Instances of this class are immutable. + * * <p><h3>Example: Symmetric Key</h3> * The following example illustrates how to obtain a {@code KeyInfo} describing the provided Android * Keystore {@link SecretKey}. @@ -102,9 +104,9 @@ public class KeyInfo implements KeySpec { mInsideSecureHardware = insideSecureHardware; mOrigin = origin; mKeySize = keySize; - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; + mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); mPurposes = purposes; mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); @@ -155,7 +157,7 @@ public class KeyInfo implements KeySpec { */ @Nullable public Date getKeyValidityStart() { - return mKeyValidityStart; + return Utils.cloneIfNotNull(mKeyValidityStart); } /** @@ -165,7 +167,7 @@ public class KeyInfo implements KeySpec { */ @Nullable public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; + return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd); } /** @@ -175,7 +177,7 @@ public class KeyInfo implements KeySpec { */ @Nullable public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; + return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd); } /** diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 432fc12..1e0611c 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -47,6 +47,8 @@ import javax.crypto.Cipher; * * <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible. * + * <p>Instances of this class are immutable. + * * <p><h3>Example: Symmetric Key</h3> * The following example illustrates how to import an AES key into the Android KeyStore under alias * {@code key1} authorized to be used only for encryption/decryption in CBC mode with PKCS#7 @@ -122,15 +124,9 @@ public final class KeyProtection implements ProtectionParameter { boolean randomizedEncryptionRequired, boolean userAuthenticationRequired, int userAuthenticationValidityDurationSeconds) { - if ((userAuthenticationValidityDurationSeconds < 0) - && (userAuthenticationValidityDurationSeconds != -1)) { - throw new IllegalArgumentException( - "userAuthenticationValidityDurationSeconds must not be negative"); - } - - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; + mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); mPurposes = purposes; mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); @@ -150,7 +146,7 @@ public final class KeyProtection implements ProtectionParameter { */ @Nullable public Date getKeyValidityStart() { - return mKeyValidityStart; + return Utils.cloneIfNotNull(mKeyValidityStart); } /** @@ -160,7 +156,7 @@ public final class KeyProtection implements ProtectionParameter { */ @Nullable public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; + return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd); } /** @@ -170,7 +166,7 @@ public final class KeyProtection implements ProtectionParameter { */ @Nullable public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; + return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd); } /** @@ -320,7 +316,7 @@ public final class KeyProtection implements ProtectionParameter { */ @NonNull public Builder setKeyValidityStart(Date startDate) { - mKeyValidityStart = startDate; + mKeyValidityStart = Utils.cloneIfNotNull(startDate); return this; } @@ -349,7 +345,7 @@ public final class KeyProtection implements ProtectionParameter { */ @NonNull public Builder setKeyValidityForOriginationEnd(Date endDate) { - mKeyValidityForOriginationEnd = endDate; + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -363,7 +359,7 @@ public final class KeyProtection implements ProtectionParameter { */ @NonNull public Builder setKeyValidityForConsumptionEnd(Date endDate) { - mKeyValidityForConsumptionEnd = endDate; + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -517,6 +513,9 @@ public final class KeyProtection implements ProtectionParameter { @NonNull public Builder setUserAuthenticationValidityDurationSeconds( @IntRange(from = -1) int seconds) { + if (seconds < -1) { + throw new IllegalArgumentException("seconds must be -1 or larger"); + } mUserAuthenticationValidityDurationSeconds = seconds; return this; } diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java new file mode 100644 index 0000000..9bec682 --- /dev/null +++ b/keystore/java/android/security/keystore/Utils.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 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.security.keystore; + +import java.util.Date; + +/** + * Assorted utility methods. + * + * @hide + */ +abstract class Utils { + private Utils() {} + + static Date cloneIfNotNull(Date value) { + return (value != null) ? (Date) value.clone() : null; + } +} diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp index 782806e..4e14b13 100644 --- a/libs/androidfw/Asset.cpp +++ b/libs/androidfw/Asset.cpp @@ -296,13 +296,13 @@ Asset::~Asset(void) * Create a new Asset from compressed data in a memory mapping. */ /*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap, - int method, size_t uncompressedLen, AccessMode mode) + size_t uncompressedLen, AccessMode mode) { _CompressedAsset* pAsset; status_t result; pAsset = new _CompressedAsset; - result = pAsset->openChunk(dataMap, method, uncompressedLen); + result = pAsset->openChunk(dataMap, uncompressedLen); if (result != NO_ERROR) return NULL; @@ -734,18 +734,12 @@ status_t _CompressedAsset::openChunk(int fd, off64_t offset, * * Nothing is expanded until the first read call. */ -status_t _CompressedAsset::openChunk(FileMap* dataMap, int compressionMethod, - size_t uncompressedLen) +status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen) { assert(mFd < 0); // no re-open assert(mMap == NULL); assert(dataMap != NULL); - if (compressionMethod != ZipFileRO::kCompressDeflated) { - assert(false); - return UNKNOWN_ERROR; - } - mMap = dataMap; mStart = -1; // not used mCompressedLen = dataMap->getDataLength(); diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 25cd363..2dc1c96 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -1156,13 +1156,11 @@ Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile, Asset* pAsset = NULL; // TODO: look for previously-created shared memory slice? - int method; - size_t uncompressedLen; + uint16_t method; + uint32_t uncompressedLen; //printf("USING Zip '%s'\n", pEntry->getFileName()); - //pZipFile->getEntryInfo(entry, &method, &uncompressedLen, &compressedLen, - // &offset); if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, NULL, NULL, NULL, NULL)) { @@ -1181,8 +1179,8 @@ Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile, ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(), dataMap->getFileName(), mode, pAsset); } else { - pAsset = Asset::createFromCompressedMap(dataMap, method, - uncompressedLen, mode); + pAsset = Asset::createFromCompressedMap(dataMap, + static_cast<size_t>(uncompressedLen), mode); ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(), dataMap->getFileName(), mode, pAsset); } diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp index 93b1d56..6f927b4 100644 --- a/libs/androidfw/ZipFileRO.cpp +++ b/libs/androidfw/ZipFileRO.cpp @@ -97,8 +97,9 @@ ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const * Returns "false" if the offsets to the fields or the contents of the fields * appear to be bogus. */ -bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const +bool ZipFileRO::getEntryInfo(ZipEntryRO entry, uint16_t* pMethod, + uint32_t* pUncompLen, uint32_t* pCompLen, off64_t* pOffset, + uint32_t* pModWhen, uint32_t* pCrc32) const { const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); const ZipEntry& ze = zipEntry->entry; @@ -166,7 +167,7 @@ void ZipFileRO::releaseEntry(ZipEntryRO entry) const /* * Copy the entry's filename to the buffer. */ -int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) +int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, size_t bufLen) const { const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index b4cbc36..fc18491 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -241,8 +241,12 @@ void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) { animatorDirtyMask = mAnimatorManager.animate(info); } - bool willHaveFunctor = info.mode == TreeInfo::MODE_FULL && mStagingDisplayListData - ? !mStagingDisplayListData->functors.isEmpty() : !mDisplayListData->functors.isEmpty(); + bool willHaveFunctor = false; + if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayListData) { + willHaveFunctor = !mStagingDisplayListData->functors.isEmpty(); + } else if (mDisplayListData) { + willHaveFunctor = !mDisplayListData->functors.isEmpty(); + } bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence( willHaveFunctor, functorsNeedLayer); diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 431d37e..173d349 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -173,8 +173,7 @@ public final class AudioDeviceInfo { * @see AudioFormat */ public @NonNull int[] getChannelIndexMasks() { - // TODO: implement - return new int[0]; + return mPort.channelIndexMasks(); } /** diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index c078260..aea39a3 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -37,12 +37,12 @@ public class AudioDevicePort extends AudioPort { private final String mAddress; AudioDevicePort(AudioHandle handle, String deviceName, - int[] samplingRates, int[] channelMasks, + int[] samplingRates, int[] channelMasks, int[] channelIndexMasks, int[] formats, AudioGain[] gains, int type, String address) { super(handle, (AudioManager.isInputDevice(type) == true) ? AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK, - deviceName, samplingRates, channelMasks, formats, gains); + deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains); mType = type; mAddress = address; } diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java index ab55c8d..ba144bf 100644 --- a/media/java/android/media/AudioMixPort.java +++ b/media/java/android/media/AudioMixPort.java @@ -31,9 +31,10 @@ public class AudioMixPort extends AudioPort { private final int mIoHandle; AudioMixPort(AudioHandle handle, int ioHandle, int role, String deviceName, - int[] samplingRates, int[] channelMasks, + int[] samplingRates, int[] channelMasks, int[] channelIndexMasks, int[] formats, AudioGain[] gains) { - super(handle, role, deviceName, samplingRates, channelMasks, formats, gains); + super(handle, role, deviceName, samplingRates, channelMasks, channelIndexMasks, + formats, gains); mIoHandle = ioHandle; } diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java index 7328d7a..19bf51d 100644 --- a/media/java/android/media/AudioPort.java +++ b/media/java/android/media/AudioPort.java @@ -71,12 +71,13 @@ public class AudioPort { private final String mName; private final int[] mSamplingRates; private final int[] mChannelMasks; + private final int[] mChannelIndexMasks; private final int[] mFormats; private final AudioGain[] mGains; private AudioPortConfig mActiveConfig; AudioPort(AudioHandle handle, int role, String name, - int[] samplingRates, int[] channelMasks, + int[] samplingRates, int[] channelMasks, int[] channelIndexMasks, int[] formats, AudioGain[] gains) { mHandle = handle; @@ -84,6 +85,7 @@ public class AudioPort { mName = name; mSamplingRates = samplingRates; mChannelMasks = channelMasks; + mChannelIndexMasks = channelIndexMasks; mFormats = formats; mGains = gains; } @@ -133,6 +135,15 @@ public class AudioPort { } /** + * Get the list of supported channel index mask configurations + * (e.g 0x0003 means 2 channel, 0x000F means 4 channel....) + * Empty array if channel index mask is not relevant for this audio port + */ + public int[] channelIndexMasks() { + return mChannelIndexMasks; + } + + /** * Get the list of supported audio format configurations * (e.g AudioFormat.ENCODING_PCM_16BIT) * Empty array if format is not relevant for this audio port diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index bba33be..fc46716 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -25,7 +25,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.concurrent.Executor; @@ -97,6 +96,22 @@ abstract class BaseActivity extends Activity { } @Override + public void onResume() { + super.onResume(); + + final State state = getDisplayState(); + final RootInfo root = getCurrentRoot(); + + // If we're browsing a specific root, and that root went away, then we + // have no reason to hang around + if (state.action == State.ACTION_BROWSE && root != null) { + if (mRoots.getRootBlocking(root.authority, root.rootId) == null) { + finish(); + } + } + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { boolean showMenu = super.onCreateOptionsMenu(menu); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 7bf2223..5a14967 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -2682,9 +2682,6 @@ class DatabaseHelper extends SQLiteOpenHelper { // Set default cdma call auto retry loadSetting(stmt, Settings.Global.CALL_AUTO_RETRY, 0); - // Set default simplified carrier network settings to 0 - loadSetting(stmt, Settings.Global.HIDE_CARRIER_NETWORK_SETTINGS, 0); - // Set the preferred network mode to target desired value or Default // value defined in RILConstants int type; diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java index e1bfc43..13747ed 100644 --- a/packages/Shell/src/com/android/shell/BugreportReceiver.java +++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java @@ -33,11 +33,23 @@ import android.os.FileUtils; import android.os.SystemProperties; import android.support.v4.content.FileProvider; import android.text.format.DateUtils; +import android.util.Log; import android.util.Patterns; import com.google.android.collect.Lists; +import libcore.io.Streams; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import java.util.ArrayList; /** @@ -73,30 +85,14 @@ public class BugreportReceiver extends BroadcastReceiver { final Uri bugreportUri = FileProvider.getUriForFile(context, AUTHORITY, bugreportFile); final Uri screenshotUri = FileProvider.getUriForFile(context, AUTHORITY, screenshotFile); - Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri); - Intent notifIntent; - - // Send through warning dialog by default - if (getWarningState(context, STATE_SHOW) == STATE_SHOW) { - notifIntent = buildWarningIntent(context, sendIntent); + boolean isPlainText = bugreportFile.getName().toLowerCase().endsWith(".txt"); + if (!isPlainText) { + // Already zipped, send it right away. + sendBugreportNotification(context, bugreportFile, screenshotFile); } else { - notifIntent = sendIntent; + // Asynchronously zip the file first, then send it. + sendZippedBugreportNotification(context, bugreportFile, screenshotFile); } - notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - final Notification.Builder builder = new Notification.Builder(context) - .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) - .setContentTitle(context.getString(R.string.bugreport_finished_title)) - .setTicker(context.getString(R.string.bugreport_finished_title)) - .setContentText(context.getString(R.string.bugreport_finished_text)) - .setContentIntent(PendingIntent.getActivity( - context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT)) - .setAutoCancel(true) - .setLocalOnly(true) - .setColor(context.getColor( - com.android.internal.R.color.system_notification_accent_color)); - - NotificationManager.from(context).notify(TAG, 0, builder.build()); // Clean up older bugreports in background final PendingResult result = goAsync(); @@ -141,6 +137,88 @@ public class BugreportReceiver extends BroadcastReceiver { } /** + * Sends a bugreport notitication. + */ + private static void sendBugreportNotification(Context context, File bugreportFile, + File screenshotFile) { + // Files are kept on private storage, so turn into Uris that we can + // grant temporary permissions for. + final Uri bugreportUri = FileProvider.getUriForFile(context, AUTHORITY, bugreportFile); + final Uri screenshotUri = FileProvider.getUriForFile(context, AUTHORITY, screenshotFile); + + Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri); + Intent notifIntent; + + // Send through warning dialog by default + if (getWarningState(context, STATE_SHOW) == STATE_SHOW) { + notifIntent = buildWarningIntent(context, sendIntent); + } else { + notifIntent = sendIntent; + } + notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + final Notification.Builder builder = new Notification.Builder(context) + .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb) + .setContentTitle(context.getString(R.string.bugreport_finished_title)) + .setTicker(context.getString(R.string.bugreport_finished_title)) + .setContentText(context.getString(R.string.bugreport_finished_text)) + .setContentIntent(PendingIntent.getActivity( + context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT)) + .setAutoCancel(true) + .setLocalOnly(true) + .setColor(context.getColor( + com.android.internal.R.color.system_notification_accent_color)); + + NotificationManager.from(context).notify(TAG, 0, builder.build()); + } + + /** + * Sends a zipped bugreport notification. + */ + private static void sendZippedBugreportNotification(final Context context, + final File bugreportFile, final File screenshotFile) { + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... params) { + File zippedFile = zipBugreport(bugreportFile); + sendBugreportNotification(context, zippedFile, screenshotFile); + return null; + } + }.execute(); + } + + /** + * Zips a bugreport file, returning the path to the new file (or to the + * original in case of failure). + */ + private static File zipBugreport(File bugreportFile) { + String bugreportPath = bugreportFile.getAbsolutePath(); + String zippedPath = bugreportPath.replace(".txt", ".zip"); + Log.v(TAG, "zipping " + bugreportPath + " as " + zippedPath); + File bugreportZippedFile = new File(zippedPath); + try (InputStream is = new FileInputStream(bugreportFile); + ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(new FileOutputStream(bugreportZippedFile)))) { + ZipEntry entry = new ZipEntry("bugreport.txt"); + zos.putNextEntry(entry); + int totalBytes = Streams.copy(is, zos); + Log.v(TAG, "size of original bugreport: " + totalBytes + " bytes"); + zos.closeEntry(); + // Delete old file; + boolean deleted = bugreportFile.delete(); + if (deleted) { + Log.v(TAG, "deleted original bugreport (" + bugreportPath + ")"); + } else { + Log.e(TAG, "could not delete original bugreport (" + bugreportPath + ")"); + } + return bugreportZippedFile; + } catch (IOException e) { + Log.e(TAG, "exception zipping file " + zippedPath, e); + return bugreportFile; // Return original. + } + } + + /** * Find the best matching {@link Account} based on build properties. */ private static Account findSendToAccount(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java index 05ee9c2..d360875 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java +++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java @@ -53,6 +53,7 @@ public class StorageNotification extends SystemUI { private static final int MOVE_ID = 0x534d4f56; // SMOV private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME"; + private static final String ACTION_FINISH_WIZARD = "com.android.systemui.action.FINISH_WIZARD"; // TODO: delay some notifications to avoid bumpy fast operations @@ -107,6 +108,15 @@ public class StorageNotification extends SystemUI { } }; + private final BroadcastReceiver mFinishReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // When finishing the adoption wizard, clean up any notifications + // for moving primary storage + mNotificationManager.cancelAsUser(null, MOVE_ID, UserHandle.ALL); + } + }; + private final MoveCallback mMoveCallback = new MoveCallback() { @Override public void onCreated(int moveId, Bundle extras) { @@ -146,6 +156,8 @@ public class StorageNotification extends SystemUI { mContext.registerReceiver(mSnoozeReceiver, new IntentFilter(ACTION_SNOOZE_VOLUME), android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null); + mContext.registerReceiver(mFinishReceiver, new IntentFilter(ACTION_FINISH_WIZARD), + android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null); // Kick current state into place final List<DiskInfo> disks = mStorageManager.getDisks(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e9b9767..667abb6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -31,7 +31,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; import static com.android.server.am.TaskRecord.INVALID_TASK_ID; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK; -import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; @@ -10338,11 +10337,12 @@ public final class ActivityManagerService extends ActivityManagerNative void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) { mVoiceWakeLock.setWorkSource(new WorkSource(targetUid)); if (mRunningVoice == null || mRunningVoice.asBinder() != session.asBinder()) { - if (mRunningVoice == null) { + boolean wasRunningVoice = mRunningVoice != null; + mRunningVoice = session; + if (!wasRunningVoice) { mVoiceWakeLock.acquire(); updateSleepIfNeededLocked(); } - mRunningVoice = session; } } @@ -11495,7 +11495,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<ris.size(); i++) { ActivityInfo ai = ris.get(i).activityInfo; ComponentName comp = new ComponentName(ai.packageName, ai.name); - if (false && lastDoneReceivers.contains(comp)) { + if (lastDoneReceivers.contains(comp)) { // We already did the pre boot receiver for this app with the current // platform version, so don't do it again... ris.remove(i); @@ -18595,29 +18595,24 @@ public final class ActivityManagerService extends ActivityManagerNative return; } boolean isInteraction; - if (!mSleeping) { - isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; + // To avoid some abuse patterns, we are going to be careful about what we consider + // to be an app interaction. Being the top activity doesn't count while the display + // is sleeping, nor do short foreground services. + if (app.curProcState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { + isInteraction = true; app.fgInteractionTime = 0; - } else { - // If the display is off, we are going to be more restrictive about what we consider - // to be an app interaction. Being the top activity doesn't count, nor do generally - // foreground services. - if (app.curProcState <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE) { - isInteraction = true; - app.fgInteractionTime = 0; - } else if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) { - final long now = SystemClock.elapsedRealtime(); - if (app.fgInteractionTime == 0) { - app.fgInteractionTime = now; - isInteraction = false; - } else { - isInteraction = now > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME; - } + } else if (app.curProcState <= ActivityManager.PROCESS_STATE_TOP_SLEEPING) { + final long now = SystemClock.elapsedRealtime(); + if (app.fgInteractionTime == 0) { + app.fgInteractionTime = now; + isInteraction = false; } else { - isInteraction = app.curProcState - <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; - app.fgInteractionTime = 0; + isInteraction = now > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME; } + } else { + isInteraction = app.curProcState + <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; + app.fgInteractionTime = 0; } if (isInteraction && !app.reportedInteraction) { String[] packages = app.getPackageList(); diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index f222dba..2eb8797 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -801,7 +801,7 @@ public class SyncManager { for (String authority : syncableAuthorities) { int isSyncable = getIsSyncable(account.account, account.userId, authority); - if (isSyncable == 0) { + if (isSyncable == AuthorityInfo.NOT_SYNCABLE) { continue; } final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo; @@ -813,8 +813,9 @@ public class SyncManager { final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs(); final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable(); if (isSyncable < 0 && isAlwaysSyncable) { - mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1); - isSyncable = 1; + mSyncStorageEngine.setIsSyncable( + account.account, account.userId, authority, AuthorityInfo.SYNCABLE); + isSyncable = AuthorityInfo.SYNCABLE; } if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) { continue; diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index d68b615..cca0c16 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -301,6 +301,30 @@ public class SyncStorageEngine extends Handler { } public static class AuthorityInfo { + // Legal values of getIsSyncable + /** + * Default state for a newly installed adapter. An uninitialized adapter will receive an + * initialization sync which are governed by a different set of rules to that of regular + * syncs. + */ + public static final int NOT_INITIALIZED = -1; + /** + * The adapter will not receive any syncs. This is behaviourally equivalent to + * setSyncAutomatically -> false. However setSyncAutomatically is surfaced to the user + * while this is generally meant to be controlled by the developer. + */ + public static final int NOT_SYNCABLE = 0; + /** + * The adapter is initialized and functioning. This is the normal state for an adapter. + */ + public static final int SYNCABLE = 1; + /** + * The adapter is syncable but still requires an initialization sync. For example an adapter + * than has been restored from a previous device will be in this state. Not meant for + * external use. + */ + public static final int SYNCABLE_NOT_INITIALIZED = 2; + final EndPoint target; final int ident; boolean enabled; @@ -349,12 +373,11 @@ public class SyncStorageEngine extends Handler { } private void defaultInitialisation() { - syncable = -1; // default to "unknown" + syncable = NOT_INITIALIZED; // default to "unknown" backoffTime = -1; // if < 0 then we aren't in backoff mode backoffDelay = -1; // if < 0 then we aren't in backoff mode PeriodicSync defaultSync; - // Old version is one sync a day. Empty bundle gets replaced by any addPeriodicSync() - // call. + // Old version is one sync a day. if (target.target_provider) { defaultSync = new PeriodicSync(target.account, target.provider, @@ -663,6 +686,12 @@ public class SyncStorageEngine extends Handler { } return; } + // If the adapter was syncable but missing its initialization sync, set it to + // uninitialized now. This is to give it a chance to run any one-time initialization + // logic. + if (sync && authority.syncable == AuthorityInfo.SYNCABLE_NOT_INITIALIZED) { + authority.syncable = AuthorityInfo.NOT_INITIALIZED; + } authority.enabled = sync; writeAccountInfoLocked(); } @@ -682,7 +711,7 @@ public class SyncStorageEngine extends Handler { new EndPoint(account, providerName, userId), "get authority syncable"); if (authority == null) { - return -1; + return AuthorityInfo.NOT_INITIALIZED; } return authority.syncable; } @@ -696,7 +725,7 @@ public class SyncStorageEngine extends Handler { return authorityInfo.syncable; } } - return -1; + return AuthorityInfo.NOT_INITIALIZED; } } @@ -720,7 +749,8 @@ public class SyncStorageEngine extends Handler { } public void setIsTargetServiceActive(ComponentName cname, int userId, boolean active) { - setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? 1 : 0); + setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? + AuthorityInfo.SYNCABLE : AuthorityInfo.NOT_SYNCABLE); } /** @@ -733,10 +763,8 @@ public class SyncStorageEngine extends Handler { AuthorityInfo aInfo; synchronized (mAuthorities) { aInfo = getOrCreateAuthorityLocked(target, -1, false); - if (syncable > 1) { - syncable = 1; - } else if (syncable < -1) { - syncable = -1; + if (syncable < AuthorityInfo.NOT_INITIALIZED) { + syncable = AuthorityInfo.NOT_INITIALIZED; } if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.d(TAG, "setIsSyncable: " + aInfo.toString() + " -> " + syncable); @@ -750,7 +778,7 @@ public class SyncStorageEngine extends Handler { aInfo.syncable = syncable; writeAccountInfoLocked(); } - if (syncable > 0) { + if (syncable == AuthorityInfo.SYNCABLE) { requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle()); } reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); @@ -2012,7 +2040,7 @@ public class SyncStorageEngine extends Handler { int userId = user == null ? 0 : Integer.parseInt(user); if (accountType == null && packageName == null) { accountType = "com.google"; - syncable = "unknown"; + syncable = String.valueOf(AuthorityInfo.NOT_INITIALIZED); } authority = mAuthorities.get(id); if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { @@ -2052,11 +2080,19 @@ public class SyncStorageEngine extends Handler { } if (authority != null) { authority.enabled = enabled == null || Boolean.parseBoolean(enabled); - if ("unknown".equals(syncable)) { - authority.syncable = -1; - } else { - authority.syncable = - (syncable == null || Boolean.parseBoolean(syncable)) ? 1 : 0; + try { + authority.syncable = (syncable == null) ? + AuthorityInfo.NOT_INITIALIZED : Integer.parseInt(syncable); + } catch (NumberFormatException e) { + // On L we stored this as {"unknown", "true", "false"} so fall back to this + // format. + if ("unknown".equals(syncable)) { + authority.syncable = AuthorityInfo.NOT_INITIALIZED; + } else { + authority.syncable = Boolean.parseBoolean(syncable) ? + AuthorityInfo.SYNCABLE : AuthorityInfo.NOT_SYNCABLE; + } + } } else { Log.w(TAG, "Failure adding authority: account=" @@ -2190,11 +2226,7 @@ public class SyncStorageEngine extends Handler { out.attribute(null, "package", info.service.getPackageName()); out.attribute(null, "class", info.service.getClassName()); } - if (authority.syncable < 0) { - out.attribute(null, "syncable", "unknown"); - } else { - out.attribute(null, "syncable", Boolean.toString(authority.syncable != 0)); - } + out.attribute(null, "syncable", Integer.toString(authority.syncable)); for (PeriodicSync periodicSync : authority.periodicSyncs) { out.startTag(null, "periodicSync"); out.attribute(null, "period", Long.toString(periodicSync.period)); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 77b800e..7999321 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -246,6 +246,8 @@ abstract class HdmiCecLocalDevice { return handleRequestActiveSource(message); case Constants.MESSAGE_GET_MENU_LANGUAGE: return handleGetMenuLanguage(message); + case Constants.MESSAGE_SET_MENU_LANGUAGE: + return handleSetMenuLanguage(message); case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS: return handleGivePhysicalAddress(); case Constants.MESSAGE_GIVE_OSD_NAME: @@ -377,6 +379,14 @@ abstract class HdmiCecLocalDevice { } @ServiceThreadOnly + protected boolean handleSetMenuLanguage(HdmiCecMessage message) { + assertRunOnServiceThread(); + Slog.w(TAG, "Only Playback device can handle <Set Menu Language>:" + message.toString()); + // 'return false' will cause to reply with <Feature Abort>. + return false; + } + + @ServiceThreadOnly protected boolean handleGiveOsdName(HdmiCecMessage message) { assertRunOnServiceThread(); // Note that since this method is called after logical address allocation is done, diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 30a9b43..493471b 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -26,9 +26,14 @@ import android.os.SystemProperties; import android.provider.Settings.Global; import android.util.Slog; +import com.android.internal.app.LocalePicker; +import com.android.internal.app.LocalePicker.LocaleInfo; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; +import java.io.UnsupportedEncodingException; +import java.util.List; + /** * Represent a logical device of type Playback residing in Android system. */ @@ -306,6 +311,35 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { return true; // Broadcast message. } + @ServiceThreadOnly + protected boolean handleSetMenuLanguage(HdmiCecMessage message) { + assertRunOnServiceThread(); + + try { + String iso3Language = new String(message.getParams(), 0, 3, "US-ASCII"); + + // Don't use Locale.getAvailableLocales() since it returns a locale + // which is not available on Settings. + final List<LocaleInfo> localeInfos = LocalePicker.getAllAssetLocales( + mService.getContext(), false); + for (LocaleInfo localeInfo : localeInfos) { + if (localeInfo.getLocale().getISO3Language().equals(iso3Language)) { + // WARNING: CEC adopts ISO/FDIS-2 for language code, while Android requires + // additional country variant to pinpoint the locale. This keeps the right + // locale from being chosen. 'eng' in the CEC command, for instance, + // will always be mapped to en-AU among other variants like en-US, en-GB, + // an en-IN, which may not be the expected one. + LocalePicker.updateLocale(localeInfo.getLocale()); + return true; + } + } + Slog.w(TAG, "Can't handle <Set Menu Language> of " + iso3Language); + return false; + } catch (UnsupportedEncodingException e) { + return false; + } + } + @Override @ServiceThreadOnly protected void sendStandby(int deviceId) { diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index 10f1696..4af7d4e 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -51,7 +51,7 @@ import java.util.concurrent.TimeUnit; public class ValidateNotificationPeople implements NotificationSignalExtractor { // Using a shorter log tag since setprop has a limit of 32chars on variable name. private static final String TAG = "ValidateNoPeople"; - private static final boolean INFO = true; + private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean ENABLE_PEOPLE_VALIDATOR = true; @@ -100,7 +100,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { public void onChange(boolean selfChange, Uri uri, int userId) { super.onChange(selfChange, uri, userId); if (DEBUG || mEvictionCount % 100 == 0) { - if (INFO) Slog.i(TAG, "mEvictionCount: " + mEvictionCount); + if (VERBOSE) Slog.i(TAG, "mEvictionCount: " + mEvictionCount); } mPeopleCache.evictAll(); mEvictionCount++; @@ -113,20 +113,20 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { public RankingReconsideration process(NotificationRecord record) { if (!mEnabled) { - if (INFO) Slog.i(TAG, "disabled"); + if (VERBOSE) Slog.i(TAG, "disabled"); return null; } if (record == null || record.getNotification() == null) { - if (INFO) Slog.i(TAG, "skipping empty notification"); + if (VERBOSE) Slog.i(TAG, "skipping empty notification"); return null; } if (record.getUserId() == UserHandle.USER_ALL) { - if (INFO) Slog.i(TAG, "skipping global notification"); + if (VERBOSE) Slog.i(TAG, "skipping global notification"); return null; } Context context = getContextAsUser(record.getUser()); if (context == null) { - if (INFO) Slog.i(TAG, "skipping notification that lacks a context"); + if (VERBOSE) Slog.i(TAG, "skipping notification that lacks a context"); return null; } return validatePeople(context, record); @@ -220,7 +220,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { return null; } - if (INFO) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId()); + if (VERBOSE) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId()); final LinkedList<String> pendingLookups = new LinkedList<String>(); for (int personIdx = 0; personIdx < people.length && personIdx < MAX_PEOPLE; personIdx++) { final String handle = people[personIdx]; @@ -244,7 +244,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { affinityOut[0] = affinity; if (pendingLookups.isEmpty()) { - if (INFO) Slog.i(TAG, "final affinity: " + affinity); + if (VERBOSE) Slog.i(TAG, "final affinity: " + affinity); if (affinity != NONE) MetricsLogger.count(mBaseContext, "note_with_people", 1); return null; } @@ -422,7 +422,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { @Override public void work() { - if (INFO) Slog.i(TAG, "Executing: validation for: " + mKey); + if (VERBOSE) Slog.i(TAG, "Executing: validation for: " + mKey); long timeStartMs = System.currentTimeMillis(); for (final String handle: mPendingLookups) { LookupResult lookupResult = null; @@ -463,7 +463,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { public void applyChangesLocked(NotificationRecord operand) { float affinityBound = operand.getContactAffinity(); operand.setContactAffinity(Math.max(mContactAffinity, affinityBound)); - if (INFO) Slog.i(TAG, "final affinity: " + operand.getContactAffinity()); + if (VERBOSE) Slog.i(TAG, "final affinity: " + operand.getContactAffinity()); } public float getContactAffinity() { diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index 1ee07a5..0de0c92 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; + +import com.android.internal.util.Preconditions; import android.content.pm.PackageParser; import android.util.ArrayMap; import android.util.ArraySet; @@ -98,6 +101,7 @@ public class KeySetManagerService { mRefCount++; return; } + public long decrRefCountLPw() { mRefCount--; return mRefCount; @@ -168,25 +172,82 @@ public class KeySetManagerService { } /** + * addScannedPackageLPw directly modifies the package metadata in pm.Settings + * at a point of no-return. We need to make sure that the scanned package does + * not contain bad keyset meta-data that could generate an incorrect + * PackageSetting. Verify that there is a signing keyset, there are no issues + * with null objects, and the upgrade and defined keysets match. + * + * Returns true if the package can safely be added to the keyset metadata. + */ + public void assertScannedPackageValid(PackageParser.Package pkg) + throws PackageManagerException { + if (pkg == null || pkg.packageName == null) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Passed invalid package to keyset validation."); + } + ArraySet<PublicKey> signingKeys = pkg.mSigningKeys; + if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has invalid signing-key-set."); + } + ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping; + if (definedMapping != null) { + if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has null defined key set."); + } + int defMapSize = definedMapping.size(); + for (int i = 0; i < defMapSize; i++) { + if (!(definedMapping.valueAt(i).size() > 0) + || definedMapping.valueAt(i).contains(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has null/no public keys for defined key-sets."); + } + } + } + ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets; + if (upgradeAliases != null) { + if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has upgrade-key-sets without corresponding definitions."); + } + } + } + + public void addScannedPackageLPw(PackageParser.Package pkg) { + Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms."); + Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms."); + PackageSetting ps = mPackages.get(pkg.packageName); + Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName + + "does not have a corresponding entry in mPackages."); + addSigningKeySetToPackageLPw(ps, pkg.mSigningKeys); + if (pkg.mKeySetMapping != null) { + addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping); + if (pkg.mUpgradeKeySets != null) { + addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets); + } + } + } + + /** * Informs the system that the given package was signed by the provided KeySet. */ - public void addSigningKeySetToPackageLPw(String packageName, + void addSigningKeySetToPackageLPw(PackageSetting pkg, ArraySet<PublicKey> signingKeys) { /* check existing keyset for reuse or removal */ - PackageSetting pkg = mPackages.get(packageName); long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) { ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId); - if (existingKeys.equals(signingKeys)) { + if (existingKeys != null && existingKeys.equals(signingKeys)) { /* no change in signing keys, leave PackageSetting alone */ return; } else { /* old keyset no longer valid, remove ref */ - KeySetHandle ksh = mKeySets.get(signingKeySetId); decrementKeySetLPw(signingKeySetId); } } @@ -212,13 +273,12 @@ public class KeySetManagerService { return KEYSET_NOT_FOUND; } - /* + /** * Inform the system that the given package defines the given KeySets. * Remove any KeySets the package no longer defines. */ - public void addDefinedKeySetsToPackageLPw(String packageName, + void addDefinedKeySetsToPackageLPw(PackageSetting pkg, ArrayMap<String, ArraySet<PublicKey>> definedMapping) { - PackageSetting pkg = mPackages.get(packageName); ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases(); /* add all of the newly defined KeySets */ @@ -227,7 +287,7 @@ public class KeySetManagerService { for (int i = 0; i < defMapSize; i++) { String alias = definedMapping.keyAt(i); ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i); - if (alias != null && pubKeys != null && pubKeys.size() > 0) { + if (alias != null && pubKeys != null || pubKeys.size() > 0) { KeySetHandle ks = addKeySetLPw(pubKeys); newKeySetAliases.put(alias, ks.getId()); } @@ -250,9 +310,8 @@ public class KeySetManagerService { * alias in its manifest to be an upgradeKeySet. This must be called * after all of the defined KeySets have been added. */ - public void addUpgradeKeySetsToPackageLPw(String packageName, - ArraySet<String> upgradeAliases) { - PackageSetting pkg = mPackages.get(packageName); + void addUpgradeKeySetsToPackageLPw(PackageSetting pkg, + ArraySet<String> upgradeAliases) { final int uaSize = upgradeAliases.size(); for (int i = 0; i < uaSize; i++) { pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i)); @@ -290,11 +349,11 @@ public class KeySetManagerService { * identify a {@link KeySetHandle}. */ public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) { - if(mKeySetMapping.get(id) == null) { + ArraySet<Long> pkIds = mKeySetMapping.get(id); + if (pkIds == null) { return null; } ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>(); - ArraySet<Long> pkIds = mKeySetMapping.get(id); final int pkSize = pkIds.size(); for (int i = 0; i < pkSize; i++) { mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey()); @@ -376,6 +435,10 @@ public class KeySetManagerService { */ private void decrementKeySetLPw(long id) { KeySetHandle ks = mKeySets.get(id); + if (ks == null) { + /* nothing to do */ + return; + } if (ks.decrRefCountLPw() <= 0) { ArraySet<Long> pubKeys = mKeySetMapping.get(id); final int pkSize = pubKeys.size(); @@ -385,7 +448,6 @@ public class KeySetManagerService { mKeySets.delete(id); mKeySetMapping.delete(id); } - return; } /* @@ -394,16 +456,20 @@ public class KeySetManagerService { */ private void decrementPublicKeyLPw(long id) { PublicKeyHandle pk = mPublicKeys.get(id); + if (pk == null) { + /* nothing to do */ + return; + } if (pk.decrRefCountLPw() <= 0) { mPublicKeys.delete(id); } - return; } /** * Adds the given PublicKey to the system, deduping as it goes. */ private long addPublicKeyLPw(PublicKey key) { + Preconditions.checkNotNull(key, "Cannot add null public key!"); long id = getIdForPublicKeyLPr(key); if (id != PUBLIC_KEY_NOT_FOUND) { @@ -473,6 +539,8 @@ public class KeySetManagerService { /* remove refs from common keysets and public keys */ PackageSetting pkg = mPackages.get(packageName); + Preconditions.checkNotNull(pkg, "pkg name: " + packageName + + "does not have a corresponding entry in mPackages."); long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); decrementKeySetLPw(signingKeySetId); ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases(); @@ -715,16 +783,36 @@ public class KeySetManagerService { final int numRefCounts = keySetRefCounts.size(); for (int i = 0; i < numRefCounts; i++) { KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i)); + if (ks == null) { + /* something went terribly wrong and we have references to a non-existent key-set */ + Slog.wtf(TAG, "Encountered non-existent key-set reference when reading settings"); + continue; + } ks.setRefCountLPw(keySetRefCounts.valueAt(i)); } + /* + * In case something went terribly wrong and we have keysets with no associated packges + * that refer to them, record the orphaned keyset ids, and remove them using + * decrementKeySetLPw() after all keyset references have been set so that the associtaed + * public keys have the appropriate references from all keysets. + */ + ArraySet<Long> orphanedKeySets = new ArraySet<Long>(); final int numKeySets = mKeySets.size(); for (int i = 0; i < numKeySets; i++) { + if (mKeySets.valueAt(i).getRefCountLPr() == 0) { + Slog.wtf(TAG, "Encountered key-set w/out package references when reading settings"); + orphanedKeySets.add(mKeySets.keyAt(i)); + } ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i); final int pkSize = pubKeys.size(); for (int j = 0; j < pkSize; j++) { mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw(); } } + final int numOrphans = orphanedKeySets.size(); + for (int i = 0; i < numOrphans; i++) { + decrementKeySetLPw(orphanedKeySets.valueAt(i)); + } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 548d93c..5b7dd70 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5109,16 +5109,18 @@ public class PackageManagerService extends IPackageManager.Stub { && !isCompatSignatureUpdateNeeded(pkg) && !isRecoverSignatureUpdateNeeded(pkg)) { long mSigningKeySetId = ps.keySetData.getProperSigningKeySet(); + KeySetManagerService ksms = mSettings.mKeySetManagerService; + ArraySet<PublicKey> signingKs; + synchronized (mPackages) { + signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId); + } if (ps.signatures.mSignatures != null && ps.signatures.mSignatures.length != 0 - && mSigningKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) { + && signingKs != null) { // Optimization: reuse the existing cached certificates // if the package appears to be unchanged. pkg.mSignatures = ps.signatures.mSignatures; - KeySetManagerService ksms = mSettings.mKeySetManagerService; - synchronized (mPackages) { - pkg.mSigningKeys = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId); - } + pkg.mSigningKeys = signingKs; return; } @@ -6590,6 +6592,10 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // Make sure we're not adding any bogus keyset info + KeySetManagerService ksms = mSettings.mKeySetManagerService; + ksms.assertScannedPackageValid(pkg); + // writer synchronized (mPackages) { // We don't expect installation to fail beyond this point @@ -6626,20 +6632,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Add the package's KeySets to the global KeySetManagerService - KeySetManagerService ksms = mSettings.mKeySetManagerService; - try { - ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys); - if (pkg.mKeySetMapping != null) { - ksms.addDefinedKeySetsToPackageLPw(pkg.packageName, pkg.mKeySetMapping); - if (pkg.mUpgradeKeySets != null) { - ksms.addUpgradeKeySetsToPackageLPw(pkg.packageName, pkg.mUpgradeKeySets); - } - } - } catch (NullPointerException e) { - Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e); - } + ksms.addScannedPackageLPw(pkg); int N = pkg.providers.size(); StringBuilder r = null; @@ -11188,7 +11181,7 @@ public class PackageManagerService extends IPackageManager.Stub { KeySetManagerService ksms = mSettings.mKeySetManagerService; for (int i = 0; i < upgradeKeySets.length; i++) { Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]); - if (newPkg.mSigningKeys.containsAll(upgradeSet)) { + if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) { return true; } } diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java index 2557974..7f9a0de 100644 --- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java @@ -118,7 +118,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1)); @@ -145,10 +145,10 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); /* add again, to represent upgrade of package */ - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1)); @@ -175,13 +175,13 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); /* now upgrade with new key */ PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); signingKeys.removeAt(0); signingKeys.add(keyB); - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2)); @@ -212,14 +212,14 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys); - mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys); /* now upgrade with new key */ PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); signingKeys.removeAt(0); signingKeys.add(keyB); - mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2)); @@ -255,13 +255,13 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys1 = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys1.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys1); + mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys1); /* collect second signing key and add */ ArraySet<PublicKey> signingKeys2 = new ArraySet<PublicKey>(); PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); signingKeys2.add(keyB); - mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys2); + mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys2); /* verify first is unchanged */ assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1)); @@ -300,10 +300,10 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys); /* add again for second package */ - mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys); assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1)); @@ -333,12 +333,12 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys); /* give ps2 a superset (add keyB) */ PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); signingKeys.add(keyB); - mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2)); @@ -374,12 +374,12 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); /* now with additional key */ PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); signingKeys.add(keyB); - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 2)); @@ -413,7 +413,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); keys.add(keyA); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1)); @@ -441,7 +441,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { keys.add(keyA); definedKS.put("aliasA", keys); definedKS.put("aliasA2", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); assertEquals(2, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 1)); @@ -470,7 +470,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); keys.add(keyA); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); /* now upgrade to different defined key-set */ keys = new ArraySet<PublicKey>(); @@ -478,7 +478,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { keys.add(keyB); definedKS.remove("aliasA"); definedKS.put("aliasB", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1)); @@ -510,14 +510,14 @@ public class KeySetManagerServiceTest extends AndroidTestCase { PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); keys.add(keyA); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); /* now upgrade to different set w/same alias as before */ keys = new ArraySet<PublicKey>(); PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); keys.add(keyB); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(0, KeySetUtils.getPubKeyRefCount(mKsms, 1)); @@ -551,7 +551,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { keys2.add(keyB); definedKS.put("aliasA", keys1); definedKS.put("aliasB", keys2); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); /* now upgrade to different set (B, C) */ keys1 = new ArraySet<PublicKey>(); @@ -559,7 +559,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { keys1.add(keyC); definedKS.remove("aliasA"); definedKS.put("aliasC", keys1); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); assertEquals(1, KeySetUtils.getKeySetRefCount(mKsms, 3)); assertEquals(1, KeySetUtils.getPubKeyRefCount(mKsms, 3)); @@ -612,7 +612,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); keys1.add(keyA); definedKS.put("aliasA", keys1); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); /* now upgrade to different set */ ArraySet<PublicKey> keys2 = new ArraySet<PublicKey>(); @@ -620,12 +620,12 @@ public class KeySetManagerServiceTest extends AndroidTestCase { keys2.add(keyB); definedKS.remove("aliasA"); definedKS.put("aliasB", keys2); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); /* upgrade back to original */ definedKS.remove("aliasB"); definedKS.put("aliasA", keys1); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1)); assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 2)); @@ -655,10 +655,10 @@ public class KeySetManagerServiceTest extends AndroidTestCase { PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); keys.add(keyA); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); ArraySet<String> upgradeKS = new ArraySet<String>(); upgradeKS.add("aliasA"); - mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS); + mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS); assertEquals(1, ps.keySetData.getUpgradeKeySets().length); assertEquals(1, ps.keySetData.getUpgradeKeySets()[0]); @@ -677,11 +677,11 @@ public class KeySetManagerServiceTest extends AndroidTestCase { PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); keys.add(keyA); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); ArraySet<String> upgradeKS = new ArraySet<String>(); upgradeKS.add("aliasB"); try { - mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS); + mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS); } catch (IllegalArgumentException e) { /* should have been caught in packagemanager, so exception thrown */ @@ -704,17 +704,17 @@ public class KeySetManagerServiceTest extends AndroidTestCase { PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); keys.add(keyA); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); ArraySet<String> upgradeKS = new ArraySet<String>(); upgradeKS.add("aliasA"); - mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS); + mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS); keys = new ArraySet<PublicKey>(); PublicKey keyB = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyB); keys.add(keyB); definedKS.remove("aliasA"); definedKS.put("aliasB", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); assertNull(ps.keySetData.getUpgradeKeySets()); } @@ -729,7 +729,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps, signingKeys); /* remove its references */ mKsms.removeAppKeySetDataLPw(ps.name); @@ -754,8 +754,8 @@ public class KeySetManagerServiceTest extends AndroidTestCase { ArraySet<PublicKey> signingKeys = new ArraySet<PublicKey>(); PublicKey keyA = PackageParser.parsePublicKey(KeySetStrings.ctsKeySetPublicKeyA); signingKeys.add(keyA); - mKsms.addSigningKeySetToPackageLPw(ps1.name, signingKeys); - mKsms.addSigningKeySetToPackageLPw(ps2.name, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps1, signingKeys); + mKsms.addSigningKeySetToPackageLPw(ps2, signingKeys); /* remove references from first package */ mKsms.removeAppKeySetDataLPw(ps1.name); @@ -784,13 +784,13 @@ public class KeySetManagerServiceTest extends AndroidTestCase { /* removal requires signing keyset to be specified (since all apps are * assumed to have it). We skipped this in the defined tests, but can't * here. */ - mKsms.addSigningKeySetToPackageLPw(ps.name, keys); + mKsms.addSigningKeySetToPackageLPw(ps, keys); definedKS.put("aliasA", keys); - mKsms.addDefinedKeySetsToPackageLPw(ps.name, definedKS); + mKsms.addDefinedKeySetsToPackageLPw(ps, definedKS); ArraySet<String> upgradeKS = new ArraySet<String>(); upgradeKS.add("aliasA"); - mKsms.addUpgradeKeySetsToPackageLPw(ps.name, upgradeKS); + mKsms.addUpgradeKeySetsToPackageLPw(ps, upgradeKS); mKsms.removeAppKeySetDataLPw(ps.name); assertEquals(0, KeySetUtils.getKeySetRefCount(mKsms, 1)); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index b0fca95..fafe44a 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -853,7 +853,38 @@ public class VoiceInteractionManagerService extends SystemService { PackageMonitor mPackageMonitor = new PackageMonitor() { @Override public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { - return super.onHandleForceStop(intent, packages, uid, doit); + if (DEBUG) Slog.d(TAG, "onHandleForceStop uid=" + uid + " doit=" + doit); + + int userHandle = UserHandle.getUserId(uid); + ComponentName curInteractor = getCurInteractor(userHandle); + ComponentName curRecognizer = getCurRecognizer(userHandle); + boolean hit = false; + for (String pkg : packages) { + if (curInteractor != null && pkg.equals(curInteractor.getPackageName())) { + hit = true; + break; + } else if (curRecognizer != null + && pkg.equals(curRecognizer.getPackageName())) { + hit = true; + break; + } + } + if (hit && doit) { + // The user is force stopping our current interactor/recognizer. + // Clear the current settings and restore default state. + synchronized (VoiceInteractionManagerService.this) { + mSoundTriggerHelper.stopAllRecognitions(); + if (mImpl != null) { + mImpl.shutdownLocked(); + mImpl = null; + } + setCurInteractor(null, userHandle); + setCurRecognizer(null, userHandle); + initForUser(userHandle); + switchImplementationIfNeededLocked(true); + } + } + return hit; } @Override @@ -865,51 +896,53 @@ public class VoiceInteractionManagerService extends SystemService { int userHandle = getChangingUserId(); if (DEBUG) Slog.d(TAG, "onSomePackagesChanged user=" + userHandle); - ComponentName curInteractor = getCurInteractor(userHandle); - ComponentName curRecognizer = getCurRecognizer(userHandle); - if (curRecognizer == null) { - // Could a new recognizer appear when we don't have one pre-installed? - if (anyPackagesAppearing()) { - curRecognizer = findAvailRecognizer(null, userHandle); - if (curRecognizer != null) { - setCurRecognizer(curRecognizer, userHandle); + synchronized (VoiceInteractionManagerService.this) { + ComponentName curInteractor = getCurInteractor(userHandle); + ComponentName curRecognizer = getCurRecognizer(userHandle); + if (curRecognizer == null) { + // Could a new recognizer appear when we don't have one pre-installed? + if (anyPackagesAppearing()) { + curRecognizer = findAvailRecognizer(null, userHandle); + if (curRecognizer != null) { + setCurRecognizer(curRecognizer, userHandle); + } } - } - return; - } - - if (curInteractor != null) { - int change = isPackageDisappearing(curInteractor.getPackageName()); - if (change == PACKAGE_PERMANENT_CHANGE) { - // The currently set interactor is permanently gone; fall back to - // the default config. - setCurInteractor(null, userHandle); - setCurRecognizer(null, userHandle); - initForUser(userHandle); return; } - change = isPackageAppearing(curInteractor.getPackageName()); - if (change != PACKAGE_UNCHANGED) { - // If current interactor is now appearing, for any reason, then - // restart our connection with it. - if (mImpl != null && curInteractor.getPackageName().equals( - mImpl.mComponent.getPackageName())) { - switchImplementationIfNeededLocked(true); + if (curInteractor != null) { + int change = isPackageDisappearing(curInteractor.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE) { + // The currently set interactor is permanently gone; fall back to + // the default config. + setCurInteractor(null, userHandle); + setCurRecognizer(null, userHandle); + initForUser(userHandle); + return; + } + + change = isPackageAppearing(curInteractor.getPackageName()); + if (change != PACKAGE_UNCHANGED) { + // If current interactor is now appearing, for any reason, then + // restart our connection with it. + if (mImpl != null && curInteractor.getPackageName().equals( + mImpl.mComponent.getPackageName())) { + switchImplementationIfNeededLocked(true); + } } + return; } - return; - } - // There is no interactor, so just deal with a simple recognizer. - int change = isPackageDisappearing(curRecognizer.getPackageName()); - if (change == PACKAGE_PERMANENT_CHANGE - || change == PACKAGE_TEMPORARY_CHANGE) { - setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); + // There is no interactor, so just deal with a simple recognizer. + int change = isPackageDisappearing(curRecognizer.getPackageName()); + if (change == PACKAGE_PERMANENT_CHANGE + || change == PACKAGE_TEMPORARY_CHANGE) { + setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle); - } else if (isPackageModified(curRecognizer.getPackageName())) { - setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), - userHandle), userHandle); + } else if (isPackageModified(curRecognizer.getPackageName())) { + setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(), + userHandle), userHandle); + } } } }; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 1cc275d..8291a30 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -667,7 +667,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getDeviceSvnUsingSubId(subId[0]); + return info.getDeviceSvnUsingSubId(subId[0], mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -744,7 +744,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getImeiForSubscriber(subId[0]); + return info.getImeiForSubscriber(subId[0], mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -773,7 +773,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - String nai = info.getNaiForSubscriber(subId[0]); + String nai = info.getNaiForSubscriber(subId[0], mContext.getOpPackageName()); if (Log.isLoggable(TAG, Log.VERBOSE)) { Rlog.v(TAG, "Nai = " + nai); } @@ -1856,7 +1856,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getIccSerialNumberForSubscriber(subId); + return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1938,7 +1938,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getSubscriberIdForSubscriber(subId); + return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1959,7 +1959,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getGroupIdLevel1(); + return info.getGroupIdLevel1(mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1983,7 +1983,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getGroupIdLevel1ForSubscriber(subId); + return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -2029,7 +2029,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getLine1NumberForSubscriber(subId); + return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -2122,7 +2122,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getLine1AlphaTagForSubscriber(subId); + return info.getLine1AlphaTagForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -2178,7 +2178,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getMsisdnForSubscriber(subId); + return info.getMsisdnForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -2211,7 +2211,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getVoiceMailNumberForSubscriber(subId); + return info.getVoiceMailNumberForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -2350,7 +2350,7 @@ public class TelephonyManager { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; - return info.getVoiceMailAlphaTagForSubscriber(subId); + return info.getVoiceMailAlphaTagForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index c91a59c..ed85392 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -25,12 +25,12 @@ interface IPhoneSubInfo { /** * Retrieves the unique device ID, e.g., IMEI for GSM phones. */ - String getDeviceId(); + String getDeviceId(String callingPackage); /** * Retrieves the unique Network Access ID */ - String getNaiForSubscriber(int subId); + String getNaiForSubscriber(int subId, String callingPackage); /** * Retrieves the unique device ID of a phone for the device, e.g., IMEI @@ -41,91 +41,91 @@ interface IPhoneSubInfo { /** * Retrieves the IMEI. */ - String getImeiForSubscriber(int subId); + String getImeiForSubscriber(int subId, String callingPackage); /** * Retrieves the software version number for the device, e.g., IMEI/SV * for GSM phones. */ - String getDeviceSvn(); + String getDeviceSvn(String callingPackage); /** * Retrieves the software version number of a subId for the device, e.g., IMEI/SV * for GSM phones. */ - String getDeviceSvnUsingSubId(int subId); + String getDeviceSvnUsingSubId(int subId, String callingPackage); /** * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones. */ - String getSubscriberId(); + String getSubscriberId(String callingPackage); /** * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones. */ - String getSubscriberIdForSubscriber(int subId); + String getSubscriberIdForSubscriber(int subId, String callingPackage); /** * Retrieves the Group Identifier Level1 for GSM phones. */ - String getGroupIdLevel1(); + String getGroupIdLevel1(String callingPackage); /** * Retrieves the Group Identifier Level1 for GSM phones of a subId. */ - String getGroupIdLevel1ForSubscriber(int subId); + String getGroupIdLevel1ForSubscriber(int subId, String callingPackage); /** * Retrieves the serial number of the ICC, if applicable. */ - String getIccSerialNumber(); + String getIccSerialNumber(String callingPackage); /** * Retrieves the serial number of a given subId. */ - String getIccSerialNumberForSubscriber(int subId); + String getIccSerialNumberForSubscriber(int subId, String callingPackage); /** * Retrieves the phone number string for line 1. */ - String getLine1Number(); + String getLine1Number(String callingPackage); /** * Retrieves the phone number string for line 1 of a subcription. */ - String getLine1NumberForSubscriber(int subId); + String getLine1NumberForSubscriber(int subId, String callingPackage); /** * Retrieves the alpha identifier for line 1. */ - String getLine1AlphaTag(); + String getLine1AlphaTag(String callingPackage); /** * Retrieves the alpha identifier for line 1 of a subId. */ - String getLine1AlphaTagForSubscriber(int subId); + String getLine1AlphaTagForSubscriber(int subId, String callingPackage); /** * Retrieves MSISDN Number. */ - String getMsisdn(); + String getMsisdn(String callingPackage); /** * Retrieves the Msisdn of a subId. */ - String getMsisdnForSubscriber(int subId); + String getMsisdnForSubscriber(int subId, String callingPackage); /** * Retrieves the voice mail number. */ - String getVoiceMailNumber(); + String getVoiceMailNumber(String callingPackage); /** * Retrieves the voice mail number of a given subId. */ - String getVoiceMailNumberForSubscriber(int subId); + String getVoiceMailNumberForSubscriber(int subId, String callingPackage); /** * Retrieves the complete voice mail number. @@ -140,13 +140,13 @@ interface IPhoneSubInfo { /** * Retrieves the alpha identifier associated with the voice mail number. */ - String getVoiceMailAlphaTag(); + String getVoiceMailAlphaTag(String callingPackage); /** * Retrieves the alpha identifier associated with the voice mail number * of a subId. */ - String getVoiceMailAlphaTagForSubscriber(int subId); + String getVoiceMailAlphaTagForSubscriber(int subId, String callingPackage); /** * Returns the IMS private user identity (IMPI) that was loaded from the ISIM. diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index a1d5dd5..5d55ec6 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -684,6 +684,18 @@ public class WifiConfiguration implements Parcelable { /** * @hide + * For debug: date at which the config was last updated + */ + public String updateTime; + + /** + * @hide + * For debug: date at which the config was last updated + */ + public String creationTime; + + /** + * @hide * The WiFi configuration is considered to have no internet access for purpose of autojoining * if there has been a report of it having no internet access, and, it never have had * internet access in the past. @@ -1000,6 +1012,12 @@ public class WifiConfiguration implements Parcelable { sbuf.append(" numNoInternetAccessReports "); sbuf.append(this.numNoInternetAccessReports).append("\n"); } + if (this.updateTime != null) { + sbuf.append("creation=").append(this.updateTime).append("\n"); + } + if (this.creationTime != null) { + sbuf.append("update=").append(this.creationTime).append("\n"); + } if (this.didSelfAdd) sbuf.append(" didSelfAdd"); if (this.selfAdded) sbuf.append(" selfAdded"); if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess"); @@ -1505,6 +1523,8 @@ public class WifiConfiguration implements Parcelable { userApproved = source.userApproved; numNoInternetAccessReports = source.numNoInternetAccessReports; noInternetAccessExpected = source.noInternetAccessExpected; + creationTime = source.creationTime; + updateTime = source.updateTime; } } |
