Merge "Add an API hint for metered multipath traffic."
diff --git a/api/current.txt b/api/current.txt
index 740543c..1a6ae5c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -67546,6 +67546,7 @@
public abstract class SSLSocketFactory extends javax.net.SocketFactory {
ctor public SSLSocketFactory();
method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
+ method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException;
method public static synchronized javax.net.SocketFactory getDefault();
method public abstract java.lang.String[] getDefaultCipherSuites();
method public abstract java.lang.String[] getSupportedCipherSuites();
diff --git a/api/system-current.txt b/api/system-current.txt
index 239ac70..12a0b0e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -71172,6 +71172,7 @@
public abstract class SSLSocketFactory extends javax.net.SocketFactory {
ctor public SSLSocketFactory();
method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
+ method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException;
method public static synchronized javax.net.SocketFactory getDefault();
method public abstract java.lang.String[] getDefaultCipherSuites();
method public abstract java.lang.String[] getSupportedCipherSuites();
diff --git a/api/test-current.txt b/api/test-current.txt
index 8108a4b..a0362b4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -67655,6 +67655,7 @@
public abstract class SSLSocketFactory extends javax.net.SocketFactory {
ctor public SSLSocketFactory();
method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
+ method public java.net.Socket createSocket(java.net.Socket, java.io.InputStream, boolean) throws java.io.IOException;
method public static synchronized javax.net.SocketFactory getDefault();
method public abstract java.lang.String[] getDefaultCipherSuites();
method public abstract java.lang.String[] getSupportedCipherSuites();
diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
index 7e37157..4e9fac3 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
@@ -241,8 +241,8 @@
*/
public static final class Builder {
- private boolean connectable = true;
- private boolean scannable = true;
+ private boolean connectable = false;
+ private boolean scannable = false;
private boolean isLegacy = false;
private boolean isAnonymous = false;
private boolean includeTxPower = false;
@@ -254,10 +254,10 @@
/**
* Set whether the advertisement type should be connectable or
* non-connectable.
- * Legacy advertisements must be both connectable and scannable. Nonlegacy
+ * Legacy advertisements can be both connectable and scannable. Non-legacy
* advertisements can be only scannable or only connectable.
* @param connectable Controls whether the advertisment type will be
- * connectable (true) or nonconnectable (false).
+ * connectable (true) or non-connectable (false).
*/
public Builder setConnectable(boolean connectable) {
this.connectable = connectable;
@@ -266,10 +266,10 @@
/**
* Set whether the advertisement type should be scannable.
- * Legacy advertisements must be both connectable and scannable. Nonlegacy
+ * Legacy advertisements can be both connectable and scannable. Non-legacy
* advertisements can be only scannable or only connectable.
* @param scannable Controls whether the advertisment type will be
- * scannable (true) or nonscannable (false).
+ * scannable (true) or non-scannable (false).
*/
public Builder setScannable(boolean scannable) {
this.scannable = scannable;
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index 9326203..3617aa7 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -17,7 +17,7 @@
package android.util;
import com.android.internal.util.ArrayUtils;
-
+import com.android.internal.util.Preconditions;
import java.util.Arrays;
import libcore.util.EmptyArray;
@@ -32,6 +32,11 @@
private int[] mValues;
private int mSize;
+ private IntArray(int[] array, int size) {
+ mValues = array;
+ mSize = Preconditions.checkArgumentInRange(size, 0, array.length, "size");
+ }
+
/**
* Creates an empty IntArray with the default initial capacity.
*/
@@ -52,6 +57,35 @@
}
/**
+ * Creates an IntArray wrapping the given primitive int array.
+ */
+ public static IntArray wrap(int[] array) {
+ return new IntArray(array, array.length);
+ }
+
+ /**
+ * Creates an IntArray from the given primitive int array, copying it.
+ */
+ public static IntArray fromArray(int[] array, int size) {
+ return wrap(Arrays.copyOf(array, size));
+ }
+
+ /**
+ * Changes the size of this IntArray. If this IntArray is shrinked, the backing array capacity
+ * is unchanged. If the new size is larger than backing array capacity, a new backing array is
+ * created from the current content of this IntArray padded with 0s.
+ */
+ public void resize(int newSize) {
+ Preconditions.checkArgumentNonnegative(newSize);
+ if (newSize <= mValues.length) {
+ Arrays.fill(mValues, newSize, mValues.length, 0);
+ } else {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
* Appends the specified value to the end of this array.
*/
public void add(int value) {
@@ -59,23 +93,23 @@
}
/**
- * Inserts a value at the specified position in this array.
+ * Inserts a value at the specified position in this array. If the specified index is equal to
+ * the length of the array, the value is added at the end.
*
* @throws IndexOutOfBoundsException when index < 0 || index > size()
*/
public void add(int index, int value) {
- if (index < 0 || index > mSize) {
- throw new IndexOutOfBoundsException();
- }
-
ensureCapacity(1);
+ int rightSegment = mSize - index;
+ mSize++;
+ checkBounds(index);
- if (mSize - index != 0) {
- System.arraycopy(mValues, index, mValues, index + 1, mSize - index);
+ if (rightSegment != 0) {
+ // Move by 1 all values from the right of 'index'
+ System.arraycopy(mValues, index, mValues, index + 1, rightSegment);
}
mValues[index] = value;
- mSize++;
}
/**
@@ -141,13 +175,19 @@
* Returns the value at the specified position in this array.
*/
public int get(int index) {
- if (index >= mSize) {
- throw new ArrayIndexOutOfBoundsException(mSize, index);
- }
+ checkBounds(index);
return mValues[index];
}
/**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(int index, int value) {
+ checkBounds(index);
+ mValues[index] = value;
+ }
+
+ /**
* Returns the index of the first occurrence of the specified value in this
* array, or -1 if this array does not contain the value.
*/
@@ -165,9 +205,7 @@
* Removes the value at the specified index from this array.
*/
public void remove(int index) {
- if (index >= mSize) {
- throw new ArrayIndexOutOfBoundsException(mSize, index);
- }
+ checkBounds(index);
System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1);
mSize--;
}
@@ -185,4 +223,10 @@
public int[] toArray() {
return Arrays.copyOf(mValues, mSize);
}
+
+ private void checkBounds(int index) {
+ if (index < 0 || mSize <= index) {
+ throw new ArrayIndexOutOfBoundsException(mSize, index);
+ }
+ }
}
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 54a6882..9b0489c 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -17,6 +17,8 @@
package android.util;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
+import java.util.Arrays;
import libcore.util.EmptyArray;
/**
@@ -30,6 +32,11 @@
private long[] mValues;
private int mSize;
+ private LongArray(long[] array, int size) {
+ mValues = array;
+ mSize = Preconditions.checkArgumentInRange(size, 0, array.length, "size");
+ }
+
/**
* Creates an empty LongArray with the default initial capacity.
*/
@@ -50,6 +57,35 @@
}
/**
+ * Creates an LongArray wrapping the given primitive long array.
+ */
+ public static LongArray wrap(long[] array) {
+ return new LongArray(array, array.length);
+ }
+
+ /**
+ * Creates an LongArray from the given primitive long array, copying it.
+ */
+ public static LongArray fromArray(long[] array, int size) {
+ return wrap(Arrays.copyOf(array, size));
+ }
+
+ /**
+ * Changes the size of this LongArray. If this LongArray is shrinked, the backing array capacity
+ * is unchanged. If the new size is larger than backing array capacity, a new backing array is
+ * created from the current content of this LongArray padded with 0s.
+ */
+ public void resize(int newSize) {
+ Preconditions.checkArgumentNonnegative(newSize);
+ if (newSize <= mValues.length) {
+ Arrays.fill(mValues, newSize, mValues.length, 0);
+ } else {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
* Appends the specified value to the end of this array.
*/
public void add(long value) {
@@ -57,23 +93,23 @@
}
/**
- * Inserts a value at the specified position in this array.
+ * Inserts a value at the specified position in this array. If the specified index is equal to
+ * the length of the array, the value is added at the end.
*
* @throws IndexOutOfBoundsException when index < 0 || index > size()
*/
public void add(int index, long value) {
- if (index < 0 || index > mSize) {
- throw new IndexOutOfBoundsException();
- }
-
ensureCapacity(1);
+ int rightSegment = mSize - index;
+ mSize++;
+ checkBounds(index);
- if (mSize - index != 0) {
- System.arraycopy(mValues, index, mValues, index + 1, mSize - index);
+ if (rightSegment != 0) {
+ // Move by 1 all values from the right of 'index'
+ System.arraycopy(mValues, index, mValues, index + 1, rightSegment);
}
mValues[index] = value;
- mSize++;
}
/**
@@ -126,13 +162,19 @@
* Returns the value at the specified position in this array.
*/
public long get(int index) {
- if (index >= mSize) {
- throw new ArrayIndexOutOfBoundsException(mSize, index);
- }
+ checkBounds(index);
return mValues[index];
}
/**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(int index, long value) {
+ checkBounds(index);
+ mValues[index] = value;
+ }
+
+ /**
* Returns the index of the first occurrence of the specified value in this
* array, or -1 if this array does not contain the value.
*/
@@ -150,9 +192,7 @@
* Removes the value at the specified index from this array.
*/
public void remove(int index) {
- if (index >= mSize) {
- throw new ArrayIndexOutOfBoundsException(mSize, index);
- }
+ checkBounds(index);
System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1);
mSize--;
}
@@ -163,4 +203,17 @@
public int size() {
return mSize;
}
+
+ /**
+ * Returns a new array with the contents of this LongArray.
+ */
+ public long[] toArray() {
+ return Arrays.copyOf(mValues, mSize);
+ }
+
+ private void checkBounds(int index) {
+ if (index < 0 || mSize <= index) {
+ throw new ArrayIndexOutOfBoundsException(mSize, index);
+ }
+ }
}
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index c3978e7..577cd49 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -276,7 +276,8 @@
jstring ifaceNameObj,
jstring serviceNameObj) {
- using ::android::vintf::operator<<;
+ using ::android::hidl::base::V1_0::IBase;
+ using ::android::hidl::manager::V1_0::IServiceManager;
if (ifaceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
@@ -318,13 +319,20 @@
<< "/"
<< serviceName;
- ::android::vintf::Transport transport =
- ::android::hardware::getTransport(ifaceName, serviceName);
- if ( transport != ::android::vintf::Transport::EMPTY
- && transport != ::android::vintf::Transport::HWBINDER) {
+ Return<IServiceManager::Transport> transportRet =
+ manager->getTransport(ifaceNameHStr, serviceNameHStr);
+
+ if (!transportRet.isOk()) {
+ signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ return NULL;
+ }
+
+ IServiceManager::Transport transport = transportRet;
+
+ if ( transport != IServiceManager::Transport::EMPTY
+ && transport != IServiceManager::Transport::HWBINDER) {
LOG(ERROR) << "service " << ifaceName << " declares transport method "
- << transport << " but framework expects "
- << ::android::vintf::Transport::HWBINDER;
+ << toString(transport) << " but framework expects hwbinder.";
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 460d466..9991a20 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1257,6 +1257,13 @@
<permission android:name="android.permission.REQUEST_NETWORK_SCORES"
android:protectionLevel="signature" />
+ <!-- Allows network stack services (Connectivity and Wifi) to coordinate
+ <p>Not for use by third-party or privileged applications.
+ @hide This should only be used by Connectivity and Wifi Services.
+ -->
+ <permission android:name="android.permission.NETWORK_STACK"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
diff --git a/core/tests/utiltests/src/android/util/IntArrayTest.java b/core/tests/utiltests/src/android/util/IntArrayTest.java
new file mode 100644
index 0000000..a6120a1
--- /dev/null
+++ b/core/tests/utiltests/src/android/util/IntArrayTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IntArrayTest {
+
+ @Test
+ public void testIntArray() {
+ IntArray a = new IntArray();
+ a.add(1);
+ a.add(2);
+ a.add(3);
+ verify(new int[]{1, 2, 3}, a);
+
+ IntArray b = IntArray.fromArray(new int[]{4, 5, 6, 7, 8}, 3);
+ a.addAll(b);
+ verify(new int[]{1, 2, 3, 4, 5, 6}, a);
+
+ a.resize(2);
+ verify(new int[]{1, 2}, a);
+
+ a.resize(8);
+ verify(new int[]{1, 2, 0, 0, 0, 0, 0, 0}, a);
+
+ a.set(5, 10);
+ verify(new int[]{1, 2, 0, 0, 0, 10, 0, 0}, a);
+
+ a.add(5, 20);
+ assertEquals(20, a.get(5));
+ assertEquals(5, a.indexOf(20));
+ verify(new int[]{1, 2, 0, 0, 0, 20, 10, 0, 0}, a);
+
+ assertEquals(-1, a.indexOf(99));
+
+ a.resize(15);
+ a.set(14, 30);
+ verify(new int[]{1, 2, 0, 0, 0, 20, 10, 0, 0, 0, 0, 0, 0, 0, 30}, a);
+
+ int[] backingArray = new int[]{1, 2, 3, 4};
+ a = IntArray.wrap(backingArray);
+ a.set(0, 10);
+ assertEquals(10, backingArray[0]);
+ backingArray[1] = 20;
+ backingArray[2] = 30;
+ verify(backingArray, a);
+ assertEquals(2, a.indexOf(30));
+
+ a.resize(2);
+ assertEquals(0, backingArray[2]);
+ assertEquals(0, backingArray[3]);
+
+ a.add(50);
+ verify(new int[]{10, 20, 50}, a);
+ }
+
+ public void verify(int[] expected, IntArray intArray) {
+ assertEquals(expected.length, intArray.size());
+ assertArrayEquals(expected, intArray.toArray());
+ }
+}
diff --git a/core/tests/utiltests/src/android/util/LongArrayTest.java b/core/tests/utiltests/src/android/util/LongArrayTest.java
new file mode 100644
index 0000000..a7afcbd
--- /dev/null
+++ b/core/tests/utiltests/src/android/util/LongArrayTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LongArrayTest {
+
+ @Test
+ public void testLongArray() {
+ LongArray a = new LongArray();
+ a.add(1);
+ a.add(2);
+ a.add(3);
+ verify(new long[]{1, 2, 3}, a);
+
+ LongArray b = LongArray.fromArray(new long[]{4, 5, 6, 7, 8}, 3);
+ a.addAll(b);
+ verify(new long[]{1, 2, 3, 4, 5, 6}, a);
+
+ a.resize(2);
+ verify(new long[]{1, 2}, a);
+
+ a.resize(8);
+ verify(new long[]{1, 2, 0, 0, 0, 0, 0, 0}, a);
+
+ a.set(5, 10);
+ verify(new long[]{1, 2, 0, 0, 0, 10, 0, 0}, a);
+
+ a.add(5, 20);
+ assertEquals(20, a.get(5));
+ assertEquals(5, a.indexOf(20));
+ verify(new long[]{1, 2, 0, 0, 0, 20, 10, 0, 0}, a);
+
+ assertEquals(-1, a.indexOf(99));
+
+ a.resize(15);
+ a.set(14, 30);
+ verify(new long[]{1, 2, 0, 0, 0, 20, 10, 0, 0, 0, 0, 0, 0, 0, 30}, a);
+
+ long[] backingArray = new long[]{1, 2, 3, 4};
+ a = LongArray.wrap(backingArray);
+ a.set(0, 10);
+ assertEquals(10, backingArray[0]);
+ backingArray[1] = 20;
+ backingArray[2] = 30;
+ verify(backingArray, a);
+ assertEquals(2, a.indexOf(30));
+
+ a.resize(2);
+ assertEquals(0, backingArray[2]);
+ assertEquals(0, backingArray[3]);
+
+ a.add(50);
+ verify(new long[]{10, 20, 50}, a);
+ }
+
+ public void verify(long[] expected, LongArray longArrays) {
+ assertEquals(expected.length, longArrays.size());
+ assertArrayEquals(expected, longArrays.toArray());
+ }
+}
diff --git a/packages/PrintRecommendationService/res/values/strings.xml b/packages/PrintRecommendationService/res/values/strings.xml
index b6c45b7..2bab1b6 100644
--- a/packages/PrintRecommendationService/res/values/strings.xml
+++ b/packages/PrintRecommendationService/res/values/strings.xml
@@ -18,6 +18,7 @@
-->
<resources>
+ <string name="plugin_vendor_google_cloud_print">Cloud Print</string>
<string name="plugin_vendor_hp">HP</string>
<string name="plugin_vendor_lexmark">Lexmark</string>
<string name="plugin_vendor_brother">Brother</string>
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
index 1fe5a2a..8edd0ec 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/RecommendationServiceImpl.java
@@ -21,6 +21,8 @@
import android.printservice.recommendation.RecommendationService;
import android.printservice.PrintService;
import android.util.Log;
+
+import com.android.printservice.recommendation.plugin.google.CloudPrintPlugin;
import com.android.printservice.recommendation.plugin.hp.HPRecommendationPlugin;
import com.android.printservice.recommendation.plugin.mdnsFilter.MDNSFilterPlugin;
import com.android.printservice.recommendation.plugin.mdnsFilter.VendorConfig;
@@ -61,6 +63,14 @@
}
try {
+ mPlugins.add(new RemotePrintServicePlugin(new CloudPrintPlugin(this), this,
+ true));
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Could not initiate "
+ + getString(R.string.plugin_vendor_google_cloud_print) + " plugin", e);
+ }
+
+ try {
mPlugins.add(new RemotePrintServicePlugin(new HPRecommendationPlugin(this), this,
false));
} catch (Exception e) {
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java
new file mode 100644
index 0000000..05b0c86
--- /dev/null
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/google/CloudPrintPlugin.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 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 com.android.printservice.recommendation.plugin.google;
+
+import static com.android.printservice.recommendation.util.MDNSUtils.ATTRIBUTE_TY;
+
+import android.annotation.NonNull;
+import android.annotation.StringRes;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.printservice.recommendation.PrintServicePlugin;
+import com.android.printservice.recommendation.R;
+import com.android.printservice.recommendation.util.MDNSFilteredDiscovery;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Plugin detecting <a href="https://developers.google.com/cloud-print/docs/privet">Google Cloud
+ * Print</a> printers.
+ */
+public class CloudPrintPlugin implements PrintServicePlugin {
+ private static final String LOG_TAG = CloudPrintPlugin.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private static final String ATTRIBUTE_TXTVERS = "txtvers";
+ private static final String ATTRIBUTE_URL = "url";
+ private static final String ATTRIBUTE_TYPE = "type";
+ private static final String ATTRIBUTE_ID = "id";
+ private static final String ATTRIBUTE_CS = "cs";
+
+ private static final String TYPE = "printer";
+
+ private static final String PRIVET_SERVICE = "_privet._tcp";
+
+ /** The required mDNS service types */
+ private static final Set<String> PRINTER_SERVICE_TYPE = new HashSet<String>() {{
+ // Not checking _printer_._sub
+ add(PRIVET_SERVICE);
+ }};
+
+ /** All possible connection states */
+ private static final Set<String> POSSIBLE_CONNECTION_STATES = new HashSet<String>() {{
+ add("online");
+ add("offline");
+ add("connecting");
+ add("not-configured");
+ }};
+
+ private static final byte SUPPORTED_TXTVERS = '1';
+
+ /** The mDNS filtered discovery */
+ private final MDNSFilteredDiscovery mMDNSFilteredDiscovery;
+
+ /**
+ * Create a plugin detecting Google Cloud Print printers.
+ *
+ * @param context The context the plugin runs in
+ */
+ public CloudPrintPlugin(@NonNull Context context) {
+ mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPE,
+ nsdServiceInfo -> {
+ // The attributes are case insensitive. For faster searching create a clone of
+ // the map with the attribute-keys all in lower case.
+ ArrayMap<String, byte[]> caseInsensitiveAttributes =
+ new ArrayMap<>(nsdServiceInfo.getAttributes().size());
+ for (Map.Entry<String, byte[]> entry : nsdServiceInfo.getAttributes()
+ .entrySet()) {
+ caseInsensitiveAttributes.put(entry.getKey().toLowerCase(),
+ entry.getValue());
+ }
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, nsdServiceInfo.getServiceName() + ":");
+ Log.i(LOG_TAG, "type: " + nsdServiceInfo.getServiceType());
+ Log.i(LOG_TAG, "host: " + nsdServiceInfo.getHost());
+ for (Map.Entry<String, byte[]> entry : caseInsensitiveAttributes.entrySet()) {
+ if (entry.getValue() == null) {
+ Log.i(LOG_TAG, entry.getKey() + "= null");
+ } else {
+ Log.i(LOG_TAG, entry.getKey() + "=" + new String(entry.getValue(),
+ StandardCharsets.UTF_8));
+ }
+ }
+ }
+
+ byte[] txtvers = caseInsensitiveAttributes.get(ATTRIBUTE_TXTVERS);
+ if (txtvers == null || txtvers.length != 1 || txtvers[0] != SUPPORTED_TXTVERS) {
+ // The spec requires this to be the first attribute, but at this time we
+ // lost the order of the attributes
+ return false;
+ }
+
+ if (caseInsensitiveAttributes.get(ATTRIBUTE_TY) == null) {
+ return false;
+ }
+
+ byte[] url = caseInsensitiveAttributes.get(ATTRIBUTE_URL);
+ if (url == null || url.length == 0) {
+ return false;
+ }
+
+ byte[] type = caseInsensitiveAttributes.get(ATTRIBUTE_TYPE);
+ if (type == null || !TYPE.equals(
+ new String(type, StandardCharsets.UTF_8).toLowerCase())) {
+ return false;
+ }
+
+ if (caseInsensitiveAttributes.get(ATTRIBUTE_ID) == null) {
+ return false;
+ }
+
+ byte[] cs = caseInsensitiveAttributes.get(ATTRIBUTE_CS);
+ if (cs == null || !POSSIBLE_CONNECTION_STATES.contains(
+ new String(cs, StandardCharsets.UTF_8).toLowerCase())) {
+ return false;
+ }
+
+ InetAddress address = nsdServiceInfo.getHost();
+ if (!(address instanceof Inet4Address)) {
+ // Not checking for link local address
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ @Override
+ @NonNull public CharSequence getPackageName() {
+ return "com.google.android.apps.cloudprint";
+ }
+
+ @Override
+ public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
+ mMDNSFilteredDiscovery.start(callback);
+ }
+
+ @Override
+ @StringRes public int getName() {
+ return R.string.plugin_vendor_google_cloud_print;
+ }
+
+ @Override
+ public void stop() throws Exception {
+ mMDNSFilteredDiscovery.stop();
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 26e8303..d1f4dc4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -139,7 +139,16 @@
if (preferLongName) {
displayName = getZoneLongName(timeZoneNames, tz, now);
} else {
- displayName = timeZoneNames.getExemplarLocationName(tz.getID());
+ // Canonicalize the zone ID for ICU. It will only return valid strings for zone IDs
+ // that match ICUs zone IDs (which are similar but not guaranteed the same as those
+ // in timezones.xml). timezones.xml and related files uses the IANA IDs. ICU IDs are
+ // stable and IANA IDs have changed over time so they have drifted.
+ // See http://bugs.icu-project.org/trac/ticket/13070 / http://b/36469833.
+ String canonicalZoneId = android.icu.util.TimeZone.getCanonicalID(tz.getID());
+ if (canonicalZoneId == null) {
+ canonicalZoneId = tz.getID();
+ }
+ displayName = timeZoneNames.getExemplarLocationName(canonicalZoneId);
if (displayName == null || displayName.isEmpty()) {
// getZoneExemplarLocation can return null. Fall back to the long name.
displayName = getZoneLongName(timeZoneNames, tz, now);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8223cdf..9dde3e2 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1303,13 +1303,16 @@
@Override
public LinkProperties getLinkProperties(Network network) {
enforceAccessPermission();
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
- if (nai != null) {
- synchronized (nai) {
- return new LinkProperties(nai.linkProperties);
- }
+ return getLinkProperties(getNetworkAgentInfoForNetwork(network));
+ }
+
+ private LinkProperties getLinkProperties(NetworkAgentInfo nai) {
+ if (nai == null) {
+ return null;
}
- return null;
+ synchronized (nai) {
+ return new LinkProperties(nai.linkProperties);
+ }
}
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
@@ -3145,7 +3148,8 @@
enforceAccessPermission();
enforceInternetPermission();
- NetworkAgentInfo nai;
+ // TODO: execute this logic on ConnectivityService handler.
+ final NetworkAgentInfo nai;
if (network == null) {
nai = getDefaultNetwork();
} else {
@@ -3156,21 +3160,24 @@
return;
}
// Revalidate if the app report does not match our current validated state.
- if (hasConnectivity == nai.lastValidated) return;
+ if (hasConnectivity == nai.lastValidated) {
+ return;
+ }
final int uid = Binder.getCallingUid();
if (DBG) {
log("reportNetworkConnectivity(" + nai.network.netId + ", " + hasConnectivity +
") by " + uid);
}
- synchronized (nai) {
- // Validating a network that has not yet connected could result in a call to
- // rematchNetworkAndRequests() which is not meant to work on such networks.
- if (!nai.everConnected) return;
-
- if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) return;
-
- nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
+ // Validating a network that has not yet connected could result in a call to
+ // rematchNetworkAndRequests() which is not meant to work on such networks.
+ if (!nai.everConnected) {
+ return;
}
+ LinkProperties lp = getLinkProperties(nai);
+ if (isNetworkWithLinkPropertiesBlocked(lp, uid, false)) {
+ return;
+ }
+ nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
}
private ProxyInfo getDefaultProxy() {
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 97669d2..6cf8f37 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -301,6 +301,11 @@
if (DBG) Log.d(TAG + "/" + mNetworkAgentInfo.name(), s);
}
+ private void validationLog(int probeType, Object url, String msg) {
+ String probeName = ValidationProbeEvent.getProbeName(probeType);
+ validationLog(String.format("%s %s %s", probeName, url, msg));
+ }
+
private void validationLog(String s) {
if (DBG) log(s);
validationLogs.log(s);
@@ -752,20 +757,19 @@
String connectInfo;
try {
InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(host);
- result = ValidationProbeEvent.DNS_SUCCESS;
- StringBuffer buffer = new StringBuffer(host).append("=");
+ StringBuffer buffer = new StringBuffer();
for (InetAddress address : addresses) {
- buffer.append(address.getHostAddress());
- if (address != addresses[addresses.length-1]) buffer.append(",");
+ buffer.append(',').append(address.getHostAddress());
}
- connectInfo = buffer.toString();
+ result = ValidationProbeEvent.DNS_SUCCESS;
+ connectInfo = "OK " + buffer.substring(1);
} catch (UnknownHostException e) {
result = ValidationProbeEvent.DNS_FAILURE;
- connectInfo = host;
+ connectInfo = "FAIL";
}
final long latency = watch.stop();
- String resultString = (ValidationProbeEvent.DNS_SUCCESS == result) ? "OK" : "FAIL";
- validationLog(String.format("%s %s %dms, %s", name, resultString, latency, connectInfo));
+ validationLog(ValidationProbeEvent.PROBE_DNS, host,
+ String.format("%dms %s", latency, connectInfo));
logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result);
}
@@ -787,7 +791,7 @@
urlConnection.setUseCaches(false);
final String userAgent = getCaptivePortalUserAgent(mContext);
if (userAgent != null) {
- urlConnection.setRequestProperty("User-Agent", userAgent);
+ urlConnection.setRequestProperty("User-Agent", userAgent);
}
// cannot read request header after connection
String requestHeader = urlConnection.getRequestProperties().toString();
@@ -801,8 +805,7 @@
// Time how long it takes to get a response to our request
long responseTimestamp = SystemClock.elapsedRealtime();
- validationLog(ValidationProbeEvent.getProbeName(probeType) + " " + url +
- " time=" + (responseTimestamp - requestTimestamp) + "ms" +
+ validationLog(probeType, url, "time=" + (responseTimestamp - requestTimestamp) + "ms" +
" ret=" + httpResponseCode +
" request=" + requestHeader +
" headers=" + urlConnection.getHeaderFields());
@@ -814,27 +817,29 @@
// proxy server.
if (httpResponseCode == 200) {
if (probeType == ValidationProbeEvent.PROBE_PAC) {
- validationLog("PAC fetch 200 response interpreted as 204 response.");
+ validationLog(
+ probeType, url, "PAC fetch 200 response interpreted as 204 response.");
httpResponseCode = 204;
} else if (urlConnection.getContentLengthLong() == 0) {
// Consider 200 response with "Content-length=0" to not be a captive portal.
// There's no point in considering this a captive portal as the user cannot
// sign-in to an empty page. Probably the result of a broken transparent proxy.
// See http://b/9972012.
- validationLog(
+ validationLog(probeType, url,
"200 response with Content-length=0 interpreted as 204 response.");
httpResponseCode = 204;
} else if (urlConnection.getContentLengthLong() == -1) {
// When no Content-length (default value == -1), attempt to read a byte from the
// response. Do not use available() as it is unreliable. See http://b/33498325.
if (urlConnection.getInputStream().read() == -1) {
- validationLog("Empty 200 response interpreted as 204 response.");
+ validationLog(
+ probeType, url, "Empty 200 response interpreted as 204 response.");
httpResponseCode = 204;
}
}
}
} catch (IOException e) {
- validationLog("Probably not a portal: exception " + e);
+ validationLog(probeType, url, "Probably not a portal: exception " + e);
if (httpResponseCode == 599) {
// TODO: Ping gateway and DNS server and log results.
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 8800f8e..7e0fbb9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -721,6 +721,16 @@
public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
/**
+ * String array for package names that need to be enabled for this carrier.
+ * If user has explicitly disabled some packages in the list, won't re-enable.
+ * Other carrier specific apps which are not in this list may be disabled for current carrier,
+ * and only be re-enabled when this config for another carrier includes it.
+ *
+ * @hide
+ */
+ public static final String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
+
+ /**
* Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference.
* Some operators support Wi-Fi Calling only, not VoLTE.
* They don't need "Cellular preferred" option.
@@ -1387,6 +1397,7 @@
sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL, false);
+ sDefaults.putStringArray(KEY_ENABLE_APPS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index 011e505..8c16dbb 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -58,8 +58,6 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" default_network_event <",
" network_id <",
" network_id: 102",
@@ -72,6 +70,8 @@
" transport_types: 2",
" transport_types: 3",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -89,13 +89,14 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" dhcp_event <",
" duration_ms: 192",
+ " error_code: 0",
" if_name: \"wlan0\"",
" state_transition: \"SomeState\"",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -112,13 +113,14 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" dhcp_event <",
" duration_ms: 0",
- " if_name: \"wlan0\"",
" error_code: 50397184",
+ " if_name: \"wlan0\"",
+ " state_transition: \"\"",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -137,8 +139,6 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" dns_lookup_batch <",
" event_types: 1",
" event_types: 1",
@@ -168,6 +168,8 @@
" return_codes: 200",
" return_codes: 178",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -185,13 +187,13 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" ip_provisioning_event <",
" event_type: 1",
" if_name: \"wlan0\"",
" latency_ms: 5678",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -208,12 +210,12 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" ip_reachability_event <",
" event_type: 512",
" if_name: \"wlan0\"",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -231,8 +233,6 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" network_event <",
" event_type: 5",
" latency_ms: 20410",
@@ -240,6 +240,8 @@
" network_id: 100",
" >",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -287,8 +289,6 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" apf_program_event <",
" current_ras: 9",
" drop_multicast: true",
@@ -297,6 +297,8 @@
" lifetime: 200",
" program_length: 2048",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -319,8 +321,6 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" apf_statistics <",
" dropped_ras: 2",
" duration_ms: 45000",
@@ -331,6 +331,8 @@
" received_ras: 10",
" zero_lifetime_ras: 1",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
@@ -351,8 +353,6 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 1",
- " transport: 0",
" ra_event <",
" dnssl_lifetime: -1",
" prefix_preferred_lifetime: 300",
@@ -361,6 +361,8 @@
" route_info_lifetime: -1",
" router_lifetime: 2000",
" >",
+ " time_ms: 1",
+ " transport: 0",
">",
"version: 2");
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 450653c..9a33cde 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -158,25 +158,24 @@
String want = joinLines(
"dropped_events: 0",
"events <",
- " time_ms: 100",
- " transport: 0",
" ip_reachability_event <",
" event_type: 512",
" if_name: \"wlan0\"",
" >",
+ " time_ms: 100",
+ " transport: 0",
">",
"events <",
- " time_ms: 200",
- " transport: 0",
" dhcp_event <",
" duration_ms: 192",
+ " error_code: 0",
" if_name: \"wlan0\"",
" state_transition: \"SomeState\"",
" >",
+ " time_ms: 200",
+ " transport: 0",
">",
"events <",
- " time_ms: 300",
- " transport: 0",
" default_network_event <",
" network_id <",
" network_id: 102",
@@ -189,15 +188,17 @@
" transport_types: 2",
" transport_types: 3",
" >",
+ " time_ms: 300",
+ " transport: 0",
">",
"events <",
- " time_ms: 400",
- " transport: 0",
" ip_provisioning_event <",
" event_type: 1",
" if_name: \"wlan0\"",
" latency_ms: 5678",
" >",
+ " time_ms: 400",
+ " transport: 0",
">",
"events <",
" time_ms: 500",
@@ -212,8 +213,6 @@
" >",
">",
"events <",
- " time_ms: 600",
- " transport: 0",
" apf_statistics <",
" dropped_ras: 2",
" duration_ms: 45000",
@@ -224,10 +223,10 @@
" received_ras: 10",
" zero_lifetime_ras: 1",
" >",
+ " time_ms: 600",
+ " transport: 0",
">",
"events <",
- " time_ms: 700",
- " transport: 0",
" ra_event <",
" dnssl_lifetime: -1",
" prefix_preferred_lifetime: 300",
@@ -236,6 +235,8 @@
" route_info_lifetime: -1",
" router_lifetime: 2000",
" >",
+ " time_ms: 700",
+ " transport: 0",
">",
"version: 2");
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 97afa60..6c8babb 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -212,8 +212,6 @@
IpConnectivityEvent got = events.get(0);
String want = joinLines(
- "time_ms: 0",
- "transport: 0",
"connect_statistics <",
" connect_count: 12",
" errnos_counters <",
@@ -247,7 +245,10 @@
" latencies_ms: 67",
" latencies_ms: 110",
" latencies_ms: 214",
- " latencies_ms: 523");
+ " latencies_ms: 523",
+ ">",
+ "time_ms: 0",
+ "transport: 0");
verifyConnectEvent(want, got);
}
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index f87f6c5..29c933a 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -36,20 +36,18 @@
built_ext_dep := $(call java-lib-deps,ext)
built_ext_classes := $(call java-lib-files,ext)
-built_ext_data := $(call intermediates-dir-for, \
- JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
+
built_icudata_dep := $(call java-lib-deps,icu4j-icudata-host-jarjar,HOST)
built_icutzdata_dep := $(call java-lib-deps,icu4j-icutzdata-host-jarjar,HOST)
-built_layoutlib_create_jar := $(call intermediates-dir-for, \
- JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
+built_layoutlib_create_jar := $(call java-lib-files,layoutlib_create,HOST)
# This is mostly a copy of config/host_java_library.mk
LOCAL_MODULE := temp_layoutlib
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_SUFFIX := $(COMMON_JAVA_PACKAGE_SUFFIX)
LOCAL_IS_HOST_MODULE := true
-LOCAL_BUILT_MODULE_STEM := javalib.jar
+LOCAL_BUILT_MODULE_STEM := classes.jar
#######################################
include $(BUILD_SYSTEM)/base_rules.mk
@@ -59,7 +57,6 @@
$(built_core_dep) \
$(built_framework_dep) \
$(built_ext_dep) \
- $(built_ext_data) \
$(built_icudata_dep) \
$(built_icutzdata_dep) \
$(built_layoutlib_create_jar)