Merge cherrypicks of [6072697, 6072075, 6072758, 6072124, 6072885, 6072886, 6072887, 6072580, 6072581, 6072582, 6072583, 6072584, 6072132, 6072195, 6072133, 6072077, 6072134, 6072078, 6072211, 6072762, 6072763, 6072908, 6072909, 6072910, 6072911, 6072912, 6072913, 6072914, 6072930, 6072212, 6072743] into pi-qpr2-release
Change-Id: I9f800670c887affef352d47aa6f83fe4e282b91a
This commit is contained in:
@@ -29,6 +29,7 @@ import android.text.Spanned;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.method.MovementMethod;
|
||||
import android.text.style.URLSpan;
|
||||
import android.util.Log;
|
||||
import android.util.Patterns;
|
||||
import android.view.textclassifier.TextClassifier;
|
||||
import android.view.textclassifier.TextLinks;
|
||||
@@ -77,6 +78,9 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
|
||||
public class Linkify {
|
||||
|
||||
private static final String LOG_TAG = "Linkify";
|
||||
|
||||
/**
|
||||
* Bit field indicating that web URLs should be matched in methods that
|
||||
* take an options mask
|
||||
@@ -246,6 +250,11 @@ public class Linkify {
|
||||
|
||||
private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
|
||||
@Nullable Context context) {
|
||||
if (text != null && containsUnsupportedCharacters(text.toString())) {
|
||||
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mask == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -291,6 +300,29 @@ public class Linkify {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified text contains at least one unsupported character for applying
|
||||
* links. Also logs the error.
|
||||
*
|
||||
* @param text the text to apply links to
|
||||
* @hide
|
||||
*/
|
||||
public static boolean containsUnsupportedCharacters(String text) {
|
||||
if (text.contains("\u202C")) {
|
||||
Log.e(LOG_TAG, "Unsupported character for applying links: u202C");
|
||||
return true;
|
||||
}
|
||||
if (text.contains("\u202D")) {
|
||||
Log.e(LOG_TAG, "Unsupported character for applying links: u202D");
|
||||
return true;
|
||||
}
|
||||
if (text.contains("\u202E")) {
|
||||
Log.e(LOG_TAG, "Unsupported character for applying links: u202E");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the text of the provided TextView and turns all occurrences of
|
||||
* the link types indicated in the mask into clickable links. If matches
|
||||
@@ -461,6 +493,11 @@ public class Linkify {
|
||||
public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
|
||||
@Nullable String defaultScheme, @Nullable String[] schemes,
|
||||
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
|
||||
if (spannable != null && containsUnsupportedCharacters(spannable.toString())) {
|
||||
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
|
||||
return false;
|
||||
}
|
||||
|
||||
final String[] schemesCopy;
|
||||
if (defaultScheme == null) defaultScheme = "";
|
||||
if (schemes == null || schemes.length < 1) {
|
||||
|
||||
@@ -104,7 +104,7 @@ public final class TextClassification implements Parcelable {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
static final TextClassification EMPTY = new TextClassification.Builder().build();
|
||||
public static final TextClassification EMPTY = new TextClassification.Builder().build();
|
||||
|
||||
private static final String LOG_TAG = "TextClassification";
|
||||
// TODO(toki): investigate a way to derive this based on device properties.
|
||||
|
||||
@@ -107,6 +107,13 @@ public final class TextLinksParams {
|
||||
Preconditions.checkNotNull(textLinks);
|
||||
|
||||
final String textString = text.toString();
|
||||
|
||||
if (Linkify.containsUnsupportedCharacters(textString)) {
|
||||
// Do not apply links to text containing unsupported characters.
|
||||
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
|
||||
return TextLinks.STATUS_NO_LINKS_APPLIED;
|
||||
}
|
||||
|
||||
if (!textString.startsWith(textLinks.getText())) {
|
||||
return TextLinks.STATUS_DIFFERENT_TEXT;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.text.Layout;
|
||||
import android.text.Selection;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
import android.view.textclassifier.SelectionEvent;
|
||||
@@ -1045,7 +1046,12 @@ public final class SelectionActionModeHelper {
|
||||
|
||||
trimText();
|
||||
final TextClassification classification;
|
||||
if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
|
||||
if (Linkify.containsUnsupportedCharacters(mText)) {
|
||||
// Do not show smart actions for text containing unsupported characters.
|
||||
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
|
||||
classification = TextClassification.EMPTY;
|
||||
} else if (mContext.getApplicationInfo().targetSdkVersion
|
||||
>= Build.VERSION_CODES.P) {
|
||||
final TextClassification.Request request =
|
||||
new TextClassification.Request.Builder(
|
||||
mTrimmedText, mRelativeStart, mRelativeEnd)
|
||||
|
||||
@@ -39,6 +39,8 @@ import android.service.textclassifier.TextClassifierService;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
@@ -306,6 +308,16 @@ public class TextClassificationManagerTest {
|
||||
mClassifier.generateLinks(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyLinks_unsupportedCharacter() {
|
||||
if (isTextClassifierDisabled()) return;
|
||||
Spannable url = new SpannableString("\u202Emoc.diordna.com");
|
||||
TextLinks.Request request = new TextLinks.Request.Builder(url).build();
|
||||
assertEquals(
|
||||
TextLinks.STATUS_NO_LINKS_APPLIED,
|
||||
mClassifier.generateLinks(request).apply(url, 0, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetTextClassifier() {
|
||||
TextClassifier classifier = mock(TextClassifier.class);
|
||||
|
||||
@@ -982,6 +982,19 @@ public class TextViewActivityTest {
|
||||
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoAssistItemForTextFieldWithUnsupportedCharacters() throws Throwable {
|
||||
useSystemDefaultTextClassifier();
|
||||
final String text = "\u202Emoc.diordna.com";
|
||||
final TextView textView = mActivity.findViewById(R.id.textview);
|
||||
mActivityRule.runOnUiThread(() -> textView.setText(text));
|
||||
mInstrumentation.waitForIdleSync();
|
||||
|
||||
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('.')));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectionMetricsLogger_noAbandonAfterCopy() throws Throwable {
|
||||
final List<SelectionEvent> selectionEvents = new ArrayList<>();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.internal.location;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@@ -27,19 +28,17 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.location.LocationManager;
|
||||
import android.location.INetInitiatedListener;
|
||||
import android.os.SystemClock;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.notification.SystemNotificationChannels;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.telephony.GsmAlphabet;
|
||||
import com.android.internal.telephony.TelephonyProperties;
|
||||
|
||||
/**
|
||||
* A GPS Network-initiated Handler class used by LocationManager.
|
||||
@@ -50,8 +49,7 @@ public class GpsNetInitiatedHandler {
|
||||
|
||||
private static final String TAG = "GpsNetInitiatedHandler";
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
private static final boolean VERBOSE = false;
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
|
||||
// NI verify activity for bringing up UI (not used yet)
|
||||
public static final String ACTION_NI_VERIFY = "android.intent.action.NETWORK_INITIATED_VERIFY";
|
||||
@@ -94,6 +92,9 @@ public class GpsNetInitiatedHandler {
|
||||
public static final int GPS_ENC_SUPL_UCS2 = 3;
|
||||
public static final int GPS_ENC_UNKNOWN = -1;
|
||||
|
||||
// Limit on SUPL NI emergency mode time extension after emergency sessions ends
|
||||
private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum
|
||||
|
||||
private final Context mContext;
|
||||
private final TelephonyManager mTelephonyManager;
|
||||
private final PhoneStateListener mPhoneStateListener;
|
||||
@@ -109,7 +110,7 @@ public class GpsNetInitiatedHandler {
|
||||
private volatile boolean mIsSuplEsEnabled;
|
||||
|
||||
// Set to true if the phone is having emergency call.
|
||||
private volatile boolean mIsInEmergency;
|
||||
private volatile boolean mIsInEmergencyCall;
|
||||
|
||||
// If Location function is enabled.
|
||||
private volatile boolean mIsLocationEnabled = false;
|
||||
@@ -119,6 +120,10 @@ public class GpsNetInitiatedHandler {
|
||||
// Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
|
||||
static private boolean mIsHexInput = true;
|
||||
|
||||
// End time of emergency call, and extension, if set
|
||||
private long mCallEndElapsedRealtimeMillis = 0;
|
||||
private long mEmergencyExtensionMillis = 0;
|
||||
|
||||
public static class GpsNiNotification
|
||||
{
|
||||
public int notificationId;
|
||||
@@ -146,16 +151,12 @@ public class GpsNetInitiatedHandler {
|
||||
if (action.equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
|
||||
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
|
||||
/*
|
||||
Emergency Mode is when during emergency call or in emergency call back mode.
|
||||
For checking if it is during emergency call:
|
||||
mIsInEmergency records if the phone is in emergency call or not. It will
|
||||
Tracks the emergency call:
|
||||
mIsInEmergencyCall records if the phone is in emergency call or not. It will
|
||||
be set to true when the phone is having emergency call, and then will
|
||||
be set to false by mPhoneStateListener when the emergency call ends.
|
||||
For checking if it is in emergency call back mode:
|
||||
Emergency call back mode will be checked by reading system properties
|
||||
when necessary: SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)
|
||||
*/
|
||||
setInEmergency(PhoneNumberUtils.isEmergencyNumber(phoneNumber));
|
||||
mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber);
|
||||
if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
|
||||
} else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
|
||||
updateLocationMode();
|
||||
@@ -195,7 +196,10 @@ public class GpsNetInitiatedHandler {
|
||||
if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is "+ state);
|
||||
// listening for emergency call ends
|
||||
if (state == TelephonyManager.CALL_STATE_IDLE) {
|
||||
setInEmergency(false);
|
||||
if (mIsInEmergencyCall) {
|
||||
mCallEndElapsedRealtimeMillis = SystemClock.elapsedRealtime();
|
||||
mIsInEmergencyCall = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -229,22 +233,35 @@ public class GpsNetInitiatedHandler {
|
||||
return mIsLocationEnabled;
|
||||
}
|
||||
|
||||
// Note: Currently, there are two mechanisms involved to determine if a
|
||||
// phone is in emergency mode:
|
||||
// 1. If the user is making an emergency call, this is provided by activly
|
||||
// monitoring the outgoing phone number;
|
||||
// 2. If the device is in a emergency callback state, this is provided by
|
||||
// system properties.
|
||||
// If either one of above exists, the phone is considered in an emergency
|
||||
// mode. Because of this complexity, we need to be careful about how to set
|
||||
// and clear the emergency state.
|
||||
public void setInEmergency(boolean isInEmergency) {
|
||||
mIsInEmergency = isInEmergency;
|
||||
/**
|
||||
* Determines whether device is in user-initiated emergency session based on the following
|
||||
* 1. If the user is making an emergency call, this is provided by actively
|
||||
* monitoring the outgoing phone number;
|
||||
* 2. If the user has recently ended an emergency call, and the device is in a configured time
|
||||
* window after the end of that call.
|
||||
* 3. If the device is in a emergency callback state, this is provided by querying
|
||||
* TelephonyManager.
|
||||
* @return true if is considered in user initiated emergency mode for NI purposes
|
||||
*/
|
||||
public boolean getInEmergency() {
|
||||
boolean isInEmergencyExtension =
|
||||
(SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) <
|
||||
mEmergencyExtensionMillis;
|
||||
boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode();
|
||||
return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension;
|
||||
}
|
||||
|
||||
public boolean getInEmergency() {
|
||||
boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode();
|
||||
return mIsInEmergency || isInEmergencyCallback;
|
||||
public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
|
||||
if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
|
||||
Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
|
||||
+ " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
|
||||
emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
|
||||
} else if (emergencyExtensionSeconds < 0) {
|
||||
Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
|
||||
+ " is negative, reset to zero.");
|
||||
emergencyExtensionSeconds = 0;
|
||||
}
|
||||
mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -723,6 +723,17 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
|
||||
}
|
||||
}
|
||||
|
||||
String emergencyExtensionSecondsString
|
||||
= properties.getProperty("ES_EXTENSION_SEC", "0");
|
||||
try {
|
||||
int emergencyExtensionSeconds =
|
||||
Integer.parseInt(emergencyExtensionSecondsString);
|
||||
mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "unable to parse ES_EXTENSION_SEC: "
|
||||
+ emergencyExtensionSecondsString);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadPropertiesFromResource(Context context,
|
||||
|
||||
@@ -4795,18 +4795,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
quality = PASSWORD_QUALITY_UNSPECIFIED;
|
||||
}
|
||||
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
|
||||
if (quality != PASSWORD_QUALITY_UNSPECIFIED) {
|
||||
final int realQuality = metrics.quality;
|
||||
if (realQuality < quality
|
||||
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
|
||||
Slog.w(LOG_TAG, "resetPassword: password quality 0x"
|
||||
+ Integer.toHexString(realQuality)
|
||||
+ " does not meet required quality 0x"
|
||||
+ Integer.toHexString(quality));
|
||||
return false;
|
||||
}
|
||||
quality = Math.max(realQuality, quality);
|
||||
final int realQuality = metrics.quality;
|
||||
if (realQuality < quality
|
||||
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
|
||||
Slog.w(LOG_TAG, "resetPassword: password quality 0x"
|
||||
+ Integer.toHexString(realQuality)
|
||||
+ " does not meet required quality 0x"
|
||||
+ Integer.toHexString(quality));
|
||||
return false;
|
||||
}
|
||||
quality = Math.max(realQuality, quality);
|
||||
int length = getPasswordMinimumLength(null, userHandle, /* parent */ false);
|
||||
if (password.length() < length) {
|
||||
Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
|
||||
@@ -4892,7 +4890,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
result = mLockPatternUtils.setLockCredentialWithToken(password,
|
||||
TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
|
||||
: LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
quality, tokenHandle, token, userHandle);
|
||||
quality, tokenHandle, token, userHandle);
|
||||
}
|
||||
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
|
||||
if (requireEntry) {
|
||||
|
||||
@@ -4181,7 +4181,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
|
||||
// test reset password with token
|
||||
when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password),
|
||||
eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD),
|
||||
eq(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED), eq(handle), eq(token),
|
||||
eq(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), eq(handle), eq(token),
|
||||
eq(UserHandle.USER_SYSTEM)))
|
||||
.thenReturn(true);
|
||||
assertTrue(dpm.resetPasswordWithToken(admin1, password, token, 0));
|
||||
|
||||
Reference in New Issue
Block a user