Skip to content

Commit 13bd23b

Browse files
committed
Merge tag 'android-9.0.0_r35' into HEAD
Android 9.0.0 release 35 Change-Id: I0e4acd53b4cde7a6087d2030a8d022a92b31a874
2 parents 54a6ad6 + 1b1681a commit 13bd23b

File tree

11 files changed

+151
-45
lines changed

11 files changed

+151
-45
lines changed

core/java/android/text/util/Linkify.java

+37
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import android.text.method.LinkMovementMethod;
3030
import android.text.method.MovementMethod;
3131
import android.text.style.URLSpan;
32+
import android.util.Log;
3233
import android.util.Patterns;
3334
import android.view.textclassifier.TextClassifier;
3435
import android.view.textclassifier.TextLinks;
@@ -77,6 +78,9 @@
7778
*/
7879

7980
public class Linkify {
81+
82+
private static final String LOG_TAG = "Linkify";
83+
8084
/**
8185
* Bit field indicating that web URLs should be matched in methods that
8286
* take an options mask
@@ -246,6 +250,11 @@ public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int m
246250

247251
private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
248252
@Nullable Context context) {
253+
if (text != null && containsUnsupportedCharacters(text.toString())) {
254+
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
255+
return false;
256+
}
257+
249258
if (mask == 0) {
250259
return false;
251260
}
@@ -291,6 +300,29 @@ private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
291300
return true;
292301
}
293302

303+
/**
304+
* Returns true if the specified text contains at least one unsupported character for applying
305+
* links. Also logs the error.
306+
*
307+
* @param text the text to apply links to
308+
* @hide
309+
*/
310+
public static boolean containsUnsupportedCharacters(String text) {
311+
if (text.contains("\u202C")) {
312+
Log.e(LOG_TAG, "Unsupported character for applying links: u202C");
313+
return true;
314+
}
315+
if (text.contains("\u202D")) {
316+
Log.e(LOG_TAG, "Unsupported character for applying links: u202D");
317+
return true;
318+
}
319+
if (text.contains("\u202E")) {
320+
Log.e(LOG_TAG, "Unsupported character for applying links: u202E");
321+
return true;
322+
}
323+
return false;
324+
}
325+
294326
/**
295327
* Scans the text of the provided TextView and turns all occurrences of
296328
* the link types indicated in the mask into clickable links. If matches
@@ -461,6 +493,11 @@ public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Patt
461493
public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
462494
@Nullable String defaultScheme, @Nullable String[] schemes,
463495
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
496+
if (spannable != null && containsUnsupportedCharacters(spannable.toString())) {
497+
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
498+
return false;
499+
}
500+
464501
final String[] schemesCopy;
465502
if (defaultScheme == null) defaultScheme = "";
466503
if (schemes == null || schemes.length < 1) {

core/java/android/view/textclassifier/TextClassification.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public final class TextClassification implements Parcelable {
104104
/**
105105
* @hide
106106
*/
107-
static final TextClassification EMPTY = new TextClassification.Builder().build();
107+
public static final TextClassification EMPTY = new TextClassification.Builder().build();
108108

109109
private static final String LOG_TAG = "TextClassification";
110110
// TODO(toki): investigate a way to derive this based on device properties.

core/java/android/view/textclassifier/TextLinksParams.java

+7
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ public int apply(@NonNull Spannable text, @NonNull TextLinks textLinks) {
107107
Preconditions.checkNotNull(textLinks);
108108

109109
final String textString = text.toString();
110+
111+
if (Linkify.containsUnsupportedCharacters(textString)) {
112+
// Do not apply links to text containing unsupported characters.
113+
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
114+
return TextLinks.STATUS_NO_LINKS_APPLIED;
115+
}
116+
110117
if (!textString.startsWith(textLinks.getText())) {
111118
return TextLinks.STATUS_DIFFERENT_TEXT;
112119
}

core/java/android/widget/SelectionActionModeHelper.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import android.text.Selection;
3232
import android.text.Spannable;
3333
import android.text.TextUtils;
34+
import android.text.util.Linkify;
3435
import android.util.Log;
3536
import android.view.ActionMode;
3637
import android.view.textclassifier.SelectionEvent;
@@ -1045,7 +1046,12 @@ private SelectionResult performClassification(@Nullable TextSelection selection)
10451046

10461047
trimText();
10471048
final TextClassification classification;
1048-
if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
1049+
if (Linkify.containsUnsupportedCharacters(mText)) {
1050+
// Do not show smart actions for text containing unsupported characters.
1051+
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
1052+
classification = TextClassification.EMPTY;
1053+
} else if (mContext.getApplicationInfo().targetSdkVersion
1054+
>= Build.VERSION_CODES.P) {
10491055
final TextClassification.Request request =
10501056
new TextClassification.Request.Builder(
10511057
mTrimmedText, mRelativeStart, mRelativeEnd)

core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import android.support.test.InstrumentationRegistry;
4040
import android.support.test.filters.SmallTest;
4141
import android.support.test.runner.AndroidJUnit4;
42+
import android.text.Spannable;
43+
import android.text.SpannableString;
4244

4345
import org.hamcrest.BaseMatcher;
4446
import org.hamcrest.Description;
@@ -306,6 +308,16 @@ public void testGenerateLinks_tooLong() {
306308
mClassifier.generateLinks(request);
307309
}
308310

311+
@Test
312+
public void testApplyLinks_unsupportedCharacter() {
313+
if (isTextClassifierDisabled()) return;
314+
Spannable url = new SpannableString("\u202Emoc.diordna.com");
315+
TextLinks.Request request = new TextLinks.Request.Builder(url).build();
316+
assertEquals(
317+
TextLinks.STATUS_NO_LINKS_APPLIED,
318+
mClassifier.generateLinks(request).apply(url, 0, null));
319+
}
320+
309321
@Test
310322
public void testSetTextClassifier() {
311323
TextClassifier classifier = mock(TextClassifier.class);

core/tests/coretests/src/android/widget/TextViewActivityTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,19 @@ public void testNoAssistItemForPasswordField() throws Throwable {
982982
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
983983
}
984984

985+
@Test
986+
public void testNoAssistItemForTextFieldWithUnsupportedCharacters() throws Throwable {
987+
useSystemDefaultTextClassifier();
988+
final String text = "\u202Emoc.diordna.com";
989+
final TextView textView = mActivity.findViewById(R.id.textview);
990+
mActivityRule.runOnUiThread(() -> textView.setText(text));
991+
mInstrumentation.waitForIdleSync();
992+
993+
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('.')));
994+
sleepForFloatingToolbarPopup();
995+
assertFloatingToolbarDoesNotContainItem(android.R.id.textAssist);
996+
}
997+
985998
@Test
986999
public void testSelectionMetricsLogger_noAbandonAfterCopy() throws Throwable {
9871000
final List<SelectionEvent> selectionEvents = new ArrayList<>();

location/java/com/android/internal/location/GpsNetInitiatedHandler.java

+45-28
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package com.android.internal.location;
1818

1919
import java.io.UnsupportedEncodingException;
20+
import java.util.concurrent.TimeUnit;
2021

2122
import android.app.Notification;
2223
import android.app.NotificationManager;
@@ -27,19 +28,17 @@
2728
import android.content.IntentFilter;
2829
import android.location.LocationManager;
2930
import android.location.INetInitiatedListener;
31+
import android.os.SystemClock;
3032
import android.telephony.TelephonyManager;
3133
import android.telephony.PhoneNumberUtils;
3234
import android.telephony.PhoneStateListener;
33-
import android.os.Bundle;
3435
import android.os.RemoteException;
3536
import android.os.UserHandle;
36-
import android.os.SystemProperties;
3737
import android.util.Log;
3838

3939
import com.android.internal.notification.SystemNotificationChannels;
4040
import com.android.internal.R;
4141
import com.android.internal.telephony.GsmAlphabet;
42-
import com.android.internal.telephony.TelephonyProperties;
4342

4443
/**
4544
* A GPS Network-initiated Handler class used by LocationManager.
@@ -50,8 +49,7 @@ public class GpsNetInitiatedHandler {
5049

5150
private static final String TAG = "GpsNetInitiatedHandler";
5251

53-
private static final boolean DEBUG = true;
54-
private static final boolean VERBOSE = false;
52+
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
5553

5654
// NI verify activity for bringing up UI (not used yet)
5755
public static final String ACTION_NI_VERIFY = "android.intent.action.NETWORK_INITIATED_VERIFY";
@@ -94,6 +92,9 @@ public class GpsNetInitiatedHandler {
9492
public static final int GPS_ENC_SUPL_UCS2 = 3;
9593
public static final int GPS_ENC_UNKNOWN = -1;
9694

95+
// Limit on SUPL NI emergency mode time extension after emergency sessions ends
96+
private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300; // 5 minute maximum
97+
9798
private final Context mContext;
9899
private final TelephonyManager mTelephonyManager;
99100
private final PhoneStateListener mPhoneStateListener;
@@ -109,7 +110,7 @@ public class GpsNetInitiatedHandler {
109110
private volatile boolean mIsSuplEsEnabled;
110111

111112
// Set to true if the phone is having emergency call.
112-
private volatile boolean mIsInEmergency;
113+
private volatile boolean mIsInEmergencyCall;
113114

114115
// If Location function is enabled.
115116
private volatile boolean mIsLocationEnabled = false;
@@ -119,6 +120,10 @@ public class GpsNetInitiatedHandler {
119120
// Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
120121
static private boolean mIsHexInput = true;
121122

123+
// End time of emergency call, and extension, if set
124+
private long mCallEndElapsedRealtimeMillis = 0;
125+
private long mEmergencyExtensionMillis = 0;
126+
122127
public static class GpsNiNotification
123128
{
124129
public int notificationId;
@@ -146,16 +151,12 @@ public static class GpsNiResponse {
146151
if (action.equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
147152
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
148153
/*
149-
Emergency Mode is when during emergency call or in emergency call back mode.
150-
For checking if it is during emergency call:
151-
mIsInEmergency records if the phone is in emergency call or not. It will
154+
Tracks the emergency call:
155+
mIsInEmergencyCall records if the phone is in emergency call or not. It will
152156
be set to true when the phone is having emergency call, and then will
153157
be set to false by mPhoneStateListener when the emergency call ends.
154-
For checking if it is in emergency call back mode:
155-
Emergency call back mode will be checked by reading system properties
156-
when necessary: SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)
157158
*/
158-
setInEmergency(PhoneNumberUtils.isEmergencyNumber(phoneNumber));
159+
mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber);
159160
if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
160161
} else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
161162
updateLocationMode();
@@ -195,7 +196,10 @@ public void onCallStateChanged(int state, String incomingNumber) {
195196
if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is "+ state);
196197
// listening for emergency call ends
197198
if (state == TelephonyManager.CALL_STATE_IDLE) {
198-
setInEmergency(false);
199+
if (mIsInEmergencyCall) {
200+
mCallEndElapsedRealtimeMillis = SystemClock.elapsedRealtime();
201+
mIsInEmergencyCall = false;
202+
}
199203
}
200204
}
201205
};
@@ -229,22 +233,35 @@ public boolean getLocationEnabled() {
229233
return mIsLocationEnabled;
230234
}
231235

232-
// Note: Currently, there are two mechanisms involved to determine if a
233-
// phone is in emergency mode:
234-
// 1. If the user is making an emergency call, this is provided by activly
235-
// monitoring the outgoing phone number;
236-
// 2. If the device is in a emergency callback state, this is provided by
237-
// system properties.
238-
// If either one of above exists, the phone is considered in an emergency
239-
// mode. Because of this complexity, we need to be careful about how to set
240-
// and clear the emergency state.
241-
public void setInEmergency(boolean isInEmergency) {
242-
mIsInEmergency = isInEmergency;
243-
}
244-
236+
/**
237+
* Determines whether device is in user-initiated emergency session based on the following
238+
* 1. If the user is making an emergency call, this is provided by actively
239+
* monitoring the outgoing phone number;
240+
* 2. If the user has recently ended an emergency call, and the device is in a configured time
241+
* window after the end of that call.
242+
* 3. If the device is in a emergency callback state, this is provided by querying
243+
* TelephonyManager.
244+
* @return true if is considered in user initiated emergency mode for NI purposes
245+
*/
245246
public boolean getInEmergency() {
247+
boolean isInEmergencyExtension =
248+
(SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) <
249+
mEmergencyExtensionMillis;
246250
boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode();
247-
return mIsInEmergency || isInEmergencyCallback;
251+
return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension;
252+
}
253+
254+
public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
255+
if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
256+
Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
257+
+ " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
258+
emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
259+
} else if (emergencyExtensionSeconds < 0) {
260+
Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
261+
+ " is negative, reset to zero.");
262+
emergencyExtensionSeconds = 0;
263+
}
264+
mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds);
248265
}
249266

250267

services/core/java/com/android/server/AlarmManagerService.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import android.database.ContentObserver;
4949
import android.net.Uri;
5050
import android.os.Binder;
51+
import android.os.Build;
5152
import android.os.Bundle;
5253
import android.os.Environment;
5354
import android.os.Handler;
@@ -1288,9 +1289,13 @@ public void onStart() {
12881289
// because kernel doesn't keep this after reboot
12891290
setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
12901291

1291-
// Also sure that we're booting with a halfway sensible current time
12921292
if (mNativeData != 0) {
1293-
final long systemBuildTime = Environment.getRootDirectory().lastModified();
1293+
// Ensure that we're booting with a halfway sensible current time. Use the
1294+
// most recent of Build.TIME, the root file system's timestamp, and the
1295+
// value of the ro.build.date.utc system property (which is in seconds).
1296+
final long systemBuildTime = Long.max(
1297+
1000L * SystemProperties.getLong("ro.build.date.utc", -1L),
1298+
Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
12941299
if (System.currentTimeMillis() < systemBuildTime) {
12951300
Slog.i(TAG, "Current time only " + System.currentTimeMillis()
12961301
+ ", advancing to build time " + systemBuildTime);

services/core/java/com/android/server/location/GnssLocationProvider.java

+11
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,17 @@ private void reloadGpsProperties(Context context, Properties properties) {
723723
Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
724724
}
725725
}
726+
727+
String emergencyExtensionSecondsString
728+
= properties.getProperty("ES_EXTENSION_SEC", "0");
729+
try {
730+
int emergencyExtensionSeconds =
731+
Integer.parseInt(emergencyExtensionSecondsString);
732+
mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds);
733+
} catch (NumberFormatException e) {
734+
Log.e(TAG, "unable to parse ES_EXTENSION_SEC: "
735+
+ emergencyExtensionSecondsString);
736+
}
726737
}
727738

728739
private void loadPropertiesFromResource(Context context,

services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java

+10-12
Original file line numberDiff line numberDiff line change
@@ -4795,18 +4795,16 @@ private boolean resetPasswordInternal(String password, long tokenHandle, byte[]
47954795
quality = PASSWORD_QUALITY_UNSPECIFIED;
47964796
}
47974797
final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
4798-
if (quality != PASSWORD_QUALITY_UNSPECIFIED) {
4799-
final int realQuality = metrics.quality;
4800-
if (realQuality < quality
4801-
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
4802-
Slog.w(LOG_TAG, "resetPassword: password quality 0x"
4803-
+ Integer.toHexString(realQuality)
4804-
+ " does not meet required quality 0x"
4805-
+ Integer.toHexString(quality));
4806-
return false;
4807-
}
4808-
quality = Math.max(realQuality, quality);
4798+
final int realQuality = metrics.quality;
4799+
if (realQuality < quality
4800+
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
4801+
Slog.w(LOG_TAG, "resetPassword: password quality 0x"
4802+
+ Integer.toHexString(realQuality)
4803+
+ " does not meet required quality 0x"
4804+
+ Integer.toHexString(quality));
4805+
return false;
48094806
}
4807+
quality = Math.max(realQuality, quality);
48104808
int length = getPasswordMinimumLength(null, userHandle, /* parent */ false);
48114809
if (password.length() < length) {
48124810
Slog.w(LOG_TAG, "resetPassword: password length " + password.length()
@@ -4892,7 +4890,7 @@ private boolean resetPasswordInternal(String password, long tokenHandle, byte[]
48924890
result = mLockPatternUtils.setLockCredentialWithToken(password,
48934891
TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE
48944892
: LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
4895-
quality, tokenHandle, token, userHandle);
4893+
quality, tokenHandle, token, userHandle);
48964894
}
48974895
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
48984896
if (requireEntry) {

0 commit comments

Comments
 (0)