diff options
37 files changed, 438 insertions, 689 deletions
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk index 200f92fb590c..f08b4025f95e 100644 --- a/apct-tests/perftests/core/Android.mk +++ b/apct-tests/perftests/core/Android.mk @@ -4,11 +4,14 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res -LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) \ + src/android/os/ISomeService.aidl LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ apct-perftests-utils \ + guava \ legacy-android-test LOCAL_PACKAGE_NAME := CorePerfTests diff --git a/apct-tests/perftests/core/AndroidManifest.xml b/apct-tests/perftests/core/AndroidManifest.xml index a709ee3ff913..f27e8c82a303 100644 --- a/apct-tests/perftests/core/AndroidManifest.xml +++ b/apct-tests/perftests/core/AndroidManifest.xml @@ -5,6 +5,7 @@ <application> <uses-library android:name="android.test.runner" /> <activity android:name="android.perftests.utils.StubActivity" /> + <service android:name="android.os.SomeService" android:exported="false" android:process=":some_service" /> </application> <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" diff --git a/apct-tests/perftests/core/src/android/os/ISomeService.aidl b/apct-tests/perftests/core/src/android/os/ISomeService.aidl new file mode 100644 index 000000000000..0658b698eb7d --- /dev/null +++ b/apct-tests/perftests/core/src/android/os/ISomeService.aidl @@ -0,0 +1,5 @@ +package android.os; + +interface ISomeService { + void readDisk(int times); +}
\ No newline at end of file diff --git a/apct-tests/perftests/core/src/android/os/SomeService.java b/apct-tests/perftests/core/src/android/os/SomeService.java new file mode 100644 index 000000000000..bdfaa444fb3d --- /dev/null +++ b/apct-tests/perftests/core/src/android/os/SomeService.java @@ -0,0 +1,42 @@ +package android.os; + +import android.app.Service; +import android.content.Intent; +import java.io.File; +import java.io.IOException; + +/** Service in separate process available for calling over binder. */ +public class SomeService extends Service { + + private File mTempFile; + + @Override + public void onCreate() { + super.onCreate(); + try { + mTempFile = File.createTempFile("foo", "bar"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private final ISomeService.Stub mBinder = + new ISomeService.Stub() { + public void readDisk(int times) { + for (int i = 0; i < times; i++) { + mTempFile.exists(); + } + } + }; + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + public void onDestroy() { + super.onDestroy(); + mTempFile.delete(); + } +} diff --git a/apct-tests/perftests/core/src/android/os/StrictModeTest.java b/apct-tests/perftests/core/src/android/os/StrictModeTest.java new file mode 100644 index 000000000000..d973c204f89e --- /dev/null +++ b/apct-tests/perftests/core/src/android/os/StrictModeTest.java @@ -0,0 +1,127 @@ +/* + * 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.os; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.net.Uri; +import android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.LargeTest; +import android.support.test.runner.AndroidJUnit4; +import com.google.common.util.concurrent.SettableFuture; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class StrictModeTest { + @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Test + public void timeVmViolation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build()); + causeVmViolations(state); + } + + @Test + public void timeVmViolationNoStrictMode() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + causeVmViolations(state); + } + + private static void causeVmViolations(BenchmarkState state) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setDataAndType(Uri.parse("content://com.example/foobar"), "image/jpeg"); + final Context context = InstrumentationRegistry.getTargetContext(); + while (state.keepRunning()) { + context.startActivity(intent); + } + } + + @Test + public void timeThreadViolation() throws IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + StrictMode.setThreadPolicy( + new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); + causeThreadViolations(state); + } + + @Test + public void timeThreadViolationNoStrictMode() throws IOException { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + causeThreadViolations(state); + } + + private static void causeThreadViolations(BenchmarkState state) throws IOException { + final File test = File.createTempFile("foo", "bar"); + while (state.keepRunning()) { + test.exists(); + } + test.delete(); + } + + @Test + public void timeCrossBinderThreadViolation() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + StrictMode.setThreadPolicy( + new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); + causeCrossProcessThreadViolations(state); + } + + @Test + public void timeCrossBinderThreadViolationNoStrictMode() throws Exception { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + causeCrossProcessThreadViolations(state); + } + + private static void causeCrossProcessThreadViolations(BenchmarkState state) + throws ExecutionException, InterruptedException, RemoteException { + final Context context = InstrumentationRegistry.getTargetContext(); + + SettableFuture<IBinder> binder = SettableFuture.create(); + ServiceConnection connection = + new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + binder.set(service); + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + binder.set(null); + } + }; + context.bindService( + new Intent(context, SomeService.class), connection, Context.BIND_AUTO_CREATE); + ISomeService someService = ISomeService.Stub.asInterface(binder.get()); + while (state.keepRunning()) { + // Violate strictmode heavily. + someService.readDisk(10); + } + context.unbindService(connection); + } +} diff --git a/api/current.txt b/api/current.txt index 8463260513b6..df8b7ef63bae 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35074,6 +35074,7 @@ package android.provider { field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS"; field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"; field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; + field public static final java.lang.String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL"; field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS"; field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"; field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"; diff --git a/api/system-current.txt b/api/system-current.txt index 9a59503b1879..007316fcf524 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -38138,6 +38138,7 @@ package android.provider { field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"; field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; + field public static final java.lang.String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL"; field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS"; field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"; field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"; @@ -41101,6 +41102,7 @@ package android.service.settings.suggestions { method public android.os.IBinder onBind(android.content.Intent); method public abstract java.util.List<android.service.settings.suggestions.Suggestion> onGetSuggestions(); method public abstract void onSuggestionDismissed(android.service.settings.suggestions.Suggestion); + method public abstract void onSuggestionLaunched(android.service.settings.suggestions.Suggestion); } } diff --git a/api/test-current.txt b/api/test-current.txt index 965dc72c148b..faccb6b58a3c 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -35345,6 +35345,7 @@ package android.provider { field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS"; field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS"; field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS"; + field public static final java.lang.String ACTION_FINGERPRINT_ENROLL = "android.settings.FINGERPRINT_ENROLL"; field public static final java.lang.String ACTION_HARD_KEYBOARD_SETTINGS = "android.settings.HARD_KEYBOARD_SETTINGS"; field public static final java.lang.String ACTION_HOME_SETTINGS = "android.settings.HOME_SETTINGS"; field public static final java.lang.String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS = "android.settings.IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS"; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 20fbf046a577..c165fb3e925c 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3604,7 +3604,6 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a - * {@link android.text.ClipboardManager} for accessing and modifying * {@link android.content.ClipboardManager} for accessing and modifying * the contents of the global clipboard. * diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 6f896446aa71..c200ae742125 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -442,6 +442,18 @@ public final class Settings { "android.settings.ASSIST_GESTURE_SETTINGS"; /** + * Activity Action: Show settings to enroll fingerprints, and setup PIN/Pattern/Pass if + * necessary. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_FINGERPRINT_ENROLL = + "android.settings.FINGERPRINT_ENROLL"; + + /** * Activity Action: Show settings to allow configuration of cast endpoints. * <p> * In some cases, a matching Activity may not exist, so ensure you diff --git a/core/java/android/service/settings/suggestions/ISuggestionService.aidl b/core/java/android/service/settings/suggestions/ISuggestionService.aidl index 423c507257c3..8dfa9c3193d3 100644 --- a/core/java/android/service/settings/suggestions/ISuggestionService.aidl +++ b/core/java/android/service/settings/suggestions/ISuggestionService.aidl @@ -17,4 +17,10 @@ interface ISuggestionService { * calls. */ void dismissSuggestion(in Suggestion suggestion) = 2; + + /** + * This is the opposite signal to {@link #dismissSuggestion}, indicating a suggestion has been + * launched. + */ + void launchSuggestion(in Suggestion suggestion) = 3; }
\ No newline at end of file diff --git a/core/java/android/service/settings/suggestions/SuggestionService.java b/core/java/android/service/settings/suggestions/SuggestionService.java index 2a4c84c2a1cf..ce9501d699ed 100644 --- a/core/java/android/service/settings/suggestions/SuggestionService.java +++ b/core/java/android/service/settings/suggestions/SuggestionService.java @@ -48,12 +48,20 @@ public abstract class SuggestionService extends Service { } @Override - public void dismissSuggestion(Suggestion suggestion) { + public void dismissSuggestion(Suggestion suggestion) { if (DEBUG) { Log.d(TAG, "dismissSuggestion() " + getPackageName()); } onSuggestionDismissed(suggestion); } + + @Override + public void launchSuggestion(Suggestion suggestion) { + if (DEBUG) { + Log.d(TAG, "launchSuggestion() " + getPackageName()); + } + onSuggestionLaunched(suggestion); + } }; } @@ -65,7 +73,12 @@ public abstract class SuggestionService extends Service { /** * Dismiss a suggestion. The suggestion will not be included in future * {@link #onGetSuggestions()} calls. - * @param suggestion */ public abstract void onSuggestionDismissed(Suggestion suggestion); + + /** + * This is the opposite signal to {@link #onSuggestionDismissed}, indicating a suggestion has + * been launched. + */ + public abstract void onSuggestionLaunched(Suggestion suggestion); } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 574137b30f1e..45008627e019 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -84,12 +84,17 @@ public class ViewConfiguration { /** * Defines the duration in milliseconds a user needs to hold down the - * appropriate button to bring up the accessibility shortcut (first time) or enable it - * (once shortcut is configured). + * appropriate button to bring up the accessibility shortcut for the first time */ private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000; /** + * Defines the duration in milliseconds a user needs to hold down the + * appropriate button to enable the accessibility shortcut once it's configured. + */ + private static final int A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION = 1500; + + /** * Defines the duration in milliseconds we will wait to see if a touch event * is a tap or a scroll. If the user does not move within this interval, it is * considered to be a tap. @@ -851,6 +856,15 @@ public class ViewConfiguration { } /** + * @return The amount of time a user needs to press the relevant keys to activate the + * accessibility shortcut after it's confirmed that accessibility shortcut is used. + * @hide + */ + public long getAccessibilityShortcutKeyTimeoutAfterConfirmation() { + return A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION; + } + + /** * The amount of friction applied to scrolls and flings. * * @return A scalar dimensionless value representing the coefficient of diff --git a/core/java/android/view/textclassifier/Log.java b/core/java/android/view/textclassifier/Log.java new file mode 100644 index 000000000000..83ca15df92f4 --- /dev/null +++ b/core/java/android/view/textclassifier/Log.java @@ -0,0 +1,46 @@ +/* + * 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.view.textclassifier; + +import android.util.Slog; + +/** + * Logging for android.view.textclassifier package. + */ +final class Log { + + /** + * true: Enables full logging. + * false: Limits logging to debug level. + */ + private static final boolean ENABLE_FULL_LOGGING = false; + + private Log() {} + + public static void d(String tag, String msg) { + Slog.d(tag, msg); + } + + public static void e(String tag, String msg, Throwable tr) { + if (ENABLE_FULL_LOGGING) { + Slog.e(tag, msg, tr); + } else { + final String trString = (tr != null) ? tr.getClass().getSimpleName() : "??"; + Slog.d(tag, String.format("%s (%s)", msg, trString)); + } + } +} diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index ef0874722d6f..1c07be4bcd75 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -35,7 +35,6 @@ import android.text.TextUtils; import android.text.method.WordIterator; import android.text.style.ClickableSpan; import android.text.util.Linkify; -import android.util.Log; import android.util.Patterns; import android.view.View; import android.widget.TextViewMetrics; @@ -163,7 +162,7 @@ final class TextClassifierImpl implements TextClassifier { } } catch (Throwable t) { // Avoid throwing from this method. Log the error. - Log.e(LOG_TAG, "Error getting assist info.", t); + Log.e(LOG_TAG, "Error getting text classification info.", t); } // Getting here means something went wrong, return a NO_OP result. return TextClassifier.NO_OP.classifyText( diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java index 3d5cd0f5847b..d0719eeca04e 100644 --- a/core/java/com/android/internal/app/LocalePickerWithRegion.java +++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java @@ -238,7 +238,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O mSearchView.setOnQueryTextListener(this); // Restore previous search status - if (mPreviousSearch != null) { + if (!TextUtils.isEmpty(mPreviousSearch)) { searchMenuItem.expandActionView(); mSearchView.setIconified(false); mSearchView.setActivated(true); diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 93c02b0e05f6..78a8e2a3c748 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4346,8 +4346,6 @@ <string name="lock_to_app_toast">To unpin this screen, touch & hold Back and Overview buttons</string> - <!-- Notify user that they are locked in lock-to-app mode --> - <string name="lock_to_app_toast_locked">This app can\'t be unpinned</string> <!-- Starting lock-to-app indication. --> <string name="lock_to_app_start">Screen pinned</string> <!-- Exting lock-to-app indication. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index a42cf42cb905..7bbd17e62c48 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -754,7 +754,6 @@ <java-symbol type="string" name="last_month" /> <java-symbol type="string" name="launchBrowserDefault" /> <java-symbol type="string" name="lock_to_app_toast" /> - <java-symbol type="string" name="lock_to_app_toast_locked" /> <java-symbol type="string" name="lock_to_app_start" /> <java-symbol type="string" name="lock_to_app_exit" /> <java-symbol type="string" name="lock_to_app_unlock_pin" /> diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf Binary files differdeleted file mode 100644 index 1bad6fe75090..000000000000 --- a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf +++ /dev/null diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx deleted file mode 100644 index 0cf0f7914931..000000000000 --- a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx +++ /dev/null @@ -1,207 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- 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. ---> -<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0"> - - <GlyphOrder> - <GlyphID id="0" name=".notdef"/> - <GlyphID id="1" name="0em"/> - <GlyphID id="2" name="1em"/> - <GlyphID id="3" name="3em"/> - <GlyphID id="4" name="5em"/> - <GlyphID id="5" name="7em"/> - <GlyphID id="6" name="10em"/> - <GlyphID id="7" name="50em"/> - <GlyphID id="8" name="100em"/> - </GlyphOrder> - - <head> - <tableVersion value="1.0"/> - <fontRevision value="1.0"/> - <checkSumAdjustment value="0x640cdb2f"/> - <magicNumber value="0x5f0f3cf5"/> - <flags value="00000000 00000011"/> - <unitsPerEm value="100"/> - <created value="Fri Mar 17 07:26:00 2017"/> - <macStyle value="00000000 00000000"/> - <lowestRecPPEM value="7"/> - <fontDirectionHint value="2"/> - <glyphDataFormat value="0"/> - </head> - - <hhea> - <tableVersion value="0x00010000"/> - <ascent value="1000"/> - <descent value="-200"/> - <lineGap value="0"/> - <caretSlopeRise value="1"/> - <caretSlopeRun value="0"/> - <caretOffset value="0"/> - <reserved0 value="0"/> - <reserved1 value="0"/> - <reserved2 value="0"/> - <reserved3 value="0"/> - <metricDataFormat value="0"/> - </hhea> - - <maxp> - <tableVersion value="0x10000"/> - <maxZones value="0"/> - <maxTwilightPoints value="0"/> - <maxStorage value="0"/> - <maxFunctionDefs value="0"/> - <maxInstructionDefs value="0"/> - <maxStackElements value="0"/> - <maxSizeOfInstructions value="0"/> - <maxComponentElements value="0"/> - </maxp> - - <OS_2> - <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' - will be recalculated by the compiler --> - <version value="3"/> - <xAvgCharWidth value="594"/> - <usWeightClass value="400"/> - <usWidthClass value="5"/> - <fsType value="00000000 00001000"/> - <ySubscriptXSize value="650"/> - <ySubscriptYSize value="600"/> - <ySubscriptXOffset value="0"/> - <ySubscriptYOffset value="75"/> - <ySuperscriptXSize value="650"/> - <ySuperscriptYSize value="600"/> - <ySuperscriptXOffset value="0"/> - <ySuperscriptYOffset value="350"/> - <yStrikeoutSize value="50"/> - <yStrikeoutPosition value="300"/> - <sFamilyClass value="0"/> - <panose> - <bFamilyType value="0"/> - <bSerifStyle value="0"/> - <bWeight value="5"/> - <bProportion value="0"/> - <bContrast value="0"/> - <bStrokeVariation value="0"/> - <bArmStyle value="0"/> - <bLetterForm value="0"/> - <bMidline value="0"/> - <bXHeight value="0"/> - </panose> - <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> - <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> - <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> - <achVendID value="UKWN"/> - <fsSelection value="00000000 01000000"/> - <usFirstCharIndex value="32"/> - <usLastCharIndex value="122"/> - <sTypoAscender value="800"/> - <sTypoDescender value="-200"/> - <sTypoLineGap value="200"/> - <usWinAscent value="1000"/> - <usWinDescent value="200"/> - <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> - <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> - <sxHeight value="500"/> - <sCapHeight value="700"/> - <usDefaultChar value="0"/> - <usBreakChar value="32"/> - <usMaxContext value="0"/> - </OS_2> - - <hmtx> - <mtx name=".notdef" width="50" lsb="0"/> - <mtx name="0em" width="0" lsb="0"/> - <mtx name="1em" width="100" lsb="0"/> - <mtx name="3em" width="300" lsb="0"/> - <mtx name="5em" width="500" lsb="0"/> - <mtx name="7em" width="700" lsb="0"/> - <mtx name="10em" width="1000" lsb="0"/> - <mtx name="50em" width="5000" lsb="0"/> - <mtx name="100em" width="10000" lsb="0"/> - </hmtx> - - <cmap> - <tableVersion version="0"/> - <cmap_format_12 format="12" reserved="0" length="6" nGroups="1" platformID="3" platEncID="10" language="0"> - <map code="0x0020" name="10em" /> - <map code="0x002e" name="10em" /> <!-- . --> - <map code="0x0043" name="100em" /> <!-- C --> - <map code="0x0049" name="1em" /> <!-- I --> - <map code="0x004c" name="50em" /> <!-- L --> - <map code="0x0056" name="5em" /> <!-- V --> - <map code="0x0058" name="10em" /> <!-- X --> - <map code="0x005f" name="0em" /> <!-- _ --> - <map code="0xfffd" name="7em" /> <!-- REPLACEMENT CHAR --> - <map code="0x10331" name="10em" /> - </cmap_format_12> - </cmap> - - <loca> - <!-- The 'loca' table will be calculated by the compiler --> - </loca> - - <glyf> - <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="0em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="5em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="7em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="10em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="50em" xMin="0" yMin="0" xMax="0" yMax="0" /> - <TTGlyph name="100em" xMin="0" yMin="0" xMax="0" yMax="0" /> - </glyf> - - <name> - <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True"> - Font for StaticLayoutLineBreakingTest - </namerecord> - <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True"> - Regular - </namerecord> - <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True"> - Font for StaticLayoutLineBreakingTest - </namerecord> - <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True"> - SampleFont-Regular - </namerecord> - <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> - Regular - </namerecord> - <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> - Sample Font - </namerecord> - <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> - SampleFont-Regular - </namerecord> - </name> - - <post> - <formatType value="3.0"/> - <italicAngle value="0.0"/> - <underlinePosition value="-75"/> - <underlineThickness value="50"/> - <isFixedPitch value="0"/> - <minMemType42 value="0"/> - <maxMemType42 value="0"/> - <minMemType1 value="0"/> - <maxMemType1 value="0"/> - </post> - -</ttFont> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 0b768f878af8..ebe0527cbbec 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -38,7 +38,6 @@ import java.util.HashSet; import java.util.Set; /** Tests that ensure appropriate settings are backed up. */ -@Presubmit @RunWith(AndroidJUnit4.class) @SmallTest public class SettingsBackupTest { diff --git a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java index c158b9f0bf71..ab541a15cdcc 100644 --- a/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java +++ b/core/tests/coretests/src/android/service/settings/suggestions/MockSuggestionService.java @@ -16,11 +16,23 @@ package android.service.settings.suggestions; +import android.support.annotation.VisibleForTesting; + import java.util.ArrayList; import java.util.List; public class MockSuggestionService extends SuggestionService { + @VisibleForTesting + static boolean sOnSuggestionLaunchedCalled; + @VisibleForTesting + static boolean sOnSuggestionDismissedCalled; + + public static void reset() { + sOnSuggestionLaunchedCalled = false; + sOnSuggestionDismissedCalled = false; + } + @Override public List<Suggestion> onGetSuggestions() { final List<Suggestion> data = new ArrayList<>(); @@ -34,5 +46,11 @@ public class MockSuggestionService extends SuggestionService { @Override public void onSuggestionDismissed(Suggestion suggestion) { + sOnSuggestionDismissedCalled = true; + } + + @Override + public void onSuggestionLaunched(Suggestion suggestion) { + sOnSuggestionLaunchedCalled = true; } } diff --git a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java index bc8823184417..dca8c096dc59 100644 --- a/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java +++ b/core/tests/coretests/src/android/service/settings/suggestions/SuggestionServiceTest.java @@ -16,12 +16,17 @@ package android.service.settings.suggestions; +import static com.google.common.truth.Truth.assertThat; + import android.content.Intent; +import android.os.IBinder; +import android.os.RemoteException; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.rule.ServiceTestRule; import android.support.test.runner.AndroidJUnit4; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -45,9 +50,36 @@ public class SuggestionServiceTest { MockSuggestionService.class); } + @After + public void tearUp() { + MockSuggestionService.reset(); + } + @Test public void canStartService() throws TimeoutException { mServiceTestRule.startService(mMockServiceIntent); // Do nothing after starting service. } + + @Test + public void dismissSuggestion_shouldCallImplementation() + throws TimeoutException, RemoteException { + MockSuggestionService service = new MockSuggestionService(); + IBinder binder = mServiceTestRule.bindService(mMockServiceIntent); + ISuggestionService serviceBinder = ISuggestionService.Stub.asInterface(binder); + serviceBinder.dismissSuggestion(null); + + assertThat(service.sOnSuggestionDismissedCalled).isTrue(); + } + + @Test + public void launchSuggestion_shouldCallImplementation() + throws TimeoutException, RemoteException { + MockSuggestionService service = new MockSuggestionService(); + IBinder binder = mServiceTestRule.bindService(mMockServiceIntent); + ISuggestionService serviceBinder = ISuggestionService.Stub.asInterface(binder); + serviceBinder.launchSuggestion(null); + + assertThat(service.sOnSuggestionLaunchedCalled).isTrue(); + } } diff --git a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java b/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java deleted file mode 100644 index f7dbafad38d1..000000000000 --- a/core/tests/coretests/src/android/text/StaticLayoutLineBreakingTest.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2012 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.text; - -import static org.junit.Assert.assertEquals; - -import android.content.Context;; -import android.graphics.Typeface; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.text.Layout.Alignment; -import android.text.style.MetricAffectingSpan; -import android.util.Log; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@SmallTest -@RunWith(AndroidJUnit4.class) -public class StaticLayoutLineBreakingTest { - // Span test are currently not supported because text measurement uses the MeasuredText - // internal mWorkPaint instead of the provided MockTestPaint. - private static final boolean SPAN_TESTS_SUPPORTED = false; - private static final boolean DEBUG = false; - - private static final float SPACE_MULTI = 1.0f; - private static final float SPACE_ADD = 0.0f; - private static final int WIDTH = 100; - private static final Alignment ALIGN = Alignment.ALIGN_LEFT; - - private static final char SURR_FIRST = '\uD800'; - private static final char SURR_SECOND = '\uDF31'; - - private static final int[] NO_BREAK = new int[] {}; - - private static final TextPaint sTextPaint = new TextPaint(); - - static { - // The test font has following coverage and width. - // U+0020: 10em - // U+002E (.): 10em - // U+0043 (C): 100em - // U+0049 (I): 1em - // U+004C (L): 50em - // U+0056 (V): 5em - // U+0058 (X): 10em - // U+005F (_): 0em - // U+FFFD (invalid surrogate will be replaced to this): 7em - // U+10331 (\uD800\uDF31): 10em - Context context = InstrumentationRegistry.getTargetContext(); - sTextPaint.setTypeface(Typeface.createFromAsset(context.getAssets(), - "fonts/StaticLayoutLineBreakingTestFont.ttf")); - sTextPaint.setTextSize(1.0f); // Make 1em == 1px. - } - - private static StaticLayout getStaticLayout(CharSequence source, int width) { - return new StaticLayout(source, sTextPaint, width, ALIGN, SPACE_MULTI, SPACE_ADD, false); - } - - private static int[] getBreaks(CharSequence source) { - return getBreaks(source, WIDTH); - } - - private static int[] getBreaks(CharSequence source, int width) { - StaticLayout staticLayout = getStaticLayout(source, width); - - int[] breaks = new int[staticLayout.getLineCount() - 1]; - for (int line = 0; line < breaks.length; line++) { - breaks[line] = staticLayout.getLineEnd(line); - } - return breaks; - } - - private static void debugLayout(CharSequence source, StaticLayout staticLayout) { - if (DEBUG) { - int count = staticLayout.getLineCount(); - Log.i("SLLBTest", "\"" + source.toString() + "\": " - + count + " lines"); - for (int line = 0; line < count; line++) { - int lineStart = staticLayout.getLineStart(line); - int lineEnd = staticLayout.getLineEnd(line); - Log.i("SLLBTest", "Line " + line + " [" + lineStart + ".." - + lineEnd + "]\t" + source.subSequence(lineStart, lineEnd)); - } - } - } - - private static void layout(CharSequence source, int[] breaks) { - layout(source, breaks, WIDTH); - } - - private static void layout(CharSequence source, int[] breaks, int width) { - StaticLayout staticLayout = getStaticLayout(source, width); - - debugLayout(source, staticLayout); - - int lineCount = breaks.length + 1; - assertEquals("Number of lines", lineCount, staticLayout.getLineCount()); - - for (int line = 0; line < lineCount; line++) { - int lineStart = staticLayout.getLineStart(line); - int lineEnd = staticLayout.getLineEnd(line); - - if (line == 0) { - assertEquals("Line start for first line", 0, lineStart); - } else { - assertEquals("Line start for line " + line, breaks[line - 1], lineStart); - } - - if (line == lineCount - 1) { - assertEquals("Line end for last line", source.length(), lineEnd); - } else { - assertEquals("Line end for line " + line, breaks[line], lineEnd); - } - } - } - - private static void layoutMaxLines(CharSequence source, int[] breaks, int maxLines) { - StaticLayout staticLayout = new StaticLayout(source, 0, source.length(), sTextPaint, WIDTH, - ALIGN, TextDirectionHeuristics.LTR, SPACE_MULTI, SPACE_ADD, false /* includePad */, - null, WIDTH, maxLines); - - debugLayout(source, staticLayout); - - final int lineCount = staticLayout.getLineCount(); - - for (int line = 0; line < lineCount; line++) { - int lineStart = staticLayout.getLineStart(line); - int lineEnd = staticLayout.getLineEnd(line); - - if (line == 0) { - assertEquals("Line start for first line", 0, lineStart); - } else { - assertEquals("Line start for line " + line, breaks[line - 1], lineStart); - } - - if (line == lineCount - 1 && line != breaks.length - 1) { - assertEquals("Line end for last line", source.length(), lineEnd); - } else { - assertEquals("Line end for line " + line, breaks[line], lineEnd); - } - } - } - - private static final int MAX_SPAN_COUNT = 10; - private static final int[] sSpanStarts = new int[MAX_SPAN_COUNT]; - private static final int[] sSpanEnds = new int[MAX_SPAN_COUNT]; - - private static MetricAffectingSpan getMetricAffectingSpan() { - return new MetricAffectingSpan() { - @Override - public void updateDrawState(TextPaint tp) { /* empty */ } - - @Override - public void updateMeasureState(TextPaint p) { /* empty */ } - }; - } - - /** - * Replaces the "<...>" blocks by spans, assuming non overlapping, correctly defined spans - * @param text - * @return A CharSequence with '<' '>' replaced by MetricAffectingSpan - */ - private static CharSequence spanify(String text) { - int startIndex = text.indexOf('<'); - if (startIndex < 0) return text; - - int spanCount = 0; - do { - int endIndex = text.indexOf('>'); - if (endIndex < 0) throw new IllegalArgumentException("Unbalanced span markers"); - - text = text.substring(0, startIndex) + text.substring(startIndex + 1, endIndex) - + text.substring(endIndex + 1); - - sSpanStarts[spanCount] = startIndex; - sSpanEnds[spanCount] = endIndex - 2; - spanCount++; - - startIndex = text.indexOf('<'); - } while (startIndex >= 0); - - SpannableStringBuilder result = new SpannableStringBuilder(text); - for (int i = 0; i < spanCount; i++) { - result.setSpan(getMetricAffectingSpan(), sSpanStarts[i], sSpanEnds[i], - Spanned.SPAN_INCLUSIVE_INCLUSIVE); - } - return result; - } - - @Test - public void testNoLineBreak() { - // Width lower than WIDTH - layout("", NO_BREAK); - layout("I", NO_BREAK); - layout("V", NO_BREAK); - layout("X", NO_BREAK); - layout("L", NO_BREAK); - layout("I VILI", NO_BREAK); - layout("XXXX", NO_BREAK); - layout("LXXXX", NO_BREAK); - - // Width equal to WIDTH - layout("C", NO_BREAK); - layout("LL", NO_BREAK); - layout("L XXXX", NO_BREAK); - layout("XXXXXXXXXX", NO_BREAK); - layout("XXX XXXXXX", NO_BREAK); - layout("XXX XXXX X", NO_BREAK); - layout("XXX XXXXX ", NO_BREAK); - layout(" XXXXXXXX ", NO_BREAK); - layout(" XX XXX ", NO_BREAK); - // 0123456789 - - // Width greater than WIDTH, but no break - layout(" XX XXX ", NO_BREAK); - layout("XX XXX XXX ", NO_BREAK); - layout("XX XXX XXX ", NO_BREAK); - layout("XXXXXXXXXX ", NO_BREAK); - // 01234567890 - } - - @Test - public void testOneLineBreak() { - // 01234567890 - layout("XX XXX XXXX", new int[] {7}); - layout("XX XXXX XXX", new int[] {8}); - layout("XX XXXXX XX", new int[] {9}); - layout("XX XXXXXX X", new int[] {10}); - // 01234567890 - layout("XXXXXXXXXXX", new int[] {10}); - layout("XXXXXXXXX X", new int[] {10}); - layout("XXXXXXXX XX", new int[] {9}); - layout("XXXXXXX XXX", new int[] {8}); - layout("XXXXXX XXXX", new int[] {7}); - // 01234567890 - layout("LL LL", new int[] {3}); - layout("LLLL", new int[] {2}); - layout("C C", new int[] {2}); - layout("CC", new int[] {1}); - } - - @Test - public void testSpaceAtBreak() { - // 0123456789012 - layout("XXXX XXXXX X", new int[] {11}); - layout("XXXXXXXXXX X", new int[] {11}); - layout("XXXXXXXXXV X", new int[] {11}); - layout("C X", new int[] {2}); - } - - @Test - public void testMultipleSpacesAtBreak() { - // 0123456789012 - layout("LXX XXXX", new int[] {4}); - layout("LXX XXXX", new int[] {5}); - layout("LXX XXXX", new int[] {6}); - layout("LXX XXXX", new int[] {7}); - layout("LXX XXXX", new int[] {8}); - } - - @Test - public void testZeroWidthCharacters() { - // 0123456789012345678901234 - layout("X_X_X_X_X_X_X_X_X_X", NO_BREAK); - layout("___X_X_X_X_X_X_X_X_X_X___", NO_BREAK); - layout("C_X", new int[] {2}); - layout("C__X", new int[] {3}); - } - - /** - * Note that when the text has spans, StaticLayout does not use the provided TextPaint to - * measure text runs anymore. This is probably a bug. - * To be able to use the fake sTextPaint and make this test pass, use mPaint instead of - * mWorkPaint in MeasuredText#addStyleRun - */ - @Test - public void testWithSpans() { - if (!SPAN_TESTS_SUPPORTED) return; - - layout(spanify("<012 456 89>"), NO_BREAK); - layout(spanify("012 <456> 89"), NO_BREAK); - layout(spanify("<012> <456>< 89>"), NO_BREAK); - layout(spanify("<012> <456> <89>"), NO_BREAK); - - layout(spanify("<012> <456> <89>012"), new int[] {8}); - layout(spanify("<012> <456> 89<012>"), new int[] {8}); - layout(spanify("<012> <456> <89><012>"), new int[] {8}); - layout(spanify("<012> <456> 89 <123>"), new int[] {11}); - layout(spanify("<012> <456> 89< 123>"), new int[] {11}); - layout(spanify("<012> <456> <89> <123>"), new int[] {11}); - layout(spanify("012 456 89 <LXX> XX XX"), new int[] {11, 18}); - } - - /* - * Adding a span to the string should not change the layout, since the metrics are unchanged. - */ - @Test - public void testWithOneSpan() { - if (!SPAN_TESTS_SUPPORTED) return; - - String[] texts = new String[] { "0123", "012 456", "012 456 89 123", "012 45678 012", - "012 456 89012 456 89012", "0123456789012" }; - - MetricAffectingSpan metricAffectingSpan = getMetricAffectingSpan(); - - for (String text : texts) { - // Get the line breaks without any span - int[] breaks = getBreaks(text); - - // Add spans on all possible offsets - for (int spanStart = 0; spanStart < text.length(); spanStart++) { - for (int spanEnd = spanStart; spanEnd < text.length(); spanEnd++) { - SpannableStringBuilder ssb = new SpannableStringBuilder(text); - ssb.setSpan(metricAffectingSpan, spanStart, spanEnd, - Spanned.SPAN_INCLUSIVE_INCLUSIVE); - layout(ssb, breaks); - } - } - } - } - - @Test - public void testWithTwoSpans() { - if (!SPAN_TESTS_SUPPORTED) return; - - String[] texts = new String[] { "0123", "012 456", "012 456 89 123", "012 45678 012", - "012 456 89012 456 89012", "0123456789012" }; - - MetricAffectingSpan metricAffectingSpan1 = getMetricAffectingSpan(); - MetricAffectingSpan metricAffectingSpan2 = getMetricAffectingSpan(); - - for (String text : texts) { - // Get the line breaks without any span - int[] breaks = getBreaks(text); - - // Add spans on all possible offsets - for (int spanStart1 = 0; spanStart1 < text.length(); spanStart1++) { - for (int spanEnd1 = spanStart1; spanEnd1 < text.length(); spanEnd1++) { - SpannableStringBuilder ssb = new SpannableStringBuilder(text); - ssb.setSpan(metricAffectingSpan1, spanStart1, spanEnd1, - Spanned.SPAN_INCLUSIVE_INCLUSIVE); - - for (int spanStart2 = 0; spanStart2 < text.length(); spanStart2++) { - for (int spanEnd2 = spanStart2; spanEnd2 < text.length(); spanEnd2++) { - ssb.setSpan(metricAffectingSpan2, spanStart2, spanEnd2, - Spanned.SPAN_INCLUSIVE_INCLUSIVE); - layout(ssb, breaks); - } - } - } - } - } - } - - public static String replace(String string, char c, char r) { - return string.replaceAll(String.valueOf(c), String.valueOf(r)); - } - - @Test - public void testWithSurrogate() { - layout("LX" + SURR_FIRST + SURR_SECOND, NO_BREAK); - layout("LXXXX" + SURR_FIRST + SURR_SECOND, NO_BREAK); - // LXXXXI (91) + SURR_FIRST + SURR_SECOND (10). Do not break in the middle point of - // surrogatge pair. - layout("LXXXXI" + SURR_FIRST + SURR_SECOND, new int[] {6}); - - // LXXXXI (91) + SURR_SECOND (replaced with REPLACEMENT CHARACTER. width is 7px) fits. - // Break just after invalid trailing surrogate. - layout("LXXXXI" + SURR_SECOND + SURR_FIRST, new int[] {7}); - - layout("C" + SURR_FIRST + SURR_SECOND, new int[] {1}); - } - - @Test - public void testNarrowWidth() { - int[] widths = new int[] { 0, 4, 10 }; - String[] texts = new String[] { "", "X", " ", "XX", " X", "XXX" }; - - for (String text: texts) { - // 15 is such that only one character will fit - int[] breaks = getBreaks(text, 15); - - // Width under 15 should all lead to the same line break - for (int width: widths) { - layout(text, breaks, width); - } - } - } - - @Test - public void testNarrowWidthZeroWidth() { - int[] widths = new int[] { 1, 4 }; - for (int width: widths) { - layout("X.", new int[] {1}, width); - layout("X__", NO_BREAK, width); - layout("X__X", new int[] {3}, width); - layout("X__X_", new int[] {3}, width); - - layout("_", NO_BREAK, width); - layout("__", NO_BREAK, width); - layout("_X", new int[] {1}, width); - layout("_X_", new int[] {1}, width); - layout("__X__", new int[] {2}, width); - } - } - - @Test - public void testMaxLines() { - layoutMaxLines("C", NO_BREAK, 1); - layoutMaxLines("C C", new int[] {2}, 1); - layoutMaxLines("C C", new int[] {2}, 2); - layoutMaxLines("CC", new int[] {1}, 1); - layoutMaxLines("CC", new int[] {1}, 2); - } -} diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp index 1e71cb081b39..6b8006cc5a33 100644 --- a/libs/hwui/Extensions.cpp +++ b/libs/hwui/Extensions.cpp @@ -31,6 +31,12 @@ namespace android { namespace uirenderer { Extensions::Extensions() { + if (Properties::getRenderPipelineType() != RenderPipelineType::OpenGL) { + //Extensions class is used only by OpenGL pipeline + //The code below will crash for SkiaVulkan, because OpenGL is not initialized + //TODO: instantiate Extensions class only for OpenGL pipeline + return; + } const char* version = (const char*) glGetString(GL_VERSION); // Section 6.1.5 of the OpenGL ES specification indicates the GL version diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp index 9982a0cfe2bf..75967e9f6503 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp @@ -73,7 +73,7 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4 * for reading back float buffers (skbug.com/6945). */ if (pixelConfig == kRGBA_half_GrPixelConfig && - !DeviceInfo::get()->extensions().hasFloatTextures()) { + !grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) { ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported"); return CopyResult::DestinationInvalid; } diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index c4bd1e1b10d4..cdf4aee609fb 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -75,6 +75,12 @@ void SkiaPipeline::unpinImages() { mPinnedImages.clear(); } +void SkiaPipeline::onPrepareTree() { + // The only time mVectorDrawables is not empty is if prepare tree was called 2 times without + // a renderFrame in the middle. + mVectorDrawables.clear(); +} + void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo) { diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h index 3e6ae306217c..dc0b8f6dd2bc 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaPipeline.h @@ -37,6 +37,7 @@ public: bool pinImages(std::vector<SkImage*>& mutableImages) override; bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override { return false; } void unpinImages() override; + void onPrepareTree() override; void renderLayers(const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 5d7f5948b0ec..ad684db56d94 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -331,6 +331,7 @@ void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, info.layerUpdateQueue = &mLayerUpdateQueue; mAnimationContext->startFrame(info.mode); + mRenderPipeline->onPrepareTree(); for (const sp<RenderNode>& node : mRenderNodes) { // Only the primary target node will be drawn full - all other nodes would get drawn in // real time mode. In case of a window, the primary node is the window content and the other diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index f9b6e384d211..0bb3889c7a1d 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -81,6 +81,7 @@ public: virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0; virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0; virtual void unpinImages() = 0; + virtual void onPrepareTree() = 0; virtual ~IRenderPipeline() {} }; diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h index 4ca19fb6245c..1f467c164d7f 100644 --- a/libs/hwui/renderthread/OpenGLPipeline.h +++ b/libs/hwui/renderthread/OpenGLPipeline.h @@ -58,6 +58,7 @@ public: bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; } bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override; void unpinImages() override; + void onPrepareTree() override {} static void destroyLayer(RenderNode* node); static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap); static void invokeFunctor(const RenderThread& thread, Functor* functor); diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index b397b151ad76..f430ce633717 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -56,6 +56,40 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) { ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); } +RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) { + + auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1, + [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) { + redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver); + }); + + LayerUpdateQueue layerUpdateQueue; + SkRect dirty = SkRect::MakeLargest(); + std::vector<sp<RenderNode>> renderNodes; + renderNodes.push_back(redNode); + bool opaque = true; + android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1); + auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread); + { + //add a pointer to a deleted vector drawable object in the pipeline + sp<VectorDrawableRoot> dirtyVD(new VectorDrawableRoot(new VectorDrawable::Group())); + dirtyVD->mutateProperties()->setScaledSize(5,5); + pipeline->getVectorDrawables()->push_back(dirtyVD.get()); + } + + //pipeline should clean list of dirty vector drawables before prepare tree + pipeline->onPrepareTree(); + + auto surface = SkSurface::MakeRasterN32Premul(1, 1); + surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver); + ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE); + + //drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer + pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, + opaque, false, contentDrawBounds, surface); + ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED); +} + RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) { auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS new file mode 100644 index 000000000000..d5d2e9e8c146 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS @@ -0,0 +1,7 @@ +# Default reviewers for this and subdirectories. +asapperstein@google.com +asargent@google.com +dling@google.com +zhfan@google.com + +# Emergency approvers in case the above are not available
\ No newline at end of file diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java index 940f9051ec1e..1c094c174e6a 100644 --- a/services/core/java/com/android/server/am/LockTaskController.java +++ b/services/core/java/com/android/server/am/LockTaskController.java @@ -327,7 +327,9 @@ public class LockTaskController { if (getDevicePolicyManager() != null) { getDevicePolicyManager().notifyLockTaskModeChanged(false, null, userId); } - getLockTaskNotify().show(false); + if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) { + getLockTaskNotify().showPinningExitToast(); + } try { boolean shouldLockKeyguard = Settings.Secure.getIntForUser( mContext.getContentResolver(), @@ -349,10 +351,13 @@ public class LockTaskController { } /** - * Show the lock task violation toast. + * Show the lock task violation toast. Currently we only show toast for screen pinning mode, and + * no-op if the device is in locked mode. */ void showLockTaskToast() { - mHandler.post(() -> getLockTaskNotify().showToast(mLockTaskModeState)); + if (mLockTaskModeState == LOCK_TASK_MODE_PINNED) { + mHandler.post(() -> getLockTaskNotify().showEscapeToast()); + } } // Starting lock task @@ -439,7 +444,9 @@ public class LockTaskController { private void performStartLockTask(String packageName, int userId, int lockTaskModeState) { // When lock task starts, we disable the status bars. try { - getLockTaskNotify().show(true); + if (lockTaskModeState == LOCK_TASK_MODE_PINNED) { + getLockTaskNotify().showPinningStartToast(); + } mLockTaskModeState = lockTaskModeState; if (getStatusBarService() != null) { int flags = 0; diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java index 0412db5e49c9..5d6e9b58881f 100644 --- a/services/core/java/com/android/server/am/LockTaskNotify.java +++ b/services/core/java/com/android/server/am/LockTaskNotify.java @@ -16,7 +16,6 @@ package com.android.server.am; -import android.app.ActivityManager; import android.content.Context; import android.os.Handler; import android.os.Message; @@ -29,7 +28,7 @@ import com.android.internal.R; /** * Helper to manage showing/hiding a image to notify them that they are entering - * or exiting lock-to-app mode. + * or exiting screen pinning mode. */ public class LockTaskNotify { private static final String TAG = "LockTaskNotify"; @@ -45,20 +44,22 @@ public class LockTaskNotify { mHandler = new H(); } - public void showToast(int lockTaskModeState) { - mHandler.obtainMessage(H.SHOW_TOAST, lockTaskModeState, 0 /* Not used */).sendToTarget(); + /** Show "Screen pinned" toast. */ + void showPinningStartToast() { + makeAllUserToastAndShow(R.string.lock_to_app_start); } - public void handleShowToast(int lockTaskModeState) { - String text = null; - if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_LOCKED) { - text = mContext.getString(R.string.lock_to_app_toast_locked); - } else if (lockTaskModeState == ActivityManager.LOCK_TASK_MODE_PINNED) { - text = mContext.getString(R.string.lock_to_app_toast); - } - if (text == null) { - return; - } + /** Show "Screen unpinned" toast. */ + void showPinningExitToast() { + makeAllUserToastAndShow(R.string.lock_to_app_exit); + } + + /** Show a toast that describes the gesture the user should use to escape pinned mode. */ + void showEscapeToast() { + mHandler.obtainMessage(H.SHOW_ESCAPE_TOAST).sendToTarget(); + } + + private void handleShowEscapeToast() { long showToastTime = SystemClock.elapsedRealtime(); if ((showToastTime - mLastShowToastTime) < SHOW_TOAST_MINIMUM_INTERVAL) { Slog.i(TAG, "Ignore toast since it is requested in very short interval."); @@ -67,20 +68,12 @@ public class LockTaskNotify { if (mLastToast != null) { mLastToast.cancel(); } - mLastToast = makeAllUserToastAndShow(text); + mLastToast = makeAllUserToastAndShow(R.string.lock_to_app_toast); mLastShowToastTime = showToastTime; } - public void show(boolean starting) { - int showString = R.string.lock_to_app_exit; - if (starting) { - showString = R.string.lock_to_app_start; - } - makeAllUserToastAndShow(mContext.getString(showString)); - } - - private Toast makeAllUserToastAndShow(String text) { - Toast toast = Toast.makeText(mContext, text, Toast.LENGTH_LONG); + private Toast makeAllUserToastAndShow(int resId) { + Toast toast = Toast.makeText(mContext, resId, Toast.LENGTH_LONG); toast.getWindowParams().privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; toast.show(); @@ -88,13 +81,13 @@ public class LockTaskNotify { } private final class H extends Handler { - private static final int SHOW_TOAST = 3; + private static final int SHOW_ESCAPE_TOAST = 3; @Override public void handleMessage(Message msg) { switch(msg.what) { - case SHOW_TOAST: - handleShowToast(msg.arg1); + case SHOW_ESCAPE_TOAST: + handleShowEscapeToast(); break; } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index ceb0ad07e72c..6520dc94072f 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -1654,11 +1654,23 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenshotChordVolumeDownKeyConsumed = true; mA11yShortcutChordVolumeUpKeyConsumed = true; mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT), - ViewConfiguration.get(mContext).getAccessibilityShortcutKeyTimeout()); + getAccessibilityShortcutTimeout()); } } } + private long getAccessibilityShortcutTimeout() { + ViewConfiguration config = ViewConfiguration.get(mContext); + try { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, mCurrentUserId) == 0 + ? config.getAccessibilityShortcutKeyTimeout() + : config.getAccessibilityShortcutKeyTimeoutAfterConfirmation(); + } catch (Settings.SettingNotFoundException e) { + throw new RuntimeException(e); + } + } + private long getScreenshotChordLongPressDelay() { if (mKeyguardDelegate.isShowing()) { // Double the time it takes to take a screenshot from the keyguard @@ -3866,8 +3878,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mAccessibilityTvScheduled = true; Message msg = Message.obtain(mHandler, MSG_ACCESSIBILITY_TV); msg.setAsynchronous(true); - mHandler.sendMessageDelayed(msg, - ViewConfiguration.get(mContext).getAccessibilityShortcutKeyTimeout()); + mHandler.sendMessageDelayed(msg, getAccessibilityShortcutTimeout()); } } else if (mAccessibilityTvScheduled) { mHandler.removeMessages(MSG_ACCESSIBILITY_TV); diff --git a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java index f9d7f9d4904a..4c1d3e9f0003 100644 --- a/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/am/LockTaskControllerTest.java @@ -189,6 +189,8 @@ public class LockTaskControllerTest { // THEN lock task mode should be started verifyLockTaskStarted(STATUS_BAR_MASK_PINNED); + // THEN screen pinning toast should be shown + verify(mLockTaskNotify).showPinningStartToast(); } @Test @@ -255,8 +257,6 @@ public class LockTaskControllerTest { // WHEN system calls stopLockTaskMode mLockTaskController.stopLockTaskMode(true, SYSTEM_UID); - // THEN a lock tash toast should be shown - verify(mLockTaskNotify).showToast(LOCK_TASK_MODE_LOCKED); // THEN lock task mode should still be active assertEquals(LOCK_TASK_MODE_LOCKED, mLockTaskController.getLockTaskModeState()); } @@ -302,6 +302,8 @@ public class LockTaskControllerTest { verifyLockTaskStopped(times(1)); // THEN the keyguard should be shown verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL); + // THEN screen pinning toast should be shown + verify(mLockTaskNotify).showPinningExitToast(); } @Test |